O guia de estilo para Ruby do Airbnb.
Inspirado por GitHub's guide e Bozhidar Batsov's guide.
Airbnb também mantém o Guia de estilo para JavaScript.
- Espaços em branco 1. Indentação 1. Linha única 1. Novas linhas
- Tamanho das linhas
- Comentários 1. Comentários de arquivos/classes 1. Comentários de funções 1. Comentários de blocos e linhas únicas 1. Pontuação, ortografia e gramática 1. Comentários de pendências 1. Códigos comentado
- Métodos 1. Definição de métodos 1. Chamada de métodos
- Expressões condicionais 1. Palavras condicionais 1. Operador ternário 1. Condições longas
- Sintaxe
- Nomenclatura
- Classes
- Exceções
- Coleções
- Textos
- Expressões regulares
- Notação de porcentagem
- Rails 1. Escopo
- Seja consistente
- Tradução
-
Use tabs com dois espaçamentos.[link]
-
Indente
when
da mesma forma quecase
. [link]case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end
-
Alinhe todos os parâmetros de função ou na mesma linha ou um por linha.[link]
# ruim def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # bom def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # bom def self.create_translation( phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification ) ... end
-
Indente continuamente múltiplas linhas de expressões condicionais.[link]
# ruim def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end # bom def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end
-
Nunca deixe espaços em branco soltos. [link]
-
Quando fizer comentários em apenas uma, inclua um espaço entre o fim do código e o começo do comentário. [link]
# ruim result = func(a, b)# Nós podemos alterar b para c # bom result = func(a, b) # Nós podemos alterar b para c
-
Use espaço ao redor de operadores e depois de virgulas, dois pontos, ponto e virgula e ao redor de
{
e antes de}
. [link]sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts 'Hi' [1, 2, 3].each { |e| puts e }
-
Nunca inclua um espaço antes de uma virgula. [link]
result = func(a, b)
-
Não inclua espaço dentro de blocos de parâmetros. Inclua um espaço entre parâmetros dentro de um bloco. Inclua um espaço fora do bloco de parâmetro. [link]
# ruim {}.each { | x, y |puts x } # bom {}.each { |x, y| puts x }
-
Não deixe espaço entre
!
e a variável. [link]!something
-
Não use espaço depois de
(
,[
ou antes de]
,)
. [link]some(arg).other [1, 2, 3].length
-
Não use espaços quando utilizar textos com variáveis.[link]
# ruim var = "This #{foobar} is interpolated." # bom var = "This #{foobar} is interpolated."
-
Não use espaços em range númericos. [link]
# ruim (0 ... coll).each do |item| # bom (0...coll).each do |item|
-
Adiciona uma nova linha depois da condição
if
usada com múltiplas linhas para ajudar diferenciar entre condições e o conteúdo. [link]if @reservation_alteration.checkin == @reservation.start_date && @reservation_alteration.checkout == (@reservation.start_date + @reservation.nights) redirect_to_alteration @reservation_alteration end
-
Adiciona uma nova linha depois de condicionais, blocos, switch-case, etc.[link]
if robot.is_awesome? send_robot_present end robot.add_trait(:human_like_intelligence)
-
Não quebre linhas entre diferentes conteúdos (Como classes ou módulos). [link]
# ruim class Foo def bar # conteúdo omitido end end # bom class Foo def bar # conteúdo omitido end end
-
Inclua APENAS uma nova linha entre métodos. [link]
def a end def b end
-
Use apenas uma linha como espaçamento entre blocos lógicos. [link]
def transformorize_car car = manufacture(options) t = transformer(robot, disguise) car.after_market_mod! t.transform(car) car.assign_cool_name! fleet.add(car) car end
-
Finalize cada linha com uma nova linha. Não inclua múltiplas linhas no fim do seu arquivo. [link]
- Mantenha cada linha do código com um tamanho viável para leitura. A não ser que você tenha uma razão para não fazer, mantenha linhas com menos de 100 caracteres. (rationale) [link]
Apesar de ser chato de escrever, comentários são extremamente importantes para manter o código viável para leitura. As regras a seguir descrevem o que você devería comentar e aonde. Mas lembre-se: Enquanto comentários são muito importantes, um bom código é auto-documentável. Definir nomes com sentido para variáveis e métodos são melhores do que usar nomes sem significado que você precise explicar através de comentários.
Enquanto estiver escrevendo seus comentários, escreva para o seu público: O próximo colaborador que irá precisar entender seu código. Seja generoso - o próximo pode ser você!
Partes dessa seção foram fortemente emprestados dos guias de estilo do Google C++ e Python.
Toda definição de classe deve ter um comentário que descreve o que ela faz e como usa-la.
Um arquivo que contém nenhuma ou alguma classe deve ter um comentário no seu ínicio descrevendo o seu conteúdo.
# Conversão automática de uma localização para outra que seja possível, como
# América para Inglês britanico.
module Translation
# Classe para conversão entre textos entre localizações similares.
# Por enquanto, somente conversões entre inglês americano -> Britânico,
# Canadense, Australiano, Nova Zelandia e variações são possíveis.
class PrimAndProper
def initialize
@converters = { :en => { :"en-AU" => AmericanToAustralian.new,
:"en-CA" => AmericanToCanadian.new,
:"en-GB" => AmericanToBritish.new,
:"en-NZ" => AmericanToKiwi.new,
} }
end
...
# Permite transformar em inglês americano o que é comum entre
# todas as outras colonias inglesas.
class AmericanToColonial
...
end
# Converte inglês americano para inglês britânico.
# Para outras variações de colonias inglesas, altere "apartment" para "flat".
class AmericanToBritish < AmericanToColonial
...
end
Todos os arquivos, incluindo arquivos de configuração e base de dados, devem ter comentários.
# Lista de variações de pronuncias de America-para-Britânico.
#
# Essa lista é feita com
# lib/tasks/list_american_to_british_spelling_variants.rake.
#
# Ela contém palavras com variações de pronuncias:
# [trave]led/lled, [real]ize/ise, [flav]or/our, [cent]er/re, plus
# and these extras:
# learned/learnt, practices/practises, airplane/aeroplane, ...
sectarianizes: sectarianises
neutralization: neutralisation
...
Toda declaração de função deve ter comentários imediatamente antes de sua definição, que descreva o que a função faz e como deve ser usada. Esse comentário deve ser preferivel ("Abre os arquivos") ao invés de ("Abra o arquivo"); o comentário descreve a função, não diz para a função o que fazer. No geral, esse comentário não descreve como a função funciona. Por outro lado, isso deve ser deixado para comentários dentro do código da função.
Toda função deve mencionar o que são as variáveis de entrada e saída, a não ser que siga todos os critérios abaixo:
- Não é visivel externamente
- Muito pequena
- Óbvio
Você pode usar o formato que desejaar. Em Ruby, duas documentações populares de função são: TomDoc e YARD. Você também pode apenas escrever algo conciso:
# Retorna o localização de fallback para a variável the_locale.
# Se opts[:exclude_default] estiver setado, a localização padrão,
# que sempre é a ultima posição da lista, será excluída.
#
# Por exemplo:
# fallbacks_for(:"pt-BR")
# => [:"pt-BR", :pt, :en]
# fallbacks_for(:"pt-BR", :exclude_default => true)
# => [:"pt-BR", :pt]
def fallbacks_for(the_locale, opts = {})
...
end
Outro lugar para ter comentários é em partes importantes do seu código. Se você vai ter que explicar durante o code review, é melhor comentar agora. Operações complicadas merecem algumas linhas de comentários antes do seu começo. Operações não óbvias, ganham comentários no fim da linha.
def fallbacks_for(the_locale, opts = {})
# dup() produz um array que podemos alterar
ret = @fallbacks[the_locale].dup
# Temos que assumir duas coisas aqui:
# 1) Há apenas uma localização padrão.
# 2) O localização padrão é um idioma. (Como :pt, e não :"pt-BR".)
if opts[:exclude_default] &&
ret.last == default_locale &&
ret.last != language_from_locale(the_locale)
ret.pop
end
ret
end
Por outro lado, nunca descreva seu comentário. Assuma que a pessoa lendo o código conhece a linguagem (e não o que você está fazendo) melhor que você.
Relacionado: Não use blocos de comentários. Eles não podem ser precedidos por espaços e não são fáceis de encaixar no código se comparado a comentários padrões. [link]
# ruim
=begin
comment line
another comment line
=end
# bom
# comentários aqui
# mais comentários
Preste atenção para pontuação, ortografia e gramática; é mais fácil ler comentários bem escritos do que comentários mal escritos.
Comentários devem ser tão fáceis de ler quanto textos de narrativa, com suas definidas pontuações e letras maiusculas. Em muitos casos, completar as frases é mais fácil de ler do que pedaços de textos. Comentários pequenos, como comentários no fim da linha do código, podem muitas vezes serem menos formais, mas você deve ser consistente com seu padrão.
Apesar que pode ser frustante ter passar por um code review que aponte que você está usando virgula ao invés de ponto e virgula, é muito importante que seu código mantenha um nível alto de clareza e leitura. Pontuação, gramática e ortografia adequadas, ajudam a alcançar o objetivo.
Comentários de pendências no código são temporários, uma solução a curto prazo.
Comentários de pendências devem incluir a palavra TODO, seguido pelo nome completo da pessoa que conhece mais do problema. Dois pontos é opcional. Um comentário explicando qual o requisito dessa tarefa é obrigatório. A principal motivação de ter um comentário de pendência é ser fácil de encontrar a pessoa que está sendo mencionada. Esse comentário não é um compromisso para a pessoa resolver o problema. Tanto que, quando você cria um comentário de pendência, costuma ser o seu nome que será mencionado.
# ruim
# TODO(RS): Use o devido nome para essa variável.
# ruim
# TODO(drumm3rz4lyfe): Use o devido nome para essa variável.
# bom
# TODO(Ringo Starr): Use o devido nome para essa variável.
- NUNCA deixe trechos de códigos comentados no seu código. [link]
-
Crie
def
com parênteses quando contém parâmetros. Não use parênteses quando o metodo não aceita parâmetros. [link]def metodo # sem conteudo end def metodo_com_parametros(arg1, arg2) # sem conteudo end
-
Não use argumentos de definição de valores. Use argumentos (se disponível - Ruby 2.0 ou posterior) ou um hash de opções.[link]
# ruim def obliterate(things, gently = true, except = [], at = Time.now) ... end # bom def obliterate(things, gently: true, except: [], at: Time.now) ... end # bom def obliterate(things, options = {}) options = { :gently => true, # remove com um soft-delete :except => [], # não remove esses itens :at => Time.now, # define o horário de remoção }.merge(options) ... end
-
Evite escrever metodos em uma linha só. Apesar de ser populares, existe algumas pecularidades que fazem dessa abordagem indesejável. [link]
# ruim def too_much; something; something_else; end # bom def some_method # conteudo end
Uso do parênteses para uma chamada de método:
-
Se o método retorna um valor. [link]
# ruim @current_user = User.find_by_id 1964192 # bom @current_user = User.find_by_id(1964192)
-
Se o primeiro argumento do método necessita de parenteses.[link]
# ruim put! (x + y) % len, value # bom put!((x + y) % len, value)
-
Nunca coloque espaço entre o nome do método e parenteses.[link]
# bad f (3 + 2) + 1 # good f(3 + 2) + 1
-
Não use parênteses para uma chamada de método se o método aceita argumentos.[link]
# ruim nil?() # bom nil?
-
Se o método não retorna um valor (ou não nos importamos com o retorno), o parênteses é opcional. (Com exceção se o argumento ocupa múltiplas linhas, parênteses podem ajudar a leitura.) [link]
# bom render(:partial => 'foo') # bom render :partial => 'foo'
Em ambos os casos:
-
Se o método aceita um hash de opções como último argumento, não use
{
}
durante a chamada. [link]# ruim get '/v1/reservations', { :id => 54875 } # bom get '/v1/reservations', :id => 54875
-
Nunca use
then
comif/unless
em múltiplas linhas. [link]# ruim if some_condition then ... end # bom if some_condition ... end
-
Nunca use
do
comwhile
ouuntil
em múltiplas linhas. [link]# ruim while x > 5 do ... end until x > 5 do ... end # bom while x > 5 ... end until x > 5 ... end
-
As palavras
and
,or
, enot
estão banidas. Não as use. Ao invés, sempre use&&
,||
, e!
. [link] -
Modificar
if/unless
é válido quando o conteúdo é pequeno, a condição é simples e tudo se encaixa em uma linha. Caso contrário, evite modificarif/unless
. [link]# ruim - isso não se encaixa em uma linha add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? # okay if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) end # ruim - isso é complexo e merece multiplas linhas e comentários parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i) # okay return if reconciled?
-
Nunca use
unless
comelse
. Reescreva com o uso deif
.[link]# ruim unless success? puts 'failure' else puts 'success' end # bom if success? puts 'success' else puts 'failure' end
-
Evite usar `unless``com múltiplas condições.[link]
# bad unless foo? && bar? ... end # okay if !(foo? && bar?) ... end
-
Evite usar
unless
com operadores de comparação. Useif
nesse caso.[link]# ruim unless x == 10 ... end # bom if x != 10 ... end # ruim unless x < 10 ... end # bom if x >= 10 ... end # ok unless x === 10 ... end
-
Não use parênteses nas condições em
if/unless/while
. [link]# ruim if (x > 10) ... end # bom if x > 10 ... end
-
Evite utilizar operadores ternários (
?:
) a não ser que a condição seja extremamente trivial. Por outro lado, use o operador ternário (?:
) ao invés deif/then/else/end
para condições de linhas únicas.[link]# ruim result = if some_condition then something else something_else end # bom result = some_condition ? something : something_else
-
Use uma expressão por bloco em operadores ternários. Isso significa que operadores ternários não devem ser longos. Prefira
if/else
nesses casos.[link]# ruim some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # bom if some_condition nested_condition ? nested_something : nested_something_else else something_else end
-
Evite multiplas condições em operadores ternários. Operadores ternários são melhor usados em condições simples. [link]
-
Evite multiplas linhas com o operador ternário
?:
, nesses casos, useif/then/else/end
. [link]# ruim some_really_long_condition_that_might_make_you_want_to_split_lines ? something : something_else # bom if some_really_long_condition_that_might_make_you_want_to_split_lines something else something_else end
-
Evite utilizar condições muito longas para controle do fluxo. (Leia mais sobre isso.) [link]
Prefira utilizar uma clause guard quando pode receber um dado inválida. Uma guard clause é uma condição no topo de uma função que retorna assim que possível.
Os principios dessa clausula, são:
- Retorna assim que sua função sabe que não pode fazer mais nada.
- Diminui o tamanho do código. Isso faz o código ser mais fácil de ler e necessita menos atenção em relação a blocos
if/else
. - O fluxo principal deve ser o último a ser validado.
# ruim def compute server = find_server if server client = server.client if client request = client.make_request if request process_request(request) end end end end # bom def compute server = find_server return unless server client = server.client return unless client request = client.make_request return unless request process_request(request) end
Durante os laços, prefira utilizar
next
ao invés de blocos condicionais.# ruim [0, 1, 2, 3].each do |item| if item > 1 puts item end end # bom [0, 1, 2, 3].each do |item| next unless item > 1 puts item end
Veja também a seção "Guard Clause", p68-70 in Beck, Kent. Implementation Patterns. Upper Saddle River: Addison-Wesley, 2008, que inspirou o conteúdo acima.
-
Nunca use
for
, a não ser que você saiba o por que. Utilize outros interatores.for
é implementado da mesma forma que oeach
, porém com uma divergência,for
não introduz um novo escopo e variáveis definidas dentro do seu bloco serão vistas fora dele.[link]arr = [1, 2, 3] # ruim for elem in arr do puts elem end # bom arr.each { |elem| puts elem }
-
Prefira
{...}
ao invés dedo...end
para blocos únicos. Evite usar{...}
para blocos de múltiplas linhas (Chaves com multiplas linhas sempre são mal vistos). Sempre usedo...end
para "controle do fluxo" e "definição de métodos" (Exemplo: em Rakefiles e alguns DSLs). Evitedo...end
com encadeamento.[link]names = ["Bozhidar", "Steve", "Sarah"] # bom names.each { |name| puts name } # ruim names.each do |name| puts name end # bom names.each do |name| puts name puts 'yay!' end # ruim names.each { |name| puts name puts 'yay!' } # bom names.select { |name| name.start_with?("S") }.map { |name| name.upcase } # ruim names.select do |name| name.start_with?("S") end.map { |name| name.upcase }
Algumas pessoas irão argumentar que chaves com multiplas linhas são bem vistas com o uso do
{...}
, mas elas devem perguntar a si mesmo se esse código é de fácil leitura e também se o conteúdo pode ser extraído em algum método. -
Sempre que possível, use a forma abreviada dos operadores.[link]
# ruim x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # bom x += y x *= y x **= y x /= y x ||= y x &&= y
-
Evite usar ponto e vírgula, com exceção de declarações de classes em uma linha. Quando for apropriado utilizar ponto e vírgula, utilize apenas quando o bloco lógico estiver terminado: Não deve ter espaço antes do ponto e vírgula.[link]
# ruim puts 'foobar'; # Desnecessário uso do ponto e vírgula puts 'foo'; puts 'bar' # Duas expressões na mesma linha. # bom puts 'foobar' puts 'foo' puts 'bar' puts 'foo', 'bar' # Isso se aplica a puts em particular
-
Use :: apenas para referenciar constantes (Isso inclui classes e módulos) e construtores (Array() ou Nakogiri::HTML()). Não use :: para inicialização de métodos. [link]
# ruim SomeClass::some_method some_object::some_method # bom SomeClass.some_method some_object.some_method SomeModule::SomeClass::SOME_CONST SomeModule::SomeClass()
-
Evite usar
return
quando não for necessário. [link]# ruim def some_method(some_arr) return some_arr.size end # bom def some_method(some_arr) some_arr.size end
-
Não faça condições com o uso de
=
.[link]# ruim - deixa explicito o uso da condição if (v = array.grep(/foo/)) ... end # ruim if v = array.grep(/foo/) ... end # bom v = array.grep(/foo/) if v ... end
-
Está liberado o uso de
||=
na inicialização das variáveis. [link]# Define o nome para Bozhidar, somente se ele for nil ou false name ||= 'Bozhidar'
-
Não use
||=
para inicializar variáveis do tipo boolean, ao invés disso, considere o que deve ser feito caso a variável esteja definida comofalse
)[link]# ruim - vai definir como true, caso seja false enabled ||= true # bom enabled = true if enabled.nil?
-
Use
.call
explicitamente quando for usar lambdas. [link]# ruim lambda.(x, y) # bom lambda.call(x, y)
-
Evite usar o estilo Perl para variáveis especiais (como,
$0-9
,$
, etc. ). Seu uso é meio enigmático e desincorajado. Prefira formas mais completas, como:$PROGRAM_NAME
.[link] -
Quando um metodo contém apenas um argumento, e seu conteúdo é apenas uma leitura ou chamada de outro método sem argumentos, use a abreviação
&:
. [link]# ruim bluths.map { |bluth| bluth.occupation } bluths.select { |bluth| bluth.blue_self? } # bom bluths.map(&:occupation) bluths.select(&:blue_self?)
-
Prefira utilizar
some_method
do queself.some_method
quando usar outro método da mesma instancia.[link]# ruim def end_date self.start_date + self.nights end # bom def end_date start_date + nights end
Nos casos de uso a seguir,
self.
é obrigatório na linguagem e uma boa prática:- Quando está definindo um método de uma classe:
def self.some_method
. - O lado esquerdo da igualdade, quando chamar o método de atribuição, incluindo atribuição de um atributo e
self
sendo uma model do ActiveRecord:self.guest = user
. - Referenciando a instance da classe atual:
self.class
.
- Quando está definindo um método de uma classe:
-
Quando for definir algum objeto de um tipo que pode ser alterado, mas com a intenção de ser uma constante, não esqueça de utilizar o método
freeze
. Exemplos comuns são: strings, arrays, e hashes. (Leia mais sobre isso.)[link]Isso acontece por que no Ruby, constantes não tem um tipo único. Utilizando
freeze
nós garantimos que o tipo não será mudado e portanto será uma constante de fato, qualquer tentativa de mudança irá gerar uma exceção.# ruim class Color RED = 'red' BLUE = 'blue' GREEN = 'green' ALL_COLORS = [ RED, BLUE, GREEN, ] COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, } end # bom class Color RED = 'red'.freeze BLUE = 'blue'.freeze GREEN = 'green'.freeze ALL_COLORS = [ RED, BLUE, GREEN, ].freeze COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, }.freeze end
-
Para métodos e variáveis, utilize o padrão
snake_case
. [link] -
Para classes ou módulos, utilize o padrão
CamelCase
. (Mantenha singlas, como: HTTP, RFC, XMLUPPERCASE
.) [link] -
Para outras constantes, utilize o padrão:
SCREAMING_SNAKE_CASE
.[link] -
Nome dos predicados dos métodos (Método que retorna um valor boolean) devem terminar com ponto de interrogação (exemplo:
Array#empty?
).[link] -
Nome de métodos que são potenciallmente "perigosos" (exemplo: métodos que modificam
self
ou argumentos,exit!
, etc.) devem terminar com um ponto de exclamação. Umbang method
só deve existir caso haja umnon-bang
correspondente. (Leia mais sobre isso.) [link] -
Nomeie variáveis temporarias com
_
. [link]version = '3.2.1' major_version, minor_version, _ = version.split('.')
-
Evite usar (
@@
) em classes devido ao seu comportamento desagradável em heranças. [link]class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => Irá imprimir "child"
Como você pode ver, todas as classes em um sistema de hierarquia irão compartilhar uma variável em comum. As variáveis da classe instanciada são preferíveis a variáveis da classe atual.
-
Use
def self.method
para definir métodos com o padrão singleton. Isso faz com que o método seja mais resistente a mudanças. [link]class TestClass # ruim def TestClass.some_method ... end # bom def self.some_other_method ... end
-
Evite
class << self
, exceto quando necessário. exemplo: Atributos auxiliares. [link]class TestClass # ruim class << self def first_method ... end def second_method_etc ... end end # bom class << self attr_accessor :per_page alias_method :nwo, :find_by_name_with_owner end def self.first_method ... end def self.second_method_etc ... end end
-
Indente métodos
public
,protected
, eprivate
tanto quanto a definição do método é aplicada. Deixe uma linha vazia antes e depois.[link]class SomeClass def public_method # ... end private def private_method # ... end end
-
Não use exceções para controle de fluxo. [link]
# ruim begin n / d rescue ZeroDivisionError puts "Cannot divide by 0!" end # bom if d.zero? puts "Cannot divide by 0!" else n / d end
-
Evite capturar a classe
Exception
. [link]# ruim begin # uma exceção acontece aqui rescue Exception # lidando com a exceção end # bom begin # uma exceção acontece aqui rescue StandardError # lidando com a exceção end # aceitável begin # uma exceção acontece aqui rescue # lidando com a exceção end
-
Não declare a exceção
RuntimeError
com dois argumentos. Prefira erros de sub-classes e erros explicítos de criação.[link]# ruim raise RuntimeError, 'message' # melhor - RuntimeError está implicito aqui raise 'message' # ótimo class MyExplicitError < RuntimeError; end raise MyExplicitError
-
Ao invés de uma instancia para tratar a exceção,'prefira fornecer uma classe e uma mensagem para exceção em dois argumentos separados com
raise
. [link]# ruim raise SomeException.new('message') # Note que não há uma forma de fazer: `raise SomeException.new('message'), backtrace`. # bom raise SomeException, 'message' # Consistente com `raise SomeException, 'message', backtrace`.
-
Evite usar
rescue
na sua forma modificada. [link]# ruim read_file rescue handle_error($!) # bom begin read_file rescue Errno:ENOENT => ex handle_error(ex) end
-
Prefira o método
map
aocollect
.[link] -
Prefira o método
detect
ao invés defind
.find
tem um uso ambiguo por causa do método do ActiveRecord'sfind
- Utilizardetect
deixa claro que você está trabalhando com uma coleção em Ruby, não um objeto ActiveRecord. [link] -
Prefira o método
reduce
ao invés deinject
. [link] -
Prefira o método
size
ao invés delength
oucount
por motivos performáticos.[link] -
Prefira criar array e hash de forma literal, a não ser que você passe parâmetros para seus construtores. [link]
# ruim arr = Array.new hash = Hash.new # bom arr = [] hash = {} # bom por que o construtor necessita de parâmetros x = Hash.new { |h, k| h[k] = {} }
-
Prefira
Array#join
do queArray#*
por clareza. [link]# ruim %w(one two three) * ', ' # => 'one, two, three' # bom %w(one two three).join(', ') # => 'one, two, three'
-
Nas hash key, use simbolos ao invés de strings. [link]
# ruim hash = { 'one' => 1, 'two' => 2, 'three' => 3 } # bom hash = { :one => 1, :two => 2, :three => 3 }
-
Use simbolos ao invés de strings sempre que possível.[link]
# ruim :"symbol" # bom :symbol
-
Use
Hash#key?
ao invés deHash#has_key?
eHash#value?
ao invés deHash#has_value?
. De acordo com Matz, as formas longas são consideradas desatualizadas. [link]# ruim hash.has_key?(:test) hash.has_value?(value) # bom hash.key?(:test) hash.value?(value)
-
Declare hashes em multiplas linhas quando for deixar o código mais fácil para leitura e utilize virgula para garantir que o parâmetro mudou. [link]
hash = { :protocol => 'https', :only_path => false, :controller => :users, :action => :set_password, :redirect => @redirect_url, :secret => @secret, }
-
Use vírgula em
Array
que abrange mais de uma linha [link]# bom array = [1, 2, 3] # bom array = [ "car", "bear", "plane", "zoo", ]
-
Prefira interpolar strings ao invés de concatena-las: [link]
# ruim email_with_name = user.name + ' <' + user.email + '>' # bom email_with_name = "#{user.name} <#{user.email}>"
Além disso, mantenha em mente que Ruby 1.9 liberou a interpolação. Digamos que você está usando cache keys como este:
CACHE_KEY = '_store' cache.write(@user.id + CACHE_KEY)
Prefira interpolar strings ao invés de concatena-las
CACHE_KEY = '%d_store' cache.write(CACHE_KEY % @user.id)
-
Evite usar
String#+
quando você precisa criar grandes pedaços de dado. Ao invés disso, useString#<<
. Concatenação altera o conteúdo da string e é sempre mais rápido queString#+
, que cria um novo objeto de strings.[link]# bom e rápido html = '' html << '<h1>Page title</h1>' paragraphs.each do |paragraph| html << "<p>#{paragraph}</p>" end
-
Para concatenar multiplas linhas de string use
\
no fim das linhas ao invés de+
ou<<
[link]# ruim "Some string is really long and " + "spans multiple lines." "Some string is really long and " << "spans multiple lines." # bom "Some string is really long and " \ "spans multiple lines."
-
Evite usar
$1-9
por que pode ser difícil de localizar o seu conteṕudo. Prefira usar variáveis. [link]# ruim /(regexp)/ =~ string ... process $1 # bom /(?<meaningful_var>regexp)/ =~ string ... process meaningful_var
-
Tenha cuidado com
^
e$
quando eles se encaixam no começo o no fim das linhas e não fim das strings. Se você quer localizar todo o texto, use:\A
e\z
.[link]string = "some injection\nusername" string[/^username$/] # encontrou string[/\Ausername\z/] # não encontrou
-
Para regex complexos, use
x
. Isso faz com que seja mais fácil de ler e você pode adicionar alguns comentários. Só tenha cuidado com os espaços que podem ser ignorados. [link]regexp = %r{ start # algum texto \s # caracter de espaço em branco (group) # primeiro grupo (?:alt1|alt2) # alguma alternativa end }x
-
Prefira parenteses ao invés de chaves, colchetes ou traço quando utilizar
%
para consistencia e pelo comportamento do%
ser mais próximos da chamada de métodos.[link]# ruim %w[date locale] %w{date locale} %w|date locale| # bom %w(date locale)
-
Use
%w
livremente.[link]STATES = %w(draft open closed)
-
Use
%()
para textos de linhas únicas que necessite tanto interpolação quando aspas duplas. Para multiplas linhas, prefira heredoc.[link]# ruim - sem necessidade de interpolação %(<div class="text">Some text</div>) # devería ser '<div class="text">Some text</div>' # ruim - sem aspas duplas %(This is #{quality} style) # Devería ser "This is #{quality} style" # ruim - multiplas linhas %(<div>\n<span class="big">#{exclamation}</span>\n</div>) # devería ser em heredoc. # bom - necessita de interpolação, tem aspas duplas e está em linha única. %(<tr><td class="name">#{name}</td>)
-
Use
%r
somente para expressões regulares localizando mais de um caracter '/'.[link]# ruim %r(\s+) # ainda ruim %r(^/(.*)$) # devería ser /^\/(.*)$/ # bom %r(^/blog/2011/(.*)$)
-
Evite o uso de
%x
, a não ser que você esteja invocando um comando com aspas invertidas (O que é indesejável). [link]# ruim date = %x(date) # bom date = `date` echo = %x(echo `date`)
-
Quando retornar imediatamente depois de
render
ouredirect_to
, coloquereturn
na próxima linha, não na mesma. [link]# ruim render :text => 'Howdy' and return # bom render :text => 'Howdy' return # ainda ruim render :text => 'Howdy' and return if foo.present? # bom if foo.present? render :text => 'Howdy' return end
-
Quando definir model no ActiveRecord, encaixe a relação em
lambda
. Sem isso, a relação força o banco de dados a estabelezer a conexão quando a classe é carregada, não no ínicio. [link]# ruim scope :foo, where(:bar => 1) # bom scope :foo, -> { where(:bar => 1) }
Se você está editando o código, invista um tempo olhando-o e determinando seu estio. Se ele usa espaço ao redor de todos os operadores aritméticos, você deve fazer também. Se os comentários contém pequenas caixas cercadas de barras, faça seus comentários da mesma forma.
A motivação de ter um guia de estilo é ter um vocabulário comum para que as pessoas possam se concentrar no que está sendo tido e não como está sendo tido. Nós apresentamos um estilo global para que as pessoas saibam esse vocabulário, mas vocabulários regionais também são importantes. Se você fizer um código completamente diferente dos códigos ao seu redor, irá causar intriga entre os leitores que forem ler ele. Evite isso.
Este guia também está disponível em outros idiomas:
- Chinês (Simplificado): 1c7/ruby-airbnb
- Inglês: airbnb/ruby