20 de abril de 2010

Quando os operadores .. e ... são usados em condicionais eles não criam objetos Range, mas sim, criam um tipo especial de expressão Boolean: flip-flop. Tanto o operador da esquerda, quanto o da direita devem ser expressões Boolean. Como é de se esperar um flip-flop retorna true ou false, mas esse valor depende da iteração anterior, assim, uma expressão flip-flop armazena um estado.

Funcionamento de uma expressão flip-flop

Vamos a um exemplo:

(1..10).each {|x| print x if x==3..x==5 }

Aqui, a flip-flop consiste nas duas condições (x==3 e x==5) ligadas pelo operador .. na condicional if no final.

A expressão é false até que a expressão da esquerda se torne true, então a expressão dá um “flip” e mantém o estado true. Ela se mantém true (e retorna sempre true) até que a expressão da direita se torne true, assim a expressão dá um “flop” para um estado false até que a esquerda se torne true novamente e sucessivamente.

Com isso em mente, o exemplo acima imprime: 345

Uma flip-flop pode ser escrito tanto com .. quanto com ...: quando uma flip-flop .. torna-se true, ele retorna true e também testa logo em seguida a expressão da direita para ver se deve mudar o estado para false. Já uma flip-flop ... espera pela próxima iteração antes de testar a expressão da direita.
Exemplo:

# Imprime "3". Flip e flop de volta quando x==3
(1..10).each {|x| print x if x==3..x>=3 }
# Imprime "34". Flip quando x == 3 e flop quando x==4
(1..10).each {|x| print x if x==3...x>=3 } # Imprime "34"

Mapa mental

Ruby Flip-Flops

Clique para ampliar

Exemplo prático

O próprio Matz desencoraja o uso de flip-flops (Matz, p. 110), porém podem ser úteis em alguns casos de leitura de arquivos e sources, como o exemplo a seguir (fonte):

code = <<-CODE
  /**
   * Some comments
   * longer comments here that we can parse.
   *
   * Wahoo
   */
   function subroutine() {

   }

   /* some more comments */

   /**
    * Another comment.
    */
    function something() {

    }
CODE

comments = code.collect { |line| line if (line =~ /^[\s]*\/\*/)..(line =~ /^[\s]*\*\//) }.join
puts comments

# Retorna
  /**
   * Some comments
   * longer comments here that we can parse.
   *
   * Wahoo
   */

   /* some more comments */

   /**
    * Another comment.
    */

Referências


Deixe uma resposta

Nome Obrigatório:

Email Obrigatório:

Website

Comentário Obrigatório:

RSS
Livros de Ruby e Rails no Submarino Livros de Ruby e Rails na Amazon