Блок DSL без аргумента в ruby

Я пишу простой DSL в рубине. Несколько недель назад я наткнулся на сообщение в блоге, в котором показано, как преобразовать код, например:

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

в более чистый код:

some_method argument do
   some_method_on_book
   some_other_method_on_book :with => argument
end

Я не могу вспомнить, как это сделать, и я не уверен в недостатках, но более чистый синтаксис заманчив. Кто-нибудь что-нибудь знает об этой трансформации?


person dhuCerbin    schedule 10.02.2012    source источник
comment
Спасибо за изменение названия! У меня были некоторые проблемы с формулировками.   -  person dhuCerbin    schedule 10.02.2012


Ответы (3)


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

ОБНОВЛЕНИЕ: Однако это опускает книгу, но не позволяет вам использовать аргумент. Чтобы использовать его прозрачно, вы должны как-то транспортировать его. Предлагаю сделать это на самой книге:

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
person Sony Santos    schedule 10.02.2012
comment
Спасибо за обновление. Мне нужно сделать дополнительную настройку с обработкой аргументов, но этот подход приводит к хорошему синтаксису. - person dhuCerbin; 10.02.2012

Взгляните на эту статью http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — есть обзор метода (конкретно изложенный в контексте его минусов и возможного их решения), плюс есть несколько полезных ссылок для дальнейшего чтения.

По сути, речь идет об использовании instance_eval для выполнения блока в желаемом контексте.

Говоря о недостатках этой техники:

Так в чем проблема? Ну, проблема в том, что блоки, как правило, являются замыканиями. И вы ожидаете, что они на самом деле будут полным закрытием. И с того момента, как вы пишете блок, не очевидно, что этот блок не может быть полным замыканием. Вот что происходит, когда вы используете instance_eval: вы сбрасываете себя этого блока во что-то другое - это означает, что блок по-прежнему является замыканием для всех локальных переменных вне блока, но НЕ для вызовов методов. Я даже не знаю, изменился ли постоянный поиск или нет.

Использование instance_eval изменяет правила языка таким образом, что это не очевидно при чтении блока. Вам нужно продумать дополнительный шаг, чтобы точно понять, почему вызов метода, который вы можете лексически видеть вокруг блока, на самом деле не может быть вызван изнутри блока.

person Alexis    schedule 10.02.2012
comment
Спасибо, надо еще поискать минусы. - person dhuCerbin; 10.02.2012

Ознакомьтесь с геммой docile. Он позаботится обо всех острых кромках, что значительно облегчит вам задачу.

person ms-ati    schedule 18.02.2013