Я пытаюсь создать немного взлома Ruby для создания чего-то как реверс взлома Symbol#to_proc. Принимая во внимание, что взлом Symbol#to_proc делает это возможным:
some_array.each(&:some_method)
совпадает с
some_array.each { |obj| obj.some_method }
Я хочу сделать это возможным:
some_array.each(&[:some_method])
совпал бы с
some_array.each { |obj| some_method(obj) }
Проблема состоит в том, что, если some_method не является методом ядра, что это действительно означало бы:
some_array.each { |obj| self.some_method(obj) }
Когда блок передается явно, он создается в рамках привязки, где эта строка записана, таким образом, сам правильно получает доступ к текущему объекту, и все хорошо работает. Однако, если блок создается в to_proc методе Массива, сам в рамках привязки Массива (и относится к самому массиву). Возможно, не возможно сделать то, что я пытаюсь сделать, но я любил бы некоторые идеи от сообщества.
Вот мой взлом до сих пор. Это работает, пока метод является методом ядра и доступен в Массиве:
class Array
def to_proc
lambda {|i| send(self.first, i)}
end
end
С этим взломом работает эта строка, и помещает эти три символа:
[:foo, :bar, :bas].each(&[:puts])
Это уже полезно для меня, потому что часто я желаю для осмотра массива объектов ActiveRecord в консоли, и это сохраняет меня от ввода {|i |, помещает меня}. Но было бы еще более полезно смочь использовать его в объектах так, чтобы некоторый метод в объекте назвали с каждым объектом в массиве, переданном в качестве параметра.
Так какая-либо идея, как заставить обязательную проблему работать?
Не делайте обоих отвечаний, "Вы не хотите делать это, потому что оно сделает вещи выполненными медленнее" или "Вы не сохраняете столько ввода символов, но оно делает код менее читаемым" - я уже знаю эти вещи.:) Это - больше питания моего вида любопытства взлома. Просто удивление, если это возможно.
Вы ищете метод с именем метод
:)
class Example
def some(arg)
p arg.size # just as a demo
end
end
obj = Example.new
%w{the quick brown fox jumps over the lazy dog}.each(&obj.method(:some))
yield
3
5
5
3
5
4
3
4
3
Хотя у Адриана есть правильная идея с использованием метода
, вы можете упростить это еще на один шаг:
# Works on any generic method
%w{the quick brown fox jumps over the lazy dog}.each(&method(:foo))
def foo(arg)
p arg.size
end
# Works on user-defined methods, too
%w{the quick brown fox jumps over the lazy dog}.each(&method(:puts))
Вместо того, чтобы делать неловкую семантику с введением Array#to_proc, почему бы просто не написать свои собственные методы Enumerable, которые сделают вашу жизнь легче вместо этого? Возможно, что-то вроде этого:
module Enumerable
def pass_each(method_name)
each(&method(method_name.to_sym))
end
end
%w{the quick brown fox jumps over the lazy dog}.pass_each(:puts)
Вот еще один способ сделать это без использования метода ()
:). Он использует блок для захвата привязки и затем вызывает соответствующий метод на self
.
class Object
def apply &block
b = eval('self', block.binding)
lambda { |param| b.send block.call, param }
end
end
# use like this:
[1, 2, 3, 4].each &apply { :puts }
output: 1
2
3
4