A Arte dos Métodos em Ruby: Dominando a Base da Linguagem
Quando estamos aprendendo Ruby, rapidamente percebemos como os métodos são fundamentais para a estrutura da linguagem. Diferente de outras linguagens de programação, Ruby trata métodos com uma elegância singular, oferecendo diversas formas de defini-los e chamá-los. Vamos explorar em detalhes como funcionam os métodos em Ruby e algumas técnicas avançadas que podem elevar seu código a um novo patamar.
Definindo Métodos: A Base de Tudo
Em Ruby, definimos métodos usando a palavra-chave def
. O corpo do método contém expressões Ruby normais, e o valor de retorno é o resultado da última expressão executada (ou o argumento de um return
explícito).
def saudacao(nome) "Olá, #{nome}!" end puts saudacao("Maria") # Imprime: Olá, Maria!
Uma característica interessante é que podemos redefinir um método sem erros - Ruby apenas emite um aviso e usa a segunda definição. Isso, combinado com a capacidade de reabrir classes, permite modificar comportamentos em tempo de execução.
A partir do Ruby 3.0, também podemos criar métodos de uma linha com uma sintaxe mais concisa, às vezes chamada de "método sem fim":
def quadrado(n) = n * n
Esta sintaxe é especialmente útil para métodos simples que realizam apenas uma operação.
Nomes de Métodos: Convenções Importantes
Os nomes de métodos em Ruby devem começar com letra minúscula ou underscore, seguido por uma combinação de letras, dígitos e underscores. Por convenção, os métodos que retornam valores booleanos (predicados) geralmente terminam com ?
:
1.even? # => false 2.even? # => true
Métodos "perigosos" ou que modificam o objeto receptor costumam terminar com exclamação !
. Estes são frequentemente emparelhados com uma versão "segura" sem a exclamação:
texto = "meu código" texto.chop # => "meu códig" (retorna uma cópia modificada) texto # => "meu código" (original permanece inalterado) texto.chop! # => "meu códig" (modifica o objeto original) texto # => "meu códig" (o objeto foi modificado)
Métodos que podem aparecer no lado esquerdo de uma atribuição terminam com sinal de igual =
:
class Pessoa def nome=(novo_nome) @nome = novo_nome end end p = Pessoa.new p.nome = "Ana Vitória" # Invoca o método nome=
O Receptor do Método: Self e Além
Em Ruby, cada método é chamado em um objeto receptor. Dentro do método, a palavra-chave self
refere-se a esse receptor.
Podemos definir métodos para classes (métodos de classe) prefixando o nome do método com self.
:
class Computador def self.funcao "Receio não poder fazer isso" end end puts Computador.funcao # Chama o método na própria classe
Também podemos anexar métodos a objetos específicos:
mac = Computador.new def mac.introducao "Eu sou um Mac" end puts mac.introducao # => "Eu sou um Mac"
Parâmetros de Método: Flexibilidade em Ação
Ruby oferece várias formas de definir parâmetros, tornando os métodos extremamente flexíveis:
Parâmetros com Valores Padrão
def musico_favorito(arg1="Chico", arg2="Elis", arg3="Caetano") "#{arg1}, #{arg2}, #{arg3}." end musico_favorito # => "Chico, Elis, Caetano." musico_favorito("Milton") # => "Milton, Elis, Caetano." musico_favorito("Milton", "Maria") # => "Milton, Maria, Caetano."
Parâmetros de Tamanho Variável (Splat)
Usando um asterisco antes do nome do parâmetro, podemos capturar múltiplos argumentos em um único array:
def argumentos_variaveis(arg1, *resto) "arg1=#{arg1} -- resto=#{resto.inspect}" end argumentos_variaveis("um") # => arg1=um -- resto=[] argumentos_variaveis("um", "dois", "três") # => arg1=um -- resto=["dois", "três"]
Parâmetros de Palavra-chave (Keyword Parameters)
def metodo_com_keywords(cidade:, estado:, cep:) "Moro em #{cidade}, #{estado} #{cep}" end metodo_com_keywords(cidade: "São Paulo", estado: "SP", cep: "01311-000") # => "Moro em São Paulo, SP 01311-000"
Podemos também coletar palavras-chave arbitrárias usando o operador de duplo splat **
:
def varargs(arg1, **resto) "arg1=#{arg1}. resto=#{resto.inspect}" end varargs("um", cor: "vermelho", tamanho: "G") # => arg1=um. resto={:cor=>"vermelho", :tamanho=>"G"}
Chamando Métodos: A Execução em Prática
Para chamar um método, você especifica (opcionalmente) um receptor, o nome do método e os argumentos:
arquivo.download_mp3("samba", velocidade: :normal) { |p| mostrar_progresso(p) }
Se omitirmos o receptor, Ruby usa self
como receptor padrão. Isso é como os métodos privados funcionam - eles só podem ser chamados implicitamente no objeto atual.
Uma observação importante: ao chamar um método no lado esquerdo de uma atribuição (com nome terminando em =
), você deve especificar explicitamente o receptor:
class Pessoa def nome=(novo_nome) @nome = novo_nome end def alterar_coisas(novo_nome) # Isso cria uma variável local chamada 'nome' nome = novo_nome # Para chamar o método, precisamos usar 'self' self.nome = novo_nome end end
Valores de Retorno: O Resultado Final
Todo método retorna um valor - o valor da última expressão executada (ou o argumento de return
):
def positivo_ou_negativo(arg) case when arg > 0 then "positivo" when arg < 0 then "negativo" else "zero" end end positivo_ou_negativo(42) # => "positivo"
Você pode usar return
para sair do método prematuramente:
def encontrar_quadrado_grande 100.times do |num| quadrado = num * num return num, quadrado if quadrado > 1000 end end numero, quadrado = encontrar_quadrado_grande # numero => 32, quadrado => 1024
Expansão em Chamadas de Método (Splat)
Assim como podemos coletar múltiplos argumentos em um array, podemos fazer o contrário - converter uma coleção em argumentos individuais usando o operador de splat:
def cinco(a, b, c, d, e) "Recebi #{a} #{b} #{c} #{d} #{e}" end cinco(*[1, 2, 3, 4, 5]) # => "Recebi 1 2 3 4 5" cinco(1, 2, *[3, 4, 5]) # => "Recebi 1 2 3 4 5" cinco(*(1..5)) # => "Recebi 1 2 3 4 5"
Da mesma forma, podemos expandir hashes em argumentos de palavra-chave usando o duplo splat:
def metodo_com_keywords(cidade:, estado:, cep:) "Moro em #{cidade}, #{estado} #{cep}" end dados = {cidade: "Recife", estado: "PE", cep: "50030-150"} metodo_com_keywords(**dados) # => "Moro em Recife, PE 50030-150"
Passando Blocos como Argumentos
Uma técnica poderosa em Ruby é a capacidade de converter um objeto Proc
em um bloco para passá-lo a um método:
["a", "b", "c"].map { |s| s.upcase } # => ["A", "B", "C"]
Existe um atalho muito usado com o operador &
quando o bloco apenas chama um método:
["a", "b", "c"].map(&:upcase) # => ["A", "B", "C"]
Isso funciona porque a classe Symbol
implementa o método to_proc
, retornando um objeto Proc
que chama o método correspondente ao símbolo.
Outra aplicação interessante é criar blocos dinamicamente e passá-los aos métodos:
print "Operação ((m)ultiplicação ou (s)oma): " operador = gets print "número: " numero = Integer(gets) metodo = numero.method(operador.start_with?("m") ? :* : :+) puts((1..10).map(&metodo).join(", "))
Conclusão: O Poder dos Métodos em Ruby
Os métodos em Ruby são muito mais do que simples funções. Eles formam a base da expressividade e flexibilidade que torna a linguagem tão querida por desenvolvedores em todo o mundo. Com recursos como parâmetros nomeados, expansão de coleções e integração com blocos, os métodos Ruby podem ser adaptados para uma ampla variedade de cenários de programação.
Dominar a arte de definir e chamar métodos em Ruby é essencial para escrever código elegante, expressivo e de fácil manutenção.
Nenhum comentário:
Postar um comentário