Há tempo, escrevi um artigo falando sobre 8 Dicas de PHP que você deveria conhecer, O público gostou bastante, principalmente por ter dicas muito úteis para o dia a dia de qualquer desenvolvedor. Seguindo essa mesma linha, juntei seis dicas de Ruby (e Rails) que você deveria conhecer.
Dica 1: Tags HTML nos ymls I18n
Por mais que não seja recomendável, é comum encontrarmos aplicações que utilizam tag html nos arquivos de traduções, como no exemplo abaixo:
# en.yml
en:
hello: "Hello <strong>%{user_name}</strong>!"
# index.html.erb
<%= t('hello', user_name: current_user.first_name) %>
Nesse exemplo, temos um problema, pois o texto que será mostrado na tela será o seguinte “Hello <strong>Allan</strong>!”. Isso mesmo, o texto imprime as tags e não as utiliza como html. Até aí, tudo bem. Esquecemos de utilizar o html_safe, logo, o resultado seria assim:
# index.html.erb
<%= t('hello', user_name: current_user.first_name).html_safe %>
Agora, você abriu uma brecha de segurança na qual qualquer usuário poderá fazer XSS no seu sistema. Mas não se preocupe: o Rails tem uma solução para isso no yml!
Você vai fazer assim:
# en.yml
en:
hello_html: "Hello <strong>%{user_name}</strong>!"
Ao inserir o “_html” na chave, o Rails entende que nesse texto tem html e, então, vai usar as tags corretamente. Você não precisa utilizar o “html_safe” na view. Fica assim:
# en.yml
en:
hello_html: "Hello <strong>%{user_name}</strong>!"
# index.html.erb
<%= t('hello', user_name: current_user.first_name) %>
Dica 2: Safe operator
Essa é para quem usa ruby 2.3+ (se você usa uma versão menor, está na hora de atualizar esa app). Os safe operators foram introduzidos na versão 2.3 e têm o mesmo comportamento semelhante ao do objeto `try`.
# Caso de sucesso
2.4.1 :001 > array = [1, 2]
2.4.1 :002 > array.first.positive?
=> true
# Caso de erro
2.4.1 :001 > array = []
2.4.1 :002 > array.first.positive?
NoMethodError: undefined method `positive?' for nil:NilClass
# Caso de tratamento com safe operator
2.4.1 :001 > array = []
2.4.1 :002 > array.first&.positive?
=> nil
Assim como o try, o safe operator faz a validação antes de executar o método, impedindo que exploda um erro, e no caso de erro retorna `nil`.
Dica 3: Mapear array
Muitas vezes temos alguns arrays com elementos fixos que vamos trabalhar dentro de um método enumerable X. Em vez de ficar repetidamente chamando `array[0]`, podemos mapear o hash da seguinte forma:
names_and_companies = [
['Allan Klaus', 'Locaweb'],
['Amleto Denmarke', 'Locaweb'],
]
O mais comum seria trabalhar com esse hash da seguinte maneira:
names_and_companies.map { |element| "#{element[0]} works at #{element[1]}" }
Porém, mapeando o hash, você pode trabalhar definindo um nome para as posições do array, facilitando a leitura e entendimento do que está acontecendo.
names_and_companies.map { |(name, company)| "#{name} works at #{company}" }
Dica 4: Keyword arguments
Há muitas formas de declarar a assinatura de um método no Ruby. A mais comum é positional arguments, que é o exemplo abaixo:
# Positional Arguments
def my_method(arg_1:, arg_2:, arg_3:)
[arg_1, arg_2, arg_3]
end
my_method(1, 'a', Object.new)
=> [1, "a", #<Object:0x000000011f3780>]
A forma positional arguments tem um gap no fato que, sempre que for usar o método, é preciso saber as posições de argumentos da assinatura. Uma forma de evitar isso é montar a assinatura do método com keyword arguments.
def my_method(arg_1:, arg_2:, arg_3:)
[arg_1, arg_2, arg_3]
end
my_method(arg_2: 'a', arg_3: Object.new, arg_1: 1)
=> [1, "a", #<Object:0x00000001216bb8>]
Dica 5: Transform values (hash)
Essa dica é só para quem usa Ruby 2.4+.
Quando precisamos fazer uma alteração em todos os elementos de um hash, até a versão 2.3 podemos utilizar uma das seguintes abordagens:
my_hash = { a: 1, b: 2, c: 4 }
my_hash.inject({}) { |h, (k, v)| h.merge(k => v * 2) }
=> { :a=>2, :b=>4, :b=>8 }
my_hash.each_with_object({}) { |(k, v), h| h[k] = v * 2 }
=> { :a=>2, :b=>4, :b=>8 }
my_hash.map { |k, v| [ k, v * 2 ] }.to_h
=> { :a=>2, :b=>4, :b=>8 }
Com a versão 2.4, podemos utilizar o método `transform_values`, esse método faz exatamente o que faríamos, só que em alto nível.
my_hash.transform_values { |v| v * 2 }
=> { :a=>2, :b=>4, :b=>8 }
O `transform_values` também implementa o “!”. Assim, você pode sobrescrever o valor do seu hash ao utilizar – o que não era possível de forma “tão simples” nas versões anteriores.
Dica 6: Métodos de classe/objeto no console
Uma coisa que sempre causa dúvida é saber quais são os métodos de determinada classe. Para isso é simples, basta usar Object.methods.
Desta maneira, você estará listando todos os métodos da classe. Também podemos buscar por algum método específico:
Object.methods.grep(/exec/)
=> [:module_exec, :class_exec, :trace_execution_scoped, :trace_execution_unscoped, :instance_exec]
Você pode fazer o mesmo para objetos instanciados:
my_object = Object.new
=> #<Object:0x000000058c5848>
my_object.methods
Também podemos aplicar a busca por métodos no objeto instanciado:
my_object.methods.grep(/exec/)
=> [:instance_exec]
É algo muito legal saber os métodos. Poderíamos pensar “sei que tem um método X, mas queria olhar para esse método, queria entender o que está por ‘baixo dos panos’”. Nesse caso, temos duas alternativas para isso:
Podemos olhar onde está localizado esse método para abrimos o arquivo. Nesse caso, podemos usar o source_location (esse método não funciona para métodos implementados em outras linguagens):
# /home/test.rb
class MyClass
def test
return 'test'
end
end
2.5.1 :001 > require './test'
=> true
2.5.1 :002 > my_object = MyClass.new
=> #<MyClass:0x00000001800bc8>
2.5.1 :003 > my_object.method(:test).source_location
=> ["/home/test.rb", 2]
O método indica em qual arquivo está e a linha do método. É muito útil no caso de você precisar alterar o código do método em questão. Caso o nosso objetivo seja só mostrar o código do método na tela, podemos usar:
2.5.1 :004 > require 'method_source'
=> true
2.5.1 :006 > my_object.method(:test).source.display
def test
return 'test'
end
=> nil
Tem mais alguma dica que acha legal? Compartilhe conosco nos comentários!