Introdução a linguagem Ruby

Introdução a linguagem Ruby


Ruby é uma linguagem dinâmica, interpretada, orientada a objeto, open source com foco na simplicidade e na produtividade.

Ruby incorpora vários conceitos como: Agile, TDD, BDD, entre outros, os quais permitem um desenvolvimento rápido de software e com qualidade. Para se ter uma ideia a propria linguagem já incorpora um sistema de tests.

Tem uma sintaxe elegante de leitura natural e fácil escrita.

Digamos que é uma linguagem “amiga do programador”, pois nos oferece muita flexibilidade, produtividade e diversão.

O que a maioria dos Rubystas irão dizer, é que é uma linguagem em que se escreve pouco e se faz muito.

Com Ruby podemos criar desde aplicações web a programas desktop.

Primeiros passos

Se você ainda não tem Ruby instalado, saiba como instalar nesse link.

Se você já instalou Ruby, basta abrir seu terminal e digitar irb, (Interactive Ruby Shell).

O IRB nos permite executar códigos Ruby diretamente no terminal, sem ter que ficar editando e executando um arquivo, vamos usá-lo para agilizar o aprendizado.

Hello World

Vamos começar com um simples Hello World e ir extendendo a complexidade.

Digite no seu terminal e observe os resultados.

# Assina a variável hello com o valor "Hello World"
hello = "Hello World"

# Exibe "Hello World"
puts hello

# Exibe "HELLO WORLD"
puts hello.upcase

# Exibe "dlroW olleH"
puts hello.reverse

# Exibe "Hello World" 3 vezes
3.times { puts hello }
# "Hello World"
# "Hello World"
# "Hello World"

# Exibe "Hello WorldHello World"
puts hello * 2

# Troca a palavra "World" por "Everyone"
hello['World'] = "Everyone"

# NOTA: "p" é uma shorthand para puts
# Exibe "Hello Everyone"
p hello

# Exibe o tamanho da string "Hello Everyone", 14
p hello.size

# Remove " Everyone" da string
hello.delete " Everyone"

# Exibe o tamanho da string "Hello", 5
p hello.size

# Exibe cada caractere da string "Hello" separadamente
p hello.chars
# H
# e
# l
# l
# o

# Adiciona cada caractere em um array
meu_array = hello.chars.to_a # ['H', 'e', 'l', 'l', 'o']

O principal objetivo da linguagem é ajudar os programadores.

“Eu queria diminuir minha frustração durante a programação, assim como eu quero diminuir meu esforço na programação. Esse era o meu objetivo principal na concepção de Ruby. Quero me divertir programando.

Depois de lançar Ruby e muitas pessoas tomarem conhecimento, elas disseram que se sentem como eu me sinto.” - Yukihiro Matz, criador da linguagem.

Object-oriented

Em Ruby, realmente tudo é um objeto! Tudo!!!

Cada bit de informação e código pode ter suas próprias propriedades e ações. Não existem tipos primitivos como em outras linguagens.

Em muitas linguagens, um número é apenas um tipo primitivo.

No Ruby ele é uma instância da classe Fixnum e possui seus próprios métodos como o laço de repetição que vimos antes, 3.times.

Veja abaixo algumas classes e heranças.

# Exibindo a classe de um objeto

5.class # Fixnum
5.5.class # Float
5555555555.class # Bignum
"Matheus".class # String
[].class # Array
{}.class # Hash
(1..10).class # Range

# Perceba que até mesmo nil, false e true são objetos

nil.class # NilClass
false.class # FalseClass
true.class # TrueClass

# Heranças

"Matheus".class # String
"Matheus".class.superclass # Object
"Matheus".class.superclass.superclass # BasicObject

5.class # Fixnum
5.class.superclass # Integer
5.class.superclass.superclass # Numeric
5.class.superclass.superclass.superclass # Object
5.class.superclass.superclass.superclass.superclass # BasicObject

Toda classe herda da class Object que herda de BasicObject


Orientado a objeto

Métodos

A definição de métodos em Ruby se da pela palavra reservada def, parceba que não é utilizado chaves para englobar o método como é comum em outras linguagens.

Para isso, usamos a palavra reservada end sinalizando o fim de um método.

# Criamos um método chamado say_hello

def say_hello

  # Exibe "Qual seu nome?"
  p "Qual seu nome?"

  # Recupera a string digitada pelo usuário com "gets"
  # E remove espaços no início e no fim da string com "chomp"
  nome = gets.chomp

  # Exibe "Olá NomeDigitado"
  p "Olá #{nome}"
end

# Executa o método say_hello
say_hello

Acabamos de ver como é extremamente simples definir métodos no Ruby. Agora vamos criar um método que recebe valores como parâmetro.

# Vamos definir um método que recebe um nome e um texto,
# Caso o texto não seja informado, o método deve
# utilizar o valor padrão: Hello World!

def exibe_mensagem(nome, texto = "Hello World!")
  puts "#{nome} diz: #{texto}"
end

# Note que em Ruby colchetes "()" são opcionais,
# então também podemos definir dessa forma

def exibe_mensagem nome, texto = "Hello World!"
  puts "#{nome} diz: #{texto}"
end

# Executando o método
exibe_mensagem("Matheus") # Matheus diz: Hello World!
exibe_mensagem("José", "Algum texto.") # José diz: Algum texto.

# Ou sem parênteses
exibe_mensagem "Matheus" # Matheus diz: Hello World!
exibe_mensagem "José", "Outro texto." # José diz: Outro texto.

Variáveis

Os tipos de variáveis em Ruby podem ser distinguidos por um caractere no início junto ao nome de cada variável.

A variável que não possui nenhum caractere no início é uma variavel de escopo, sendo visível somente no escopo em que foi criada.

Se a váriavel inicia com $, ela é uma variável global, sendo exposta em toda aplicação.

Se iniciar com @, é uma variável de instância, utilizada em classes. Seria como o this. ou self. de outras linguagens. Que provavelmente representará algum atributo do objeto.

Iniciando com @@ é uma variável privada de classe, essa variável é compartilhada em todas as instâncias da sua classe.

Já uma constante não tem nenhum caractere especial e possui todas as suas letras maiúsculas.

variavel = "Hello"    # Variável local
$variavel = "Hello"   # Variável global
@variavel = "Hello"   # Variável de instância
@@variavel = "Hello"  # Variável privada de classe
CONSTANTE = "Hello"   # Constante

Classes

Tendo o entendimento de como funciona os métodos e variáveis, podemos partir para a criação de classes.

Para isso basta utilizar a palavra class.

Várias linguagens possuem sua maneira de indicar o método construtor, em Java é o método com o mesmo nome que a classe, em Python usa-se __init__, e Ruby não podia deixar de ser diferente e ter seu própio estilo para definir construtores :).

O método construtor de uma classe em Ruby chama-se initialize.

class Cumprimenta

  # Em Ruby o método construtor chama-se initialize
  def initialize(nome)

    # A variável de classe @nome recebe o nome informado, e por ser
    # variável de classe pode ser usada em todo escopo da classe
    @nome = nome.capitalize
  end

  # Definimos um método que exibe "Olá NomeInformado"
  def sauda
    puts "Olá #{@nome}!"
  end
end

# Cria um novo objeto
c = Cumprimenta.new("Matheus")

# Ou sem ()
c = Cumprimenta.new "Matheus"

# Exibe "Olá Matheus"
c.sauda

Tudo funciona bem, mas é comum em programação precisar acessar o valor de um atributo de uma classe.

No momento se tentarmos acessar o valor da variável @nome diretamente, ocasionará um erro.

# A variável é privada a classe, portanto não podemos acessar

c.@nome # ERRO

Esse erro ocorre porque a variável é privada e não temos acesso a ela.

Normalmente para isso criamos os métodos Get e Set, para recuperar e atribuir valores aos atributos, como sempre é feito em outras linguagens.

Porém no Ruby não é preciso ficar criando esses métodos, podemos usar o snippet abaixo:

# Criando Get e Set

class Cumprimenta

  # Cria os métodos Get e Set para o atributo
  attr_accessor :nome

  def initialize(nome)
    @nome = nome.capitalize
  end

  def sauda
    puts "Olá #{@nome}!"
  end
end

# Cria um novo objeto
c = Cumprimenta.new "Matheus"

# Exibe "Olá Matheus"
c.sauda

# Recupera o valor do atributo
c.nome # Retorna "Matheus"

# Atribui um novo valor para o atributo nome
c.nome = "Azzi"

# Exibe "Olá Azzi"
c.sauda

Mágica!

Como podemos ver, attr_accessor cria os métodos Get e Set para o atributo.

Mas você pode criar apenas o método Get ou o método Set também:

class Cumprimenta

  # Cria apenas o método Get para o atributo nome
  attr_reader :nome

  def initialize(nome)
    @nome = nome.capitalize
  end

  def sauda
    puts "Olá #{@nome}!"
  end
end

# Cria um novo objeto
c = Cumprimenta.new "Matheus"

# Exibe "Olá Matheus"
c.sauda

# Recupera o valor do atributo
c.nome # Retorna "Matheus"

# Atribui um novo valor para o atributo nome
c.nome = "Azzi" # ERRO, porque definimos apenas o método Get

Podemos definir esses acessos com a seguinte sintaxe:

attr_reader :nome    # Cria só o método Get
attr_writer :nome    # Cria só o método Set
attr_accessor :nome  # Cria os métodos Get e Set

# Também é possível dinifir vários ao mesmo tempo
attr_accessor :nome, :idade, :sexo

Isso facilita a vida do programador, imagine que fossem 5 atributos e precisasse criar o Get e Set para cada um. Com isso, temos muito menos linhas de código.

Herança

Para criar uma herança entre classes usamos o símbolo < que representa a herença, seria como um extends em Java.

No exemplo temos a classe Mamífero e Gato, onde Gato herda de Mamífero.

# Criamos a classe Mamífero

class Mamifero
  def respira
    puts "O mamífero respira..."
  end

  def fala
    puts "O mamífero falou..."
  end
end

# Criamos a classe Gato
# Gato herda de Mamífero

class Gato < Mamifero

  # Sobrecarregando o método
  def fala
    puts "Miau..."
  end
end

m = Mamifero.new
m.respira # O mamífero respira...
m.fala # O mamífero falou...

g = Gato.new
g.respira # O mamífero respira...
g.fala # Miau...

Não temos multipla herança em Ruby, mas não encare isso como um problema.

Lembre-se, um dos princípios da orientação a objetos é: Prefira composição de objetos à herança de classes.

Ruby trabalha com o conceito de módulos.

Return

Em Ruby, mesmo que você não defina um return ele vai retornar o último item do bloco. Na verdade só será feito algo diferente disso caso você defina um return.

Então no seguinte exemplo:

def hello
  return "Olá Mundo!"
end

# E

def hello
  "Olá Mundo!"
end

# Terão o mesmo resultado
puts hello # Olá Mundo!

Outro exemplo:

def numeros(a, b, c)
  soma = a + b + c

  if soma > 10
    "O resultado é MAIOR que 10"
  else
    "O resultado é MENOR que 10"
  end
end

puts numeros(1, 2, 3) # O resultado é MENOR que 10
puts numeros(5, 4, 8) # O resultado é MAIOR que 10

Condições

Ruby possui os mais diversos tipos de condicionais.

# If comum
if condicao
  faca_algo
end

# If expressivo
faca_algo if condicao

# If / Elsif / Else
if condicao
  executa_algo
elsif outra_condicao
  executa_outro
else
  chuta_o_balde
end

# Atribuindo condição a variável
resultado =
  if condicao
    'A'
  elsif outra_condicao
    'B'
  else
    'C'
  end

# Operador ternário, caso a condição seja verdadeira
# executa alguma_coisa, senão outra_coisa
resultado = condicao ? alguma_coisa : outra_coisa

# Unless (a não ser que)
unless condicao
  executa_algo
end

# Unless expressivo
executa_algo unless condicao

# Case
idade = 20
case
when idade <= 13
  puts "Criança"
when idade > 13 && idade <= 25
  puts "Jovem"
when idade > 25
  puts "Adulto"
else
  puts "Idoso"
end

# Atribuindo condição a variável
idade = 20
puts resultado = case
  when idade <= 13
    "Criança"
  when idade > 13 && idade <= 25
    "Jovem"
  when idade > 25
    "Adulto"
  else
    "Idoso"
  end

# Usando ranges para melhor legibilidade
idade = 20
puts resultado = case idade
  when 0..13
    "Criança"
  when 13..25
    "Jovem"
  when 26..50
    "Adulto"
  else
    "Idoso"
  end

Quanta coisa não? Isso que você nem viu os Loops ainda.

Ruby nos dá diversas possibilidades para você utilizar a que melhor se aplicar ao seu caso.

Loops

Cansado do velho for(i = 1; i >= itens.length; i++) ?

Convenhamos que ele tem o seu valor, mas em Ruby loops podem ser feitos de diversas maneiras, assim como vimos em condições.

# While
i = 1
while i < 11 do
  puts i
  i++
end

# While expressivo
i = 0
puts i++ while i < 10

# Until (até que)
i = 1
until i > 10 do
  puts i
  i++
end

# Until expressivo
i = 0
puts i++ until i == 10

# Each
@nomes.each do |nome|
  puts nome
end

[0,1,2,3].each do |i|
  puts i
end

# Each expressivo
@nomes.each { |nome| puts nome }

# Times
3.times do
  puts "Hello"
end

# Times expressivo
10.times { |i| puts i }

# For in
for nome in @nomes
  puts nome
end

for i in 1..5
  puts i
end

# Begin While
i = 0
begin
  puts i
  i++
end while i < 5

# Begin Until
i = 0
begin
  puts i
  i++
end until i > 5

# Loop
i = 0
loop do
  break if i > 10
  puts i
  i++
end

Arrays

Agora sinta-se num Playground, ainda temos muito que falar de Ruby, mas abordar tudo seria demais para um post só.

Portando escolhi os Arrays para demonstrar um pouco mais sobre Ruby.

# Cria um array vazio
meu_array = []

# Verifica se o array é vazio
meu_array.empty? # true

# Cria um novo array com itens de vários tipos
meu_array = [1, "Matheus", 3.5, nil, 99999, true]

# Agora o array não está mais vazio
meu_array.empty? # false

# Acessando um item no array
meu_array[2]    # Retorna 3.5
meu_array[100]  # Retorna nil, porque não existe
meu_array[1..3] # Retorna ["Matheus", 3.5, nil]
meu_array.first # Retorna 1
meu_array.last  # Retorna true

# Verificar tamanho do array
meu_array.size # 6

# Verificar se um item existe no array
meu_array.include?(4) # false
meu_array.include?(3.5) # true

# Inserir item no início do array
meu_array << "início"
# ou
meu_array.unshift("início")
# ["início", 1, "Matheus", 3.5, nil, 99999, true]

# Inserir item no final do array
meu_array >> "fim"
# ou
meu_array.push("fim")
# ["início", 1, "Matheus", 3.5, nil, 99999, true, "fim"]

# Mudar o valor de um item
meu_array[3] = 10000
# ["início", 1, "Matheus", 10000, nil, 99999, true, "fim"]

# Deletar um item baseado no index do array
# Deleta o 4 item do array
meu_array.delete_at(3) # ["início", 1, "Matheus", nil, 99999, true, "fim"]

# Deletar um item do array baseado no valor
# Deleta os itens do array que tiverem "Matheus" como valor
meu_array.delete("Matheus") # ["início", 1, 10000, nil, 99999, true, "fim"]

# Outros métodos
meu_array.uniq! # Remove itens duplicados no array
meu_array.compact! # Remove valores nil no array

# Removing Nesting
[1, [2, 3], [true, ["Foo", nil]]].flatten
# [1, 2, 3, true, "Foo", nil]

[10, 5.5, 6, 3].max # 10
[10, 5.5, 6, 3].min # 3
[10, 5.5, 6, 3].sort # [3, 5.5, 6, 10]
[10, 5.5, 6, 3].reverse # [10, 6, 5.5, 3]

novo_array = [1, 2, 3, 4, 5]
novo_array.map! { |a| 2 * a } # [2, 4, 6, 8, 10]

# Congelando array
novo_array.freeze
novo_array << 12 # RuntimeError: can't modify frozen Array

[1, 2, 3].map(&10.method(:+)) # [11, 12, 13]

# Manipulando itens

["banana", "maçã", "abóbora"].each { |i| i.capitalize }
# ["Banana", "Maçã", "Abóbora"]

# Ou utilizando map

["banana", "maçã", "abóbora"].map(&:capitalize)
# ["Banana", "Maçã", "Abóbora"]

Indo além

Tudo que você viu aqui é a base da base, mas já da para ter uma ideia.

A comunidade Ruby é realmente gigantesca e acolhedora.

Ruby é ótimo para desenvolvimento Web, na minha opinião possui um dos melhores Frameworks web da atualidade, Ruby on Rails. De longe o Framework Web Back-end mais popular do Github.

Também possui o Sinatra, um micro-framework que também acabou originando micro-frameworks baseados nele para como Express em NodeJS e Flask em Python.