5 exemplos da melhor utilização do Ruby
Já alguma vez pensou no que podemos fazer com Ruby? Bem, o céu é provavelmente o limite, mas temos todo o gosto em falar sobre alguns casos mais ou menos conhecidos...
Antes de começarmos a criar um método bang, vamos aprender o que é exatamente este tipo de método e quais são as suas caraterísticas. Comecemos pelo facto de não existir uma definição inequívoca para este tipo de métodos. Em termos simples, um método bang é um método com um ponto de exclamação no final.
É frequente encontrarmos uma afirmação de que o método bang é, de certa forma, um método perigoso e o ponto de exclamação no final da sua definição diz-nos nós para estar atento à utilização deste método. Vejamos: o que é exatamente esta ameaça no que diz respeito a estes métodos e quais são as suas caraterísticas?
Uma das caraterísticas mais populares deste tipo de métodos é o facto de normalmente mudarem o seu público. Vejamos o método map! como exemplo. De acordo com a documentação, o método map! invoca o bloco dado uma vez para cada elemento de self, substituindo o elemento pelo valor devolvido pelo bloco e, se não for dado nenhum bloco, é devolvido um Enumerador.
arry = [1, 2, 3, 4, 5]
arry.object_id => 280
arry.map! {|num| num**num } => [1, 4, 27, 256, 3125]
arry.map! => #
arry.map! {|n| n } => [1, 4, 27, 256, 3125]
arry.object_id => 280
Como podemos ver, object_id permanece inalterado. Assim, o perigo de utilizar este método parece óbvio. Se no nosso código usámos a variável arry noutro sítio qualquer, então o map! vai alterá-la. Isto pode levar a que o nosso programa funcione de uma forma indesejável ou até mesmo a crashar.
Existem objectos em Rubi que não podem ser alterados, tais como instâncias das classes Integer, Float e Symbol. Ao trabalhar em um projeto, pode também encontrar o chamado comentário mágico que é assim:
frozenstringliteral: verdadeiro
A tentativa de alterar o destinatário da String no código em que esse comentário foi utilizado resultaria num erro como este:
'abc'.upcase!
FrozenError (não é possível modificar uma String congelada)
Curiosamente, havia planos para introduzir uma cadeia de caracteres imutável em Rubi 3.0, mas foi decidido não efetuar esta alteração. No entanto, convém lembrar que nem todos os métodos bang alteram o destinatário, pelo que deve sempre verificar na documentação o tipo de perigo que deve esperar no caso de um determinado método.
Outra caraterística distintiva destes métodos é que, para muitos deles, é levantada uma exceção. Um exemplo de tal método é o ActiveRecord::FinderMethods#first! De acordo com a documentação, o método first! é igual ao primeiro, mas levanta ActiveRecord::RecordNotFound se não for encontrado nenhum registo. Note que first! não aceita argumentos.
Ficheiro activerecord/lib/activerecord/relation/findermethods.rb, linha 128
def first!
first || raiserecordnotfoundexception!
end
No entanto, o método ActiveRecord::FinderMethods#first que é utilizado acima tem o seguinte aspeto:
Ficheiro activerecord/lib/activerecord/relation/findermethods.rb, linha 116
def first(limit = nil)
checkreorderdeprecation unless loaded?
if limit
findnthwithlimit(0, limit)
senão
findnth 0
fim
fim
Graças aos exemplos acima, vemos o perigo de usar o primeiro. Se utilizarmos o ActiveRecord::FinderMethods#find! e este não encontrar um registo adequado na base de dados, então devolverá ActiveRecord::RecordNotFound, o que pode fazer com que o nosso programa deixe de funcionar.
No entanto, devemos recordar que isto não significa que, se um método não tiver um ponto de exclamação no final, é seguro e não levantará a exceção ou alterará o destinatário.
Um novo par de métodos foi introduzido em Ruby on Rails 6.0: ActiveRecord::Persistence::ClassMethods#insert_all e ActiveRecord::Persistence::ClassMethods#insert_all!
O primeiro destes métodos já apresenta um certo grau de perigo. Bem, de acordo com a documentação, inseririnsere vários registos na base de dados numa única instrução SQL INSERT. Não instancia quaisquer modelos nem acciona as chamadas de retorno ou validações do ActiveRecord. No entanto, o comando insertall! levanta adicionalmente ActiveRecord::RecordNotUnique se alguma linha violar um índice único na tabela. Nesse caso, não são inseridas linhas. Isto significa que o primeiro destes métodos guardará todos os registos, exceto aqueles que violam o índice único, enquanto o segundo método (mais perigoso) levantará uma exceção e não guardará nenhum dos registos na base de dados.
Muitos métodos, mesmo que não tenham um ponto de exclamação no final, são perigosos de utilizar. Por exemplo, ActiveRecord::FinderMethods#find. De acordo com a documentação, se um ou mais registos não puderem ser encontrados para os ids solicitados, então ActiveRecord::RecordNotFound será levantado.
Podemos ver que, embora este método tenha o mesmo grau de perigo que ActiveRecord::FinderMethods#first!, não tem um ponto de exclamação.
O mesmo é verdade quando se trata de modificar o destinatário. Por exemplo, Array.delete (como documentado) elimina todos os itens do self que são iguais a object e devolve o último item eliminado, ou nil se não forem encontrados itens correspondentes.
a = [1, 2, 3, 4, 5]
a.object_id #=> 320
a.delete(2) #=> 2
a #=> [1, 3, 4, 5]
a.delete(6) #=> nil
a.object_id #=> 320
É possível ver claramente que o objeto foi modificado. O que os dois métodos têm em comum é o facto de não terem um equivalente em ponto de exclamação. Portanto, se o método que queremos criar tiver o tipo de perigos que mencionei acima, não precisa de ter imediatamente um ponto de exclamação no final. Além disso, é aconselhável criar um método bang se já existir um método com o mesmo nome que seja menos perigoso do que o método que se pretende criar.
Pode perguntar-se porquê utilizar estes métodos perigosos, especialmente porque normalmente temos métodos menos perigosos. Uma das vantagens pode ser, por exemplo, a melhoria do desempenho do código graças à redução do número de objectos criados. Aqui pode ler mais sobre como aumentar o desempenho do Rails.
Quando se trata de levantar excepções, utilizar o método create em vez do perigoso create! pode levar a uma situação em que um erro na nossa aplicação é difícil de detetar, porque os registos não serão escritos na base de dados. Por isso, se tivermos a certeza de que os parâmetros que passamos para este método estão corretos, devemos utilizar o método create! que levantará uma exceção se, por alguma razão, o registo não for guardado na base de dados.
A conclusão é simples e é a seguinte: a utilização prudente de tais métodos pode melhorar o desempenho e a qualidade do nosso código. No entanto, devemos ter sempre presente que a sua utilização incorrecta pode impedir que o código funcione corretamente.
Se quiseres criar o teu próprio método perigoso, tens de passar por um determinado processo de decisão. Em primeiro lugar, a questão é saber se já existe um método com o mesmo nome do método que se pretende criar, mas menos perigoso. Também podes considerar criar um par de métodos em que um deles é equivalente ao outro, mas mais perigoso.
Não faz sentido criar um método bang se a sua contraparte sem um ponto de exclamação não existir. Há métodos que são perigosos porque alteram o objeto ou levantam uma exceção e, no entanto, não têm um ponto de exclamação no fim do nome. Criar um método bang sem equivalente iria confundir um programador que utilizasse o seu código. Esta pessoa não seria capaz de dizer qual é o perigo deste método e porque é que merece um ponto de exclamação no final do seu nome.
Em segundo lugar, devemos considerar de que tipo de perigos estamos a falar. Dos exemplos acima, podemos concluir que o tipo de perigo mais comum é a alteração do próprio objeto (em vez de criar a sua cópia) ou levantar uma exceção. Claro que isto não é uma regra, mas sim um resultado da análise dos métodos que foram definidos em Ruby e Ruby on Carris. Por exemplo, podemos considerar a implementação de um par de métodos em que o método sem o ponto de exclamação guardaria o registo na base de dados, enquanto o método com o ponto de exclamação saltaria a validação deste registo. Neste caso, é claro onde reside o perigo potencial da utilização destes métodos.
Um resumo do conhecimento dos métodos bang aponta para as seguintes conclusões: o 1º método com o ponto de exclamação tem um menos ameaçador sem um ponto de exclamação, em segundo lugar, o método com um ponto de exclamação executa uma ação perigosa, por exemplo, modifica o destinatário ou levanta uma exceção.
Em conclusão, a compreensão do conceito de métodos de pancada em Rubi desenvolvimento de software pode melhorar muito as suas competências de codificação e trazer mais clareza à sua base de código. Métodos Bang, denotados por um ponto de exclamação no final dos seus nomes, indicam uma versão destrutiva ou potencialmente perigosa de um método. Por convenção, o contrapartida de estrondo de um método deve ser usado com cuidado, pois pode modificar objectos diretamente, sem criar uma cópia separada. Isto pode ser particularmente útil quando se lida com objectos mutáveis ou quando a otimização do desempenho é uma preocupação. No entanto, é importante ter cuidado ao utilizar métodos bang, uma vez que podem ter consequências indesejadas se não forem corretamente tratados. Também vale a pena notar que nem todos os métodos têm um versão bange sua presença deve ser avaliada caso a caso. Com o conhecimento de quando e como criar métodos bang, pode utilizar esta poderosa ferramenta de forma eficaz e escrever código limpo e eficiente que satisfaça os seus requisitos específicos.