Como funciona o "Syntactic Sugar" em Ruby

Artigos - 18/Mar/2020 - por André Kanamura

Ruby é uma linguagem de programação que permite escrever código conciso e fácil de ler. Isso acontece porque a linguagem possui um conjunto de características comumente chamadas de "Syntactic Sugar", já que tornam a vida de quem escreve código mais "doce".

Ruby possui pequenas regras de linguagem que permitem escrever código que parece não corresponder às normas usuais, mas que tornam o código mais fácil de lembrar. Como, por exemplo, não exigir o inclusão de certos símbolos ou parênteses. Aqui vamos descrever apenas alguns exemplos de syntactic sugar que o Ruby possui. Afinal, seria demais explicar o funcionamento interno da linguagem de programação.

Nomes e chamadas de métodos

Usar símbolos para nomear métodos

Em Ruby é permitido usar símbolos para dar nome aos métodos. Podemos usar métodos Ruby como save! ou odd?, por exemplo. São permitidos caracteres como: =, [, ], ?, %, &, |, <, >, *, -, + e /.

Uma vantagem dessa propriedade é que podemos atribuir nomes de métodos que sejam mais representativos da sua função. Pode não parecer útil num primeiro momento, mas isso facilita muito a compreensão do que os códigos executam. O próprio Ruby se aproveita dessa característica para dar nomes bastante compreensíveis aos seus métodos. Por exemplo, o odd? pergunta se o valor é ímpar e retorna true ou false, ou map! mapeia os valores de um array e altera seus valores de acordo com a ação executada sobre cada um.

Assim, é possível criar métodos como user.employee? ou profile.destroy! que podem fazer mais sentido dentro do contexto da nossa aplicação.

Outro uso interessante dessa propriedade em programação orientada a objetos é que podemos criar métodos como esse:

class User 
  def initialize(name)
    @name = name
  end

  def name=(valor)
    @name = valor
  end

  def name
    return @name
  end
end

No código acima, criamos uma classe User e dois métodos, um para definir o valor de name (setter) e outro para obter o valor (getter). Note como o método setter name= recebe um parâmetro entre os parênteses. Dessa forma podemos fazer o seguinte:

user = User.new("João")

user.name
#=> "João"

user.name=("Henrique")
user.name
#=> "Henrique"

Ignorar parênteses e incluir espaços

Mais interessante ainda é que podemos ignorar os parênteses e adicionar um espaço na chamada do método, que mesmo assim o Ruby compreende o que está sendo feito e executa a operação.

user.name = "André"
user.name
#=> "André"

Dessa maneira a leitura do código fica muito mais clara e fácil de lembrar. Outra situação em que podemos omitir parênteses é na declaração do if:

puts "Hello, João" if(user.name == "João")
puts "Hello, João" if user.name == "João"

Ambos códigos acima funcionam. :)

attr_acessor

Para facilitar ainda mais nosso trabalho, podemos utilizar attr_accessor na criação de uma classe. Por trás dos panos, o Ruby cria os métodos de leitura e obtenção de atributos por conta própria.

class User 
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

user = User.new("André")
user.name
#=> "André"

Operadores matemáticos

Uma interessante exceção às regras de chamadas de métodos é que não é obrigatório usar o . entre um objeto e o método chamado. Quando estamos executando operações matemáticas, por exemplo, cada número é um objeto e cada operador é um método. Assim, uma simples conta de somar dois números

4 + 2
#=> 6

poderia ser executada da seguinte forma

4.+(2)
#=> 6

Muitos métodos têm essa propriedade:

+   -   *   /   =   ==    !=    >   <   >=    <=    []

O [] em especial, além de não precisar do ., pode encapsular os valores dos argumentos:

lista = ["banana", "ovos", "pão", "leite", "arroz"]

lista[1]
#=> "ovos"

lista.[](1)
#=> "ovos"

Laço de repetição for

Em Ruby, quando criamos o laço de repetição usando o for, internamente a linguagem monta um bloco each para iterar pelos valores do array. Por exemplo, quando executamos:

lista = ["banana", "ovos", "pão", "leite", "arroz"]

for item in lista
  puts item
  item = "comprado"
end

Na realidade, o Ruby internamente roda:

lista.each do |item|
  puts item
  item = "comprado"
end

A diferença é que o método each chama o bloco de código repetidas vezes, enquanto o for é uma construção da linguagem. No entanto, eles têm propriedades diferentes: a variável item dentro do laço de repetição for fica disponível fora do bloco, enquanto com o each a variável não existe fora do bloco.

Considerações finais

Assim concluímos essa rápida explicação sobre syntactic sugar em Ruby. Compilamos aqui alguns exemplos simples, mas isso compreende apenas uma visão superficial sobre o funcionamento da linguagem de programação. Com esse conhecimento você pode explorar as possibilidades e criar métodos e classes que aproveitam a liberdade criativa que o Ruby te oferece.

Para entender mais profundamente o código Ruby você pode ler o livro de Pat Shaughnessy Ruby Under The Microscope.

Referências

Foto de perfil do autor
André Kanamura

Dev na Campus Code