Как обеспечить методы класса / объекта в блоке в Ruby? - PullRequest
2 голосов
/ 08 августа 2010

Иногда вы можете увидеть:

do_this do
   available_method1 "arg1"
   available_method2 "arg1"
end

Когда я использую блок из метода do_this, я получаю несколько методов, которые можно использовать внутри этого блока.

Интересно, как это сделать?Как выглядит код за кулисами?

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

Ответы [ 2 ]

4 голосов
/ 08 августа 2010

Он называется домен-специфическим языком (DSL). Вот (последняя заархивированная версия) отличная информация о различных формах блоков Ruby DSL.

Существует два способа сделать это с разными синтаксисами:

do_thing do |thing| # with a block parameter
  thing.foo :bar
  thing.baz :wibble
end

# versus

do_thing do # with block-specific methods
  foo :bar
  baz :wibble
end

Первый более явный и менее вероятный сбой, а второй более краткий.

Первый может быть реализован так, просто передавая новый экземпляр как блокпараметр с yield:

class MyThing
  def self.create
    yield new
  end

  def foo(stuff)
    puts "doing foo with #{stuff}"
  end
end

MyThing.create do |thing|
  thing.foo :bar
end

И второй, который запускает блок в контексте нового объекта, предоставляя ему доступ к self, переменным экземпляра и методам:

class MyThing
  def self.create(&block)
    new.instance_eval &block
  end

  def foo(stuff)
    puts "doing foo with #{stuff}"
  end
end

MyThing.create do
  foo :bar
end

И если вы действительно хотите сделать это без звонка MyThing.create, просто:

def create_thing(&block)
  MyThing.create &block
end
2 голосов
/ 08 августа 2010

Обычно это делается с помощью instance_eval для изменения значения self внутри блока на какой-то другой объект, который затем обрабатывает эти вызовы методов.

В качестве быстрого примера:

class ExampleReceiver
  def available_method1 arg ; p [:available_method1, arg] ; end
  def available_method2 arg ; p [:available_method2, arg] ; end
end
def do_this(&blk) ; ExampleReceiver.new.instance_eval(&blk) ; end

do_this do
  available_method1 "arg1" #=> [:available_method1, "arg1"]
  available_method2 "arg1" #=> [:available_method2, "arg1"]
end

Несмотря на то, что это мощная языковая функция, и до этого она использовалась с большим эффектом, по-прежнему ведутся споры о том, хорошая это идея или нет.Если вы не знаете, что происходит, вы можете быть удивлены тем, что значение @some_instance_variable изменяется внутри и снаружи блока, поскольку оно относительно текущего значения self.

См. Отличная статья Даниэля Азумы для подробностей и подробностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...