Подтвердить что ты не робот

Использование урожая внутри define_method в Ruby

Можно ли сделать ключевое слово yield внутри блока, заданного для define_method? Простой пример:

class Test
  define_method :test do |&b|
    puts b    # => #<Proc:...>
    yield
  end
end

Test.new.test {
  puts "Hi!"
}

Этот код вызывает следующую ошибку в Ruby 1.8.7 и 1.9.0:

test.rb: 4: в `test ': никакого блока (LocalJumpError)     от test.rb: 8

Странная вещь - это b блочная переменная != nil, но block_given? возвращает false. Является ли намеренное поведение Ruby не распознавать блоки объектами Proc?

Изменить: Относится к Beerlington. Ответ: b.call() - это не то, что я ищу. Блочная переменная использовалась только для указания того, что блок действительно задан и не обнаружен внутри define_method.

Причина, по которой мне нужно использовать yield вместо block.call

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

Таким образом, подобную семантику нельзя принимать во внимание, поскольку это заставляет пользователей моей библиотеки использовать только один правильный способ передать блок. Это нарушает правило TIMTOWTDI и не делает мою библиотеку прозрачной.

Пример реальной жизни

Код ниже может быть упрощен для кода выше, поскольку my_def использует define_method:

require 'my_library'

class Test
  # client can write 'my_def' instead of 'def' since
  # my_library extends Class class
  my_def :test, "some parameter" do
    yield        # oh no, error :(
  end
end

Test.new.test {
  puts "Hi!"
}
4b9b3361

Ответ 2

Вы не можете использовать yield внутри блока define_method. Это связано с тем, что блоки захватываются затворами, наблюдайте:

def hello
  define_singleton_method(:bye) { yield }
end

hello { puts "hello!" }

bye {  puts "bye!" } #=> "hello!"

Я не думаю, что ваши пользователи будут не в состоянии использовать "доходность" в том, как вы заявляете ---- синтаксис не похож на обычный синтаксис определения метода Ruby, поэтому вряд ли будет какая-то путаница.

Дополнительная информация о том, почему вы не можете передавать блоки неявно в найденные здесь методы: http://banisterfiend.wordpress.com/2010/11/06/behavior-of-yield-in-define_method/