Какова цель методов 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 с функциями для поиска метода.