Por que os pontos de exclamação são usados ​​nos methods Ruby?

Em Ruby, alguns methods possuem um ponto de interrogação ( ? ) Que faz uma pergunta como include? que perguntam se o object em questão está incluído, então retorna um verdadeiro / falso.

Mas por que alguns methods têm pontos de exclamação ( ! ) Onde outros não têm?

O que isso significa?

Em geral, methods que terminam em ! indica que o método irá modificar o object que é chamado . Ruby chama isso de ” methods perigosos ” porque mudam de estado para o qual alguém pode ter uma referência. Aqui está um exemplo simples para strings:

 foo = "A STRING" # a string called foo foo.downcase! # modifies foo itself puts foo # prints modified foo 

Isto irá produzir:

 a string 

Nas bibliotecas padrão, existem muitos lugares onde você verá pares de methods com nomes semelhantes, um com o ! e um sem. Os que não estão são chamados de “methods seguros”, e eles retornam uma cópia do original com as alterações aplicadas à cópia , com a calibração inalterada. Aqui está o mesmo exemplo sem o ! :

 foo = "A STRING" # a string called foo bar = foo.downcase # doesn't modify foo; returns a modified string puts foo # prints unchanged foo puts bar # prints newly created bar 

Isso gera:

 A STRING a string 

Tenha em mente que isso é apenas uma convenção, mas muitas classs Ruby o seguem. Ele também ajuda você a acompanhar o que está sendo modificado em seu código.

O ponto de exclamação significa muitas coisas, e às vezes você não pode contar muito com isso, a não ser “isso é perigoso, tenha cuidado”.

Como outros já disseram, em methods padrão é freqüentemente usado para indicar um método que faz com que um object se mude, mas nem sempre. Note que muitos methods padrão mudam seu receptor e não tem um ponto de exclamação ( pop , shift , clear ), e alguns methods com pontos de exclamação não mudam de receptor ( exit! ). Veja este artigo por exemplo.

Outras bibliotecas podem usá-lo de maneira diferente. No Rails, um ponto de exclamação geralmente significa que o método lançará uma exceção na falha, em vez de falhar silenciosamente.

É uma convenção de nomenclatura, mas muitas pessoas a usam de maneiras sutilmente diferentes. Em seu próprio código, uma boa regra dos polegares é usá-lo sempre que um método está fazendo algo “perigoso”, especialmente quando existem dois methods com o mesmo nome e um deles é mais “perigoso” do que o outro. “Perigoso” pode significar quase tudo embora.

Essa convenção de nomenclatura é levantada do Scheme .

1.3.5 Convenções de Nomenclatura

Por convenção, os nomes dos procedimentos que sempre retornam um valor booleano normalmente terminam em “? ”. Tais procedimentos são chamados predicados.

Por convenção, os nomes dos procedimentos que armazenam valores em locais previamente alocados (veja seção 3.4) geralmente terminam em “! ”. Tais procedimentos são chamados de procedimentos de mutação. Por convenção, o valor retornado por um procedimento de mutação não é especificado.

! Normalmente, significa que o método age sobre o object, em vez de retornar um resultado. Do livro Programming Ruby :

Métodos que são “perigosos”, ou modificam o receptor, podem ser nomeados com um “!” À direita.

De themomorohoax.com:

Um estrondo pode ser usado das maneiras abaixo, na ordem de minha preferência pessoal.

1) Um método de registro ativo gera um erro se o método não fizer o que disser.

2) Um método de registro ativo salva o registro ou um método salva um object (por exemplo, tira!)

3) Um método faz algo “extra”, como posts em algum lugar, ou faz alguma ação.

O ponto é: use apenas um estrondo quando você realmente pensou se é necessário, para salvar outros desenvolvedores, o incômodo de ter que verificar por que você está usando um estrondo.

O estrondo fornece duas sugestões para outros desenvolvedores.

1) que não é necessário salvar o object depois de chamar o método.

2) quando você chama o método, o database será alterado.

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods

É mais correto dizer que os methods com um Bang! são a versão mais perigosa ou surpreendente . Existem muitos methods que sofrem mutação sem um Bang como o .destroy e, em geral, os methods têm apenas franja onde existe uma alternativa mais segura no core lib.

Por exemplo, no Array temos .compact e .compact! ambos os methods .compact! o array, mas .compact! retorna nulo ao invés de si mesmo se não houver nenhum nulo na matriz, o que é mais surpreendente do que apenas retornar a si mesmo.

O único método não mutante que eu encontrei com um estrondo é o .exit! Kernel .exit! o que é mais surpreendente que .exit porque você não pode pegar SystemExit enquanto o processo está sendo fechado.

Rails e ActiveRecord continuam esta tendência em que usa bang para efeitos mais ‘surpreendentes’ como .create! o que gera erros na falha.

Explicação simples:

 foo = "BEST DAY EVER" #assign a string to variable foo. => foo.downcase #call method downcase, this is without any exclamation. "best day ever" #returns the result in downcase, but no change in value of foo. => foo #call the variable foo now. "BEST DAY EVER" #variable is unchanged. => foo.downcase! #call destructive version. => foo #call the variable foo now. "best day ever" #variable has been mutated in place. 

Mas se você já chamou um método downcase! na explicação acima, foo mudaria para downcase permanentemente. downcase! não retornaria um novo object string, mas replaceia a string no lugar, mudando totalmente o foo para downcase. Eu sugiro que você não use downcase! a menos que seja totalmente necessário.

Chamado de “Métodos Destrutivos” Eles tendem a alterar a cópia original do object a que você está se referindo.

 numbers=[1,0,10,5,8] numbers.collect{|n| puts n*2} # would multiply each number by two numbers #returns the same original copy numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array numbers # returns [nil,nil,nil,nil,nil] 

Bottom line:! Os methods apenas alteram o valor do object para o qual são chamados, enquanto um método sem ! retorna um valor manipulado sem escrever sobre o object que o método foi chamado.

Apenas use ! se você não planeja precisar do valor original armazenado na variável na qual você chamou o método.

Eu prefiro fazer algo como:

 foo = "word" bar = foo.capitalize puts bar 

OU

 foo = "word" puts foo.capitalize 

Ao invés de

 foo = "word" foo.capitalize! puts foo 

Apenas no caso eu gostaria de acessar o valor original novamente.

 ! 

Eu gosto de pensar nisso como uma mudança explosiva que destrói tudo o que aconteceu antes dele. Bang ou ponto de exclamação significa que você está fazendo uma alteração salva permanente em seu código.

Se você usar, por exemplo, o método de Ruby para substituição global, gsub! a substituição que você faz é permanente.

Outra maneira que você pode imaginar é abrir um arquivo de texto e localizar e replace, seguido de salvar. ! faz o mesmo no seu código.

Outro lembrete útil se você vem do mundo bash é sed -i tem esse efeito semelhante de fazer alterações salvas permanentes.