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

Пиша прост dsl в ruby. Преди няколко седмици попаднах на публикация в блог, която показва как да трансформирам код като:

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

Разгледайте покорния скъпоценен камък. Той се грижи за всички остри ръбове, което прави това много лесно за вас.

person ms-ati    schedule 18.02.2013