Articles

Como Escrever uma Expressão de Caso em Ruby

Posted on

Imagine que precisa de uma forma de verificar o valor de um objecto, e executar uma acção diferente com base nisso. A forma de Programação Orientada para Objectos é utilizar polimorfismo, e veremos como fazê-lo num segundo.

Mas primeiro, vejamos como funciona a expressão case , e como pode utilizá-la para atingir o objectivo acima mencionado.

Como funciona o caso?

Existem duas partes principais da expressão case. A cláusula case, e a cláusula when.

A cláusula when é a expressão que define o receptor do operador (por defeito para ===), e a cláusula case define o argumento que lhe foi transmitido.

Vejamos um exemplo.

case awhen String #..end

Por isso, pode-se pensar no exemplo acima como String === a, ou .

Finalmente, há também uma cláusula else que pode utilizar quando não houver correspondência.

case my_objectwhen String "This is a string"else "I have no idea what this is"end

O operador triplo é igual a (====)

Por defeito, case utiliza o operador triplo é igual a (===) para fazer a comparação.

A coisa com === é que não tem nada a ver com igualdade. Por defeito, é aliado ao duplo operador igual (==) que normalmente verifica se dois objectos têm valor equivalente, mas pode ser definido para significar qualquer coisa.

Por exemplo, um intervalo define-o como um alias para includes?, um regex define-o como um alias para match, uma classe para is_a?, um proc para call. Fica-se com a ideia.

que o operador funciona como esperado com literals, mas não com classes:

1 === 1 # => trueNumeric === Numeric # => false

Isso porque o === é um pseudónimo para kind_of?. E aqui estão os documentos para kind_of?.

kind_of?(class) → true or false

Retorna true se a classe for a classe de obj, ou se a classe for uma das superclasses de obj ou módulos incluídos no obj.

Isto significa que se quiser fazer um case ... when sobre a classe de um objecto, isto não funcionará:

obj = 'Hi'case obj.classwhen String "It's a string"end

Isso porque, traduz-se por String === String. E isso retorna false.

O operador por defeito

O case expressão tem um operador por defeito. E isso significa que não tem de o especificar. Isso é muito bom, porque pode simplesmente escrever when String e por defeito o === operador.

mas, há alturas em que quer utilizar um operador diferente. E a Ruby permite-lhe fazê-lo. Eis como.

casewhen a < 3 "Smaller than 3"end

Caso é uma expressão

Apenas como o nome diz, a coisa toda é uma expressão. Isto significa que se avalia a um valor. Assim, pode atribuir o resultado de toda a expressão case a uma variável, como assim.

value = case when a < 3 "Smaller than 3" end

Não há nenhuma quebra

Se vem de outras línguas, provavelmente usou uma declaração switch ou algo semelhante, e notou que case não usa palavras-chave como break para quebrar o fluxo.

Isso é porque não há queda com case. Apenas devolve o valor da expressão que foi correspondida e pronto.

Múltiplas correspondências

Up até agora, só se utilizou um valor para a cláusula when. Mas pode usar múltiplos valores.

case awhen 1..3 "Small number"end

Matching regexes

P>Pode usar case expressões para corresponder a qualquer coisa. Mas no caso de não ser óbvio, pode também combinar regexes, ou lambdas. Eis um exemplo.

even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end

Definir os seus próprios

Uma dos factos menos conhecidos é que pode definir os seus próprios comparadores.

Text = Struct.new(:min_length) do def ===(string) string.size > min_length && string.is_a?(String) endendcase awhen Text.new(100) "It's text"end

No exemplo acima, se a for uma sequência de mais de 100 caracteres, então a expressão case retornará It's text.

Utilizar polimorfismo em vez disso

Não vou entrar nos benefícios do OOP aqui, pode ler mais sobre isso no artigo Programação Orientada para Objectos com Ruby, mas vou mostrar-lhe como pode usar o polimorfismo para substituir uma expressão case.

A versão case

class Person attr_reader :country def initialize(country) @country = country end def nationality case country when "USA" "This guy is an American" when "Romania" "This guy is a Romanian" end endendjohn = Person.new("USA")puts john.nationality # => This guy is an American

A versão OOP

class Person attr_reader :country def initialize(country) @country = country end def nationality country.nationality endendclass America def nationality "This guy is an American" endendclass Romania def nationality "This guy is a Romanian" endendjohn = Person.new(America.new)puts john.nationality # => This guy is an American

É uma boa ideia apagar tanto código de controlo de fluxo (i.e. ifs, e case expressões) o mais possível. Melhora a adesão ao Princípio da Responsabilidade Única e torna o programa mais legível em geral.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *