Explorando as funcionalidades do Ruby 3
O Ruby 3, lançado em dezembro de 2020, representa um marco na evolução da linguagem. Com o ambicioso projeto Ruby 3x3, que prometia tornar o Ruby três vezes mais rápido que o Ruby 2, a versão trouxe não apenas ganhos de performance, mas também novas paradigmas de concorrência, tipagem opcional e expressividade sintática. Este artigo explora as principais funcionalidades do Ruby 3 sob a perspectiva de uma lista final de 1200 temas, oferecendo exemplos práticos para cada conceito.
1. Ruby 3: A nova era da performance e concorrência
1.1. O projeto Ruby 3x3: três vezes mais rápido que o Ruby 2
O principal objetivo do Ruby 3 era alcançar performance três vezes superior ao Ruby 2. Embora esse número seja uma meta aspiracional, os ganhos reais são significativos, especialmente em aplicações com carga computacional intensa.
# Exemplo de benchmark simples comparando Ruby 2 vs Ruby 3
require 'benchmark'
def calculo_pesado(n)
(1..n).reduce(0) { |acc, i| acc + Math.sqrt(i) * Math.sin(i) }
end
Benchmark.bm do |x|
x.report("Ruby 3") { 100.times { calculo_pesado(10000) } }
end
1.2. MJIT e YJIT: compiladores Just-In-Time para aceleração real
O Ruby 3 introduziu dois compiladores JIT: MJIT (Method-based JIT) e posteriormente YJIT (Yet Another JIT), desenvolvido pela Shopify. O YJIT, disponível a partir do Ruby 3.1, oferece ganhos ainda mais expressivos.
# Ativando YJIT na linha de comando
# ruby --yjit meu_script.rb
# Exemplo de código que se beneficia do YJIT
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) + fibonacci(n - 2)
end
puts fibonacci(35) # Execução otimizada com YJIT
1.3. Ractor: concorrência segura e paralelismo sem race conditions
Ractor (Ruby Actor) permite paralelismo real sem compartilhamento de estado, eliminando race conditions.
# Exemplo de Ractor para processamento paralelo
ractor1 = Ractor.new do
sleep 1
"Resultado do Ractor 1"
end
ractor2 = Ractor.new do
sleep 2
"Resultado do Ractor 2"
end
puts ractor1.take # Aguarda 1 segundo
puts ractor2.take # Aguarda 2 segundos (execução paralela)
2. Tipagem estática opcional com RBS e TypeProf
2.1. RBS: arquivos de assinatura de tipos para código Ruby
RBS (Ruby Signature) permite declarar tipos em arquivos separados, sem modificar o código original.
# Arquivo: pessoa.rbs
class Pessoa
attr_reader nome: String
attr_reader idade: Integer
def initialize: (String nome, Integer idade) -> void
def apresentar: () -> String
end
2.2. TypeProf: inferência automática de tipos para projetos legados
TypeProf analisa seu código e gera arquivos RBS automaticamente.
# Comando para gerar assinaturas automaticamente
# typeprof meu_arquivo.rb
# Exemplo de código analisado pelo TypeProf
def soma(a, b)
a + b
end
# TypeProf inferiria: def soma: (Integer, Integer) -> Integer
2.3. Integração com ferramentas de análise estática e IDEs
Ferramentas como Steep e Solargraph usam RBS para fornecer autocomplete e detecção de erros em tempo real.
# Configuração básica do Steep
# Arquivo: Steepfile
target :app do
check "lib"
signature "sig"
end
3. Pattern Matching: expressividade e legibilidade
3.1. Pattern Matching básico: case/in para desestruturação de dados
def avaliar_resposta(resposta)
case resposta
in { status: 200, body: }
"Sucesso: #{body}"
in { status: 404 }
"Não encontrado"
in { status: 500..599 }
"Erro do servidor"
else
"Resposta desconhecida"
end
end
puts avaliar_resposta({ status: 200, body: "OK" })
3.2. Padrões avançados: arrays, hashes, objetos e combinadores
def processar_dados(dado)
case dado
in [Integer => x, String => y] if x > 0
"Array com inteiro positivo e string: #{x}, #{y}"
in { nome: /^A/, idade: 18..30 }
"Jovem com nome começando com A"
in Array => arr if arr.all? { |e| e.is_a?(Numeric) }
"Array numérico: #{arr.sum}"
end
end
puts processar_dados([42, "Ruby"])
puts processar_dados({ nome: "Ana", idade: 25 })
3.3. One-line pattern matching com o operador => e in
# Pattern matching em uma linha
{ nome: "João", idade: 30 } => { nome:, idade: }
puts "#{nome} tem #{idade} anos"
# Verificação condicional com in
if [1, 2, 3] in [Integer, Integer, Integer]
puts "Array de três inteiros"
end
4. Novidades na sintaxe e no núcleo da linguagem
4.1. Endless methods: definição de métodos em uma única linha
def quadrado(x) = x * x
def saudacao(nome) = "Olá, #{nome}!"
puts quadrado(5) # 25
puts saudacao("Ana") # Olá, Ana!
4.2. Find pattern: busca em arrays com [*first, target, *last]
def encontrar_elemento(array, alvo)
case array
in [*before, ^alvo, *after]
{ antes: before, depois: after }
else
nil
end
end
dados = [10, 20, 30, 40, 50]
resultado = encontrar_elemento(dados, 30)
puts resultado # {:antes=>[10, 20], :depois=>[40, 50]}
4.3. Numbered parameters: _1, _2 em blocos sem nomear argumentos
numeros = [1, 2, 3, 4, 5]
# Sem numbered parameters
dobrados = numeros.map { |n| n * 2 }
# Com numbered parameters
dobrados = numeros.map { _1 * 2 }
# Múltiplos parâmetros
pares = [[1, 2], [3, 4]]
somas = pares.map { _1 + _2 }
puts somas # [3, 7]
5. Fiber Scheduler e concorrência assíncrona
5.1. Fiber Scheduler: interface para I/O não bloqueante
require 'async'
def tarefa_demorada(nome, tempo)
Async do
sleep tempo
puts "#{nome} concluída após #{tempo} segundos"
end
end
Async do
tarefa_demorada("Tarefa 1", 2)
tarefa_demorada("Tarefa 2", 1)
end
5.2. Fiber.schedule e execução concorrente leve
require 'fiber'
scheduler = Scheduler.new
Fiber.set_scheduler(scheduler)
Fiber.schedule do
sleep 1
puts "Fiber 1"
end
Fiber.schedule do
sleep 2
puts "Fiber 2"
end
5.3. Compatibilidade com gems assíncronas
# Usando a gem async-http
require 'async'
require 'async/http/internet'
Async do
internet = Async::HTTP::Internet.new
response = internet.get("https://api.github.com")
puts response.read
end
6. Melhorias na ferramenta de pacotes e segurança
6.1. Bundler integrado: gemas gerenciadas diretamente pelo Ruby
# Ruby 3+ inclui bundler como gem padrão
# Arquivo Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.0'
gem 'puma', '~> 6.0'
gem 'sqlite3', '~> 1.6'
6.2. Gemas de segurança: set, net-* e dependências atualizadas
# Verificando vulnerabilidades em gems
# bundle audit check --update
# Exemplo de uso seguro de net/http
require 'net/http'
require 'uri'
uri = URI('https://api.exemplo.com')
response = Net::HTTP.get_response(uri)
puts response.body if response.is_a?(Net::HTTPSuccess)
6.3. Type checking em gems: RBS como padrão da comunidade
# Adicionando types a uma gem
# Estrutura de diretórios:
# minha_gem/
# sig/
# minha_gem.rbs
# lib/
# minha_gem.rb
# Arquivo sig/minha_gem.rbs
module MinhaGem
VERSION: String
def self.saudacao: (String nome) -> String
end
7. Depuração e análise de código avançadas
7.1. Debug gem: novo depurador com REPL e breakpoints remotos
# debug.rb
require 'debug'
def calculo_complexo(x, y)
resultado = x + y
debugger # Ponto de interrupção
resultado * 2
end
puts calculo_complexo(10, 20)
7.2. TracePoint e profiling com --rjit-stats e --mjit-stats
# Ativando estatísticas do YJIT
# ruby --yjit --yjit-stats meu_script.rb
# Usando TracePoint para profiling
TracePoint.new(:call) do |tp|
puts "Chamada: #{tp.method_id} em #{tp.defined_class}"
end.enable
def exemplo
sleep 0.1
end
exemplo
7.3. Ferramentas de cobertura e análise de tipos em tempo real
# Usando coverage do Ruby padrão
require 'coverage'
Coverage.start
require_relative 'meu_codigo'
result = Coverage.result
puts result.inspect
8. Casos de uso e migração para Ruby 3
8.1. Aplicações web com Rails 7 e Ruby 3: sinergia e ganhos reais
# Gemfile para Rails 7 com Ruby 3
source 'https://rubygems.org'
ruby '~> 3.2'
gem 'rails', '~> 7.1'
gem 'puma', '~> 6.0'
gem 'importmap-rails'
gem 'turbo-rails'
gem 'stimulus-rails'
8.2. Scripts de processamento de dados com Pattern Matching
def processar_logs(logs)
logs.map do |log|
case log
in { level: "ERROR", message:, timestamp: }
"[#{timestamp}] ERRO: #{message}"
in { level: "WARN", message:, timestamp: }
"[#{timestamp}] AVISO: #{message}"
in { level: "INFO", message:, timestamp: }
"[#{timestamp}] INFO: #{message}"
else
"Log desconhecido"
end
end
end
logs = [
{ level: "ERROR", message: "Falha na conexão", timestamp: "2024-01-01" },
{ level: "INFO", message: "Servidor iniciado", timestamp: "2024-01-01" }
]
puts processar_logs(logs)
8.3. Roteiro de migração: compatibilidade, gemas e testes com Ruby 3
# Checklist de migração para Ruby 3
# 1. Verificar compatibilidade de gems
# bundle update
# bundle exec ruby -c app.rb
# 2. Executar testes
# bundle exec rspec spec/
# 3. Ativar YJIT gradualmente
# RUBY_YJIT_ENABLE=1 bundle exec rails server
# 4. Verificar warnings de depreciação
# ruby -W:deprecated meu_script.rb
Referências
- Documentação Oficial do Ruby 3.0 — Anúncio oficial e notas de lançamento do Ruby 3.0
- Ruby 3x3: O Projeto de Performance — Detalhes do projeto que visou triplicar a performance do Ruby
- Guia de Pattern Matching no Ruby — Documentação completa sobre pattern matching no Ruby 3
- Ractor: Guia de Concorrência — Tutorial oficial sobre o modelo de atores do Ruby 3
- YJIT: Compilador JIT do Ruby — Artigo técnico da Shopify sobre o desenvolvimento do YJIT
- RBS: Documentação de Tipos — Repositório oficial do sistema de tipos RBS
- TypeProf: Inferência Automática de Tipos — Ferramenta para geração automática de assinaturas de tipos
- Fiber Scheduler: Concorrência Assíncrona — Documentação da interface de agendamento de fibras