Какова цель методов bind / unbind в Ruby?
какова цель иметь Method#unbind
и UnboundMethod#bind
?
из того, что я собираю, методы являются вызываемыми объектами, такими как procs и lambdas, за исключением того, что методы привязаны к области их приемника:
class SomeClass
def a_method; puts "from SomeClass"; end
end
s = SomeClass.new
s.a_method # => "from SomeClass"
я могу назвать a_method
если я нахожусь в контексте SomeClass
или если у меня есть объект SomeClass
. Я могу сделать его вызываемым объектом, извлекая метод как Method
объект, но он все еще привязан к объекту класса SomeClass
в этом примере:
m = s.method :a_method
m.class # => Method
m.owner # => SomeClass
m.call # => "from SomeClass"
почему я должен хотеть unbind
метод из его приемника? Может быть, я могу передать это или bind
это другой объект, дающий ему новый контекст, возможно, я могу иметь совершенно другой объект, вызывающий этот метод без наследования, но я ничего не могу с ним сделать, если я не свяжу его с объектом его исходного класса или не преобразую его в Proc
объект (действительно лямбда, так как методы и лямбда несколько похожи):
# Module#instance_method gives me an UnboundMethod
ub = SomeClass.instance_method :a_method
ub.class # -> UnboundMethod
# now I can't make any calls
ub.call # -> NoMethod Error, undefined method 'call'
class AnotherClass; end
a = AnotherClass.new
b = ub.bind(a) # -> TypeError: bind argument must be an instance of SomeClass
b = ub.bind(SomeClass.new).call # -> "from SomeClass"
я мог бы преобразовать объект метода в proc и, возможно, что-то с ним сделать:
AnotherClass.class_eval do
# I can access m becausec this block is evaluated in the same
# scope it's defined, so I can grab m ;)
define_method(:method_from_some_class, m.to_proc)
end
AnotherClass.instance_methods(false) # -> [:method_from_some_class]
a.method_from_some_class # -> "from SomeClass"
какова цель этого? Каковы реальные приложения для чего-то подобного?
1 ответов
это действительно полезно для метапрограммирования. Предположим, вы хотите знать местоположение исходного кода для SomeClass#method
. Если вы можете создать экземпляр SomeClass
, то вы можете создать (связанный) экземпляр метода на этом SomeClass
экземпляр, на котором можно вызвать различные методы для исследования некоторых метаданных метода. Но что делать, если вы не знали сигнатуру метода SomeClass#new
, или был назван иначе, чем SomeClass#new
? Просто безопасное создание экземпляра из SomeClass
может быть сложно. Вот где unbound метод пригодится. Не беспокоясь о конкретном экземпляре класса или о том, как создать экземпляр, вы можете просто сделать SomeClass.instance_method(:a_method)
(который является несвязанным методом), затем вызовите source_location
на нем, чтобы исследовать местоположение определения.
и когда такой вид метапрограммирования будет необходим в реальных приложениях? Одним из примеров является создание среды IDE с функциями для поиска метода.