Добавляет ли блок Object.send к вызываемому методу?

Я только что завершил Ruby Koans, и ни одно из методов вызова методов, использующих Object.send, и документацию Ruby в методе не предоставляет никакой информации при использовании блоков с методом отправки. Будет ли передан блок, прикрепленный к методу отправки, методу, который он вызывает, или будет потерян блок?

Пример:

foo.send(:a_method) { bar.another_method }

Ответы

Ответ 1

Документация немного неясна:

отправить (символ [, args...]) → obj

Вызывает метод, идентифицированный символом, передавая ему любые указанные аргументы.

Но обратите внимание на любую указанную часть аргументов. Блок, который вы передаете методу, действительно является смешным типом неявного аргумента, так что вы можете делать такие вещи, как:

def m(&b)
    @a.each(&b)
end
m { |e| puts e }

чтобы передать блок как экземпляр Proc. Однако вы также можете это сделать:

def m
    yield
end
m { puts 'pancakes' }

поэтому блок является особым для списка аргументов, но блок все еще ведет себя как аргумент, даже если он иногда неявный.

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

class C
    def m
        yield
    end
end
o = C.new
o.send(:m) { puts 'pancakes' }
# "pancakes" comes out

Ответ 2

Да. Рассмотрим следующее:

class A
  def explicit(&b); b; end
  def implicit; yield "hello"; end
end

>> A.new.send(:explicit) { }
=> #<Proc:[email protected](irb):19>
>> A.new.send(:implicit) { |greeting| puts greeting }
hello
=> nil

Надеюсь, это поможет!

Ответ 3

Да, будет. Внутри метода вы можете проверить его с помощью block_given? и вызвать блок с помощью yield

Код

class Foo
  def bar
    puts "before yield"
    yield if block_given?
    puts "after yield"
  end
end

f = Foo.new
f.send(:bar)
puts ""
f.send(:bar) { puts "yield"}

Выход

before yield
after yield

before yield
yield
after yield