#4 Metaprogramação: Blocos

12 February 2010

Obs: Esse post assume que você conhece o básico sobre blocos em Ruby. Um código precisa de um ambiente pra ser executado, que pode ser uma variável local, variável de instância, self... O nome dado para essas entidades normalmente é binding. A característica principal dos blocos é que eles contém tanto o código a ser executado quanto os bindings. Vejamos esse exemplo. Um método imprime_cor passando um bloco. Antes disso, uma variável x definida como "Azul". A variável se encontra no mesmo escopo da chamada do método: Qual será a resposta ? Quando você passa um bloco para um método, eles tem um conjunto de bindings diferentes entre si. No escopo do método, a variável x vale "Vermelho". No escopo do bloco a variável x vale "Azul". Não existe algo como sobrescrita aqui! Os escopos são diferentes, o que faz com que o código no método não seja visível ao bloco. Resposta: Azul Essa propriedade é chamada de closure, o importante aqui é que o bloco captura seu conjunto de bindings e leva consigo por onde for. Vamos entender um pouco mais sobre os Escopos (Scopes).
Scopes
De acordo com o escopo atual, voce terá dierentes bindings. O objeto atual que ve os escopos é também conhecido como self. Vamos analisar os bindings em diferentes escopos com a ajuda do método Kernel#local_variables( ). O primeiro escopo, ainda fora da classe é chamado de top-level scope e define a variável v1. Então ele entra no escopo da classe, e o que ocorre ? Sempre que você entra em um novo escopo os bindings anteriores são substituídos por um novo conjunto de bindings, o que significa que quando o programa entra na classe, v1 saiu do escopo e não é mais visível. E quanto ao escopo do método? Enquanto o método não for chamado, seu escopo não existe. Essa análise é mais fácil de ser feita conhecendo as barreiras dos escopos (Scope Gates).
Scope Gates
Existem 3 lugares que Ruby deixa o escopo anterior e cria um novo:
  • Classes (class)
  • Módulos (module)
  • Métodos (def)
A diferença sutil está entre classes/modulos e métodos. Códigos em classes e módulos são executados imediatamente enquanto códigos em métodos são executados eventualmente de acordo com a chamada a eles.
Flattening the Scope
Existe um maneira de "burlar" e passar pelas barreiras dos escopos, vejamos o código abaixo: O problema é que a cada vez que você entra em um novo escopo, as variáveis antigas somem do escopo anterior...então como passar a variável ? A primeira barreira é a class. Quando a classe aparece um novo escopo é criado. Porém.. se a chamada a classe fosse através de um metodo ela estaria no mesmo escopo. Você pode capturar a variável e passar esse closure ao método. Como? Criar uma classe é o mesmo que chamar seu método new! A mesma estratégia pode ser utilizada com o método, também passando o clousure: Essa estratégia é também conhecida como nested lexical scopes, flattening the scope, ou apenas Flat Scope. Continua Próximo post - Procs, lambdas e &
comments powered by Disqus