Este guia é um material de apoio para quem está começando na linguagem Ruby, especialmente para estudantes que já possuem uma base em lógica de programação.

Criada em 1995 pelo cientista da computação japonês Yukihiro Matsumoto (conhecido como “Matz”), Ruby foi desenhada com uma premissa fundamental: otimizar a linguagem para a felicidade humana e a produtividade do desenvolvedor, e não para a máquina.

Ruby combina o poder prático e de manipulação de texto do Perl com a elegância orientada a objetos do Smalltalk e a sintaxe amigável de linguagens como Python e Eiffel. É a linguagem por trás do consagrado framework web Ruby on Rails e de ferramentas populares como o Jekyll (o próprio gerador de sites estáticos que alimenta este portal!).


🛠️ Instalação e Configuração do Ambiente

1. Instalação do Interpretador Ruby

  • Windows: A forma oficial e mais simples é baixar o instalador no RubyInstaller for Windows. Escolha a versão recomendada com Devkit (que permite compilar extensões nativas em C).
  • Linux (Ubuntu/Debian): sudo apt update && sudo apt install ruby-full (ou via gerenciadores como rbenv/asdf).
  • macOS: Já possui uma versão básica no sistema, mas é recomendado instalar a versão mais recente via Homebrew: brew install ruby.

Verifique a instalação no terminal:

ruby -v

2. O Console Interativo (IRB)

Uma das melhores ferramentas para aprender Ruby é o IRB (Interactive Ruby), um terminal interativo (REPL) onde você pode testar expressões em tempo real:

irb

No prompt do IRB, você pode digitar comandos como:

irb(main):001> 2 + 3
=> 5
irb(main):002> "ruby".upcase
=> "RUBY"
irb(main):003> exit

3. Editor de Código (VS Code)

  1. Instale o Visual Studio Code.
  2. Na aba de Extensões (Ctrl + Shift + X), instale a extensão oficial Ruby LSP (da Shopify) ou Ruby para suporte a realce de sintaxe, autocompletar e formatação.

🚀 Seu Primeiro Programa em Ruby

Crie um arquivo chamado ola.rb:

puts "Ola, Universo Ruby!"

Execute no terminal:

ruby ola.rb

O resultado será:

Ola, Universo Ruby!

puts, print e p: Qual a diferença?

  • puts (put string): Exibe o conteúdo e adiciona uma quebra de linha (\n) no final.
  • print: Exibe o conteúdo sem quebra de linha.
  • p: Usado para depuração (inspeção de objetos). Exibe o valor em formato cru (mostra aspas em strings, elementos de arrays etc.).
print "Linha 1 "
print "continua aqui.\n"
puts "Linha 2 com quebra automática."
p "Texto com aspas visíveis no debug" # => "\"Texto com aspas visíveis no debug\""

💎 O Conceito Fundamental: Tudo é um Objeto

Em muitas linguagens (como C, Java ou Go), existem “tipos primitivos” e “objetos”. Em Ruby, absolutamente tudo é um objeto — instâncias de classes com métodos que você pode chamar:

-10.abs        # => 10 (chama o método .abs no número -10)
5.times { puts "Oi" }  # Executa o bloco 5 vezes
"texto".length # => 5
nil.nil?       # => true

📊 Tipos de Dados e Variáveis

Ruby possui tipagem dinâmica (você não precisa declarar tipos) e tipagem forte (não converte tipos incompatíveis de forma silenciosa).

Tipo Descrição Exemplo
Integer Números inteiros 42, -10
Float Números de ponto flutuante 3.1415, 99.90
String Textos e caracteres "Sofia", 'Olá'
TrueClass / FalseClass Valores booleanos true, false
NilClass Ausência de valor nil (equivalente ao null/None)
Symbol Identificadores imutáveis :id, :ativo, :pendente

Convenções de Nomenclatura

  • Variáveis locais: snake_case (ex: idade_usuario, total_vendas)
  • Constantes: MAIUSCULAS ou PascalCase (ex: PI = 3.14, TaxaMaxima = 0.2)
  • Variáveis de instância: prefixadas com @ (ex: @nome)
  • Variáveis globais: prefixadas com $ (ex: $debug_mode)

Interpolação de Strings

Strings com aspas duplas ("...") suportam interpolação direta de código com #{expressao}:

nome = "Sofia Oliveira"
idade = 28
salario = 6450.50
genero = 'F'

# Interpolação limpa e legível
puts "NOME = #{nome}"
puts "IDADE = #{idade}"
puts "GENERO = #{genero}"
# Formatação com sprintf / printf
puts sprintf("SALARIO = %.2f", salario)

⚠️ Atenção: Aspas simples ('...') são literais e não processam interpolação nem caracteres de escape como \n.


🔢 Operadores

Aritméticos

Operador Significado Exemplo
+ Adição 10 + 5 (15)
- Subtração 10 - 5 (5)
* Multiplicação 10 * 5 (50)
/ Divisão (inteira se ambos forem inteiros) 10 / 4 (2) ou 10.0 / 4 (2.5)
% Resto da divisão (módulo) 10 % 3 (1)
** Exponenciação 2 ** 3 (8)

Comparativos

Operador Significado
== Igual a
!= Diferente de
> Maior que
< Menor que
>= Maior ou igual a
<= Menor ou igual a
<=> Operador espaçonave (retorna -1 se menor, 0 se igual, 1 se maior)

Lógicos

  • && e and (E lógico)
  • || e or (OU lógico)
  • ! e not (NÃO lógico)

💡 Regra de ouro dos booleanos em Ruby: Em Ruby, apenas false e nil são avaliados como falsos. O número 0, a string vazia "" e um array vazio [] são todos considerados verdadeiros (truthy)!


📥 Entrada e Saída de Dados

A leitura do teclado é feita com gets. O método .chomp remove a quebra de linha residual do Enter.

Conversões explícitas:

  • .to_i: Converte para inteiro (Integer)
  • .to_f: Converte para ponto flutuante (Float)
  • .to_s: Converte para texto (String)
print "Digite seu nome: "
nome = gets.chomp

print "Digite sua idade: "
idade = gets.chomp.to_i

print "Digite seu salário: "
salario = gets.chomp.to_f

puts "\n--- DADOS CADASTRADOS ---"
puts "Nome: #{nome}"
puts "Idade em meses: #{idade * 12}"
puts sprintf("Salário anual: R$ %.2f", salario * 12)

🔀 Estruturas Condicionais

1. if / elsif / else

Repare na grafia elsif (sem o “e” no final do else):

print "Digite uma hora do dia (0 a 23): "
hora = gets.chomp.to_i

if hora < 12
  puts "Bom dia!"
elsif hora < 18
  puts "Boa tarde!"
else
  puts "Boa noite!"
end

2. A estrutura unless

unless executa o bloco se a condição for falsa (equivalente a if not):

chovendo = false

unless chovendo
  puts "Podemos ir ao parque caminhar!"
end

3. Modificadores Inline (Pós-fixados)

Para comandos curtos de uma linha, Ruby permite colocar o if ou unless no final da instrução:

nota = 8.5
puts "Parabéns, você foi aprovado!" if nota >= 7.0
puts "Atenção: nota insuficiente!" unless nota >= 7.0

4. case / when (Seleção Múltipla)

O case em Ruby é flexível e aceita comparações com intervalos numéricos (Range):

idade = 15

case idade
when 0..12
  puts "Criança"
when 13..17
  puts "Adolescente"
when 18..59
  puts "Adulto"
else
  puts "Idoso"
end

🔁 Estruturas de Repetição e Iteradores

Embora Ruby possua laços tradicionais como while e until, o código idiomático em Ruby quase sempre utiliza iteradores baseados em blocos.

1. Laço while e until

contador = 1
while contador <= 3
  puts "Contagem while: #{contador}"
  contador += 1
end

# until repete ATÉ que a condição se torne verdadeira
fim = 3
until fim == 0
  puts "Regressivo until: #{fim}"
  fim -= 1
end

2. O Jeito Idiomático Ruby: Iteradores

# Repetição simples com .times
3.times do |i|
  puts "Execução número #{i + 1}"
end

# Contagem em intervalo com .upto e .downto
1.upto(3) { |n| puts "Subindo: #{n}" }
3.downto(1) { |n| puts "Descendo: #{n}" }

📏 Vetores (Arrays) e Coleções

Em Ruby, Array é uma coleção ordenada dinâmica que pode crescer conforme a necessidade.

# Criando um array
frutas = ["Maçã", "Banana", "Laranja"]

# Adicionando elementos (operador shovel << ou push)
frutas << "Uva"
frutas.push("Manga")

puts "Total de frutas: #{frutas.length}"
puts "Primeira fruta: #{frutas.first}"
puts "Última fruta: #{frutas.last}"

# Iterando sobre o array com .each
puts "\nLista de frutas:"
frutas.each do |fruta|
  puts "- #{fruta}"
end

Transformações Poderosas em Coleções

Ruby brilha na manipulação de listas com métodos de alta ordem:

numeros = [1, 2, 3, 4, 5, 6]

# .map: Transforma cada elemento
dobros = numeros.map { |n| n * 2 }
# => [2, 4, 6, 8, 10, 12]

# .select: Filtra elementos (retorna os que satisfazem a condição)
pares = numeros.select { |n| n.even? }
# => [2, 4, 6]

# .sum: Soma todos os valores
total = numeros.sum
# => 21

🗂️ Dicionários / Mapas (Hash)

O Hash é uma estrutura de dados baseada em pares chave-valor:

aluno = {
  nome: "Lucas Pereira",
  idade: 22,
  curso: "Ciência da Computação",
  matriculado: true
}

puts "Aluno: #{aluno[:nome]}"
puts "Curso: #{aluno[:curso]}"

# Percorrendo chave e valor
aluno.each do |chave, valor|
  puts "#{chave.to_s.capitalize}: #{valor}"
end

🧩 Funções e Métodos

Métodos são definidos com a palavra-chave def e finalizados com end.

Retorno Implícito

Em Ruby, a palavra-chave return é opcional: a última linha avaliada dentro do método é retornada automaticamente.

# Método com parâmetros e valor padrão
def calcular_area_retangulo(base, altura = 1.0)
  base * altura # Retorno implícito
end

area1 = calcular_area_retangulo(5.0, 3.0)
area2 = calcular_area_retangulo(4.0) # Usa altura padrão = 1.0

puts "Área 1 = #{area1}" # => 15.0
puts "Área 2 = #{area2}" # => 4.0

Métodos Predicados (?)

Por convenção, métodos que retornam true ou false terminam com uma interrogação ?:

def numero_positivo?(n)
  n > 0
end

puts numero_positivo?(10)  # => true
puts numero_positivo?(-5)  # => false

🧱 Blocos e Closures

Um bloco em Ruby é um trecho de código anônimo que pode ser passado como argumento para qualquer método. Podem ser escritos de duas formas:

  • Em uma linha: { |parametro| ... }
  • Em múltiplas linhas: do |parametro| ... end

Podemos criar nossos próprios métodos que recebem blocos usando a instrução yield:

def executar_duas_vezes
  yield
  yield
end

executar_duas_vezes { puts "Olá do bloco!" }

🪄 Metaprogramação: Código que Escreve Código

Metaprogramação é escrever código que cria ou modifica outro código em tempo de execução — definir métodos dinamicamente, interceptar chamadas a métodos que não existem, ou inspecionar/alterar objetos e classes já carregados. Ruby é uma das linguagens mais amigáveis para isso, porque (lembrando a seção anterior) tudo é um objeto, inclusive classes.

define_method: Criando Métodos em Tempo de Execução

class Pessoa
  # define_method cria um metodo a partir de uma lista, sem escrever "def" 2x
  ["nome", "idade"].each do |atributo|
    define_method("#{atributo}=") do |valor|
      instance_variable_set("@#{atributo}", valor)
    end
    define_method(atributo) do
      instance_variable_get("@#{atributo}")
    end
  end
end

p1 = Pessoa.new
p1.nome = "Carlos"
p1.idade = 30
puts "Nome: #{p1.nome}, Idade: #{p1.idade}"

Saída: Nome: Carlos, Idade: 30

💡 Isso é exatamente o que attr_accessor :nome, :idade faz por baixo dos panos — attr_accessor é, ele mesmo, um pedaço de metaprogramação da biblioteca padrão do Ruby.

method_missing: Interceptando Chamadas Inexistentes

Quando você chama um método que a classe não define, Ruby não falha imediatamente — primeiro chama method_missing, que você pode sobrescrever para responder dinamicamente:

class Pessoa
  def method_missing(nome, *args)
    if nome.to_s.start_with?("bio_")
      "Metodo dinamico chamado: #{nome}"
    else
      super # Deixa o erro padrão acontecer para outros casos
    end
  end

  def respond_to_missing?(nome, include_private = false)
    nome.to_s.start_with?("bio_") || super
  end
end

p1 = Pessoa.new
puts p1.bio_resumo   # Nunca foi definido -- mas method_missing responde
puts p1.send(:bio_resumo) # .send chama um metodo pelo nome (String/Symbol)

Saída: Metodo dinamico chamado: bio_resumo (duas vezes)

⚠️ Sempre implemente respond_to_missing? junto com method_missing. Sem isso, métodos como .respond_to? e .methods mentem sobre o que o objeto realmente aceita — um bug sutil e clássico de metaprogramação mal feita. É esse tipo de “mágica” (poderosa, mas fácil de abusar) que frameworks como Ruby on Rails usam extensivamente para APIs fluentes, e que exige disciplina para não virar código difícil de depurar.


⚠️ Erros Comuns de Iniciantes

  1. Esquecer o chomp no gets:
    nome = gets # Contém "Carlos\n"
    if nome == "Carlos" # FALSO, porque "Carlos\n" != "Carlos"
    # Correção: nome = gets.chomp
    
  2. Escrever elseif ou elif:
    • Em Ruby, a palavra-chave correta é exclusivamente elsif.
  3. Supor que 0 ou "" são falsos:
    if 0
      puts "Em Ruby, 0 é VERDADEIRO (truthy)!"
    end
    
  4. Confundir aspas simples com aspas duplas na interpolação:
    nome = "Ana"
    puts 'Olá, #{nome}' # Saída literal: Olá, #{nome}
    puts "Olá, #{nome}" # Saída correta: Olá, Ana
    

🧠 Ruby x Outras Linguagens

Característica Ruby 💎 Python 🐍 JavaScript 🌐
Filosofia Felicidade do dev e expressividade Legibilidade e código explícito Versatilidade e onipresença
Delimitação de Blocos def/if/do ... end Indentação obrigatória Chaves { ... }
Tudo é Objeto? Sim, 100% puro (5.times) Quase tudo (funções soltas e tipos primitivos) Não (primitivos vs objetos)
Valores Falsy Apenas false e nil False, None, 0, "", [] false, null, undefined, 0, "", NaN
Retorno de Métodos Implícito (última linha) Explícito (return) Explícito (return)

🌙 E a Linguagem Lua?

Lua (1993, PUC-Rio) compartilha com Ruby a tipagem dinâmica e uma sintaxe enxuta — mas nasceu com um objetivo bem diferente: ser pequena e embarcável, para ser incorporada dentro de outros programas como linguagem de script (motores de jogos como Roblox e LÖVE2D, o editor Neovim, e até equipamentos industriais). Onde Ruby otimiza para a felicidade do desenvolvedor de aplicações completas, Lua otimiza para rodar rápido e ocupar pouco espaço dentro de um hospedeiro maior escrito em C.

print("Ola, Universo Lua!")

Saída: Ola, Universo Lua!

A Única Estrutura de Dados: table

Diferente de Ruby (Array e Hash separados), Lua tem uma única estrutura composta, a table, que serve tanto como array quanto como dicionário:

local aluno = {
  nome = "Sofia",
  idade = 22,
  notas = {8.5, 9.0, 7.5}
}

print("Nome: " .. aluno.nome)

-- ATENCAO: arrays em Lua comecam no indice 1, nao 0!
print("Primeira nota: " .. aluno.notas[1])

local soma = 0
for i, nota in ipairs(aluno.notas) do
  soma = soma + nota
end
print(string.format("Media: %.2f", soma / #aluno.notas))

Saída:

Nome: Sofia
Primeira nota: 8.5
Media: 8.33

⚠️ O índice 1, não 0, é a pegadinha nº1 de quem vem de C/Python/Ruby para Lua. aluno.notas[1] é o primeiro elemento — aluno.notas[0] simplesmente retorna nil, sem erro, o que pode mascarar bugs silenciosamente.

Funções de Primeira Classe e Closures

Assim como em Ruby (blocos) e Python, funções em Lua podem ser guardadas em variáveis e passadas como argumento — a base do seu uso como “linguagem de cola” para scriptar comportamento dentro de um jogo ou aplicação hospedeira:

local function saudar(nome)
  return "Ola, " .. nome .. "!"
end

local function executarCallback(funcao, valor)
  return funcao(valor)
end

print(executarCallback(saudar, "Mundo"))

-- Closure: uma funcao que "lembra" variaveis do escopo onde foi criada
local function criarContador()
  local total = 0
  return function()
    total = total + 1
    return total
  end
end

contador = criarContador()
print(contador())
print(contador())
print(contador())

Saída:

Ola, Mundo!
1
2
3

🎓 Conclusão

Ruby se destaca pela facilidade de leitura e pela rica expressividade de sua sintaxe. Dominar Ruby abre portas tanto para entender ferramentas de automação e DevOps quanto para o desenvolvimento web robusto com Ruby on Rails e sites estáticos com Jekyll. Lua mostra o outro extremo do espectro de linguagens dinâmicas: onde Ruby maximiza expressividade para quem escreve aplicações, Lua maximiza simplicidade e footprint mínimo para quem embute um interpretador dentro de outro programa — a mesma dinamicidade de tipos, aplicada a objetivos de design opostos.