2012-02-10 6 views
8

Estoy escribiendo un dsl simple en ruby. Hace unas semanas me encontré con alguna entrada del blog, que muestran cómo transformar un código como:Bloque DSL sin argumento en ruby ​​

some_method argument do |book| 
    book.some_method_on_book 
    book.some_other_method_on_book :with => argument 
end 

en un código más limpio:

some_method argument do 
    some_method_on_book 
    some_other_method_on_book :with => argument 
end 

No puedo recordar cómo hacer esto y no estoy seguro acerca de las desventajas, pero la sintaxis más limpia es tentadora. ¿Alguien tiene una pista sobre esta transformación?

+0

¡Gracias por cambiar el título! Tuve algunos problemas con la redacción. – dhuCerbin

Respuesta

9
def some_method argument, &blk 
    #... 
    book.instance_eval &blk 
    #... 
end 

ACTUALIZACIÓN: Sin embargo, eso omite el libro pero no le permite usar el argumento. Para usarlo de forma transparente, debes transportarlo de alguna manera. Sugiero hacerlo por sí mismo libro:

class Book 
    attr_accessor :argument 
end 

def some_method argument, &blk 
    #... 
    book.argument = argument 
    book.instance_eval &blk 
    #... 
end 

some_method 'argument' do 
    some_method_on_book 
    some_other_method_on_book argument 
end 
+0

Gracias por la actualización. Necesito hacer más personalización con los argumentos de manejo, pero este enfoque resulta en una buena sintaxis. – dhuCerbin

7

Tome un vistazo a este artículo http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation - hay una visión general del método (que se indique específicamente en el contexto de sus desventajas y posible solución a ellos), además de que hay' re varios enlaces útiles para lectura adicional.

Básicamente, se trata de usar instance_eval para ejecutar el bloque en el contexto deseado.

Hablando sobre desventaja de esta técnica:

Entonces, ¿cuál es el problema con eso? Bueno, el problema es que los bloques son generalmente cierres. Y esperas que sean cierres completos. Y no es obvio desde el punto donde se escribe el bloque que ese bloque podría no ser un cierre completo. Eso es lo que sucede cuando usa instance_eval: restablece el auto de ese bloque en algo else - esto significa que el bloque sigue siendo un cierre sobre todas las variables locales fuera del bloque, pero NO para las llamadas a métodos. Ni siquiera sé si se cambia o no la búsqueda constante.

El uso de instance_eval cambia las reglas para el lenguaje de una manera que no es evidente al leer un bloque. Necesita pensar un paso adicional para averiguar exactamente por qué una llamada a un método que puede ver léxicamente alrededor del bloque no se puede llamar desde el interior del bloque.

+0

Gracias, tengo que aprender más sobre los inconvenientes. – dhuCerbin

0

Echa un vistazo a docile gema. Cuida todos los bordes afilados, haciendo que esto sea muy fácil para ti.

Cuestiones relacionadas