Как определить метод, похожий на «yield» (я имею в виду, автоматически перехватывать блок)? - PullRequest
1 голос
/ 09 августа 2010

Если мне нужно определить метод с именем 'yields', который будет вызывать yiled 3 раза:


def yields
  3.times do
    yield
  end
end

И затем я буду использовать его в другом методе:


def call_me_3_times
  yields
end

В консоли или IRB:


>> call_me_3_times { puts 'me'} # => Cause error
=>  LocalJumpError: no block given (yield)
 from (irb):32:in `yields'
    from (irb):35:in `call_me_3_times'

Я надеюсь, вы можете прочитать, что я хочу;
И как сделать'yields' автоматически захватывает данный блок?


Я имею в виду, что когда мы используем 'yields', нам не нужно передавать ему '& block', точно так же, как использование 'yield'( нам даже не нужно передавать '& block' в 'yield', не так ли? ).



Ответы [ 4 ]

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

Что-то вроде:

def call_me_3_times &block
  yields &block
end
2 голосов
/ 09 августа 2010

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

Я попытался с block_given, и, глядя на реализацию из ruby ​​core rdocs , я обнаружил, что block_given? реализован так:

rb_f_block_given_p()
{
  if (ruby_frame->prev && ruby_frame->prev->iter == ITER_CUR && ruby_block)
    return Qtrue;
  return Qfalse;
}

Как видите, это C, так что это слишком низкоуровневая реализация. Мы не можем сделать то же самое.

Если block_given? методы должны полагаться на реализацию C, чтобы просто проверить, что блок передан, я не вижу, как мы можем получить этот блок и вызвать его в коде ruby.

Так что я думаю, что нет способа делать то, что вы хотите.

1 голос
/ 10 августа 2010

Решение этой проблемы может быть создано с использованием методов, описанных в этом сообщении в блоге http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html

def call_me_three_times
  yields &(Proc.new) if block_given?
end

Когда вы определяете метод как def some_method(&block) ruby ​​будет ожидать, что вы передадите блок методу,Он преобразует этот блок в Proc и сохраняет его в переменной блока.

Если вы добавите объект Proc к префиксу &, он преобразует его в блок.

Если вы вызываете Proc.new в методе и не предоставляете ему блок, он создает Proc из переданного ему блока.

Некоторые результаты теста ниже

def yields
  puts "Tripling"
  3.times do 
    yield 
  end
end

def call_me_three_times 
  yields &(Proc.new) if block_given?
end

x="Foo"
call_me_three_times { puts x }
x="Bar"
call_me_three_times { puts x }
call_me_three_times

Выход

Tripling
Foo
Foo
Foo
Tripling
Bar
Bar
Bar
1 голос
/ 09 августа 2010

Вам нужен блок, чтобы получить метод доходности или избегать доходности, если нет блока

нет выхода, если нет блока:

def yields
  3.times do
    yield if block_given?
  end
end

Передайте блок вашим методам доходности

def call_me_3_times
  yields { puts 'hello' }
end
...