如何在Ruby中动态改变inheritance

我想动态地为Ruby中的类指定父类。 考虑以下代码:

class Agent def self.hook_up(calling_class, desired_parent_class) # Do some magic here end end class Parent def bar puts "bar" end end class Child def foo puts "foo" end Agent.hook_up(self, Parent) end Child.new.bar 

ParentChild类定义都没有指定父类,因此它们都从Objectinheritance。 我的第一个问题是:我需要在Agent.hook_up中做什么才能使Parent成为Child的超类(例如, Child对象可以inheritance’bar’方法)。

我的第二个问题是:我是否需要将第一个参数传递给Agent.hook_up ,或者是否有某种方式hook_up方法可以通过编程方式确定调用它的类?

Joshua已经为您提供了很多替代方案,但是要回答您的问题:在ruby中创建类之后,您无法更改类的超类。 这根本不可能。

也许你正在寻找这个

 Child = Class.new Parent do def foo "foo" end end Child.ancestors # => [Child, Parent, Object, Kernel] Child.new.bar # => "bar" Child.new.foo # => "foo" 

由于parent是Class.new的参数,因此可以将其与其他类交换出来。

在编写某些类型的测试之前,我已经使用过这种技术。 但是我很难找到许多有利于做这件事的好借口。


我怀疑你真正想要的是一个模块。

 class Agent def self.hook_up(calling_class, desired_parent_class) calling_class.send :include , desired_parent_class end end module Parent def bar "bar" end end class Child def foo "foo" end Agent.hook_up(self, Parent) end Child.ancestors # => [Child, Parent, Object, Kernel] Child.new.bar # => "bar" Child.new.foo # => "foo" 

当然,虽然根本不需要代理

 module Parent def bar "bar" end end class Child def foo "foo" end include Parent end Child.ancestors # => [Child, Parent, Object, Kernel] Child.new.bar # => "bar" Child.new.foo # => "foo" 

仅限Ruby 1.9 🙁 1.8类似,但使用RCLASS(自我) – >超级代替)

 require 'inline' class Class inline do |builder| builder.c %{ VALUE set_super(VALUE sup) { RCLASS(self)->ptr->super = sup; return sup; } } builder.c %{ VALUE get_super() { return RCLASS(self)->ptr->super; } } end J = Class.new J.set_super(Class.new) 

正如已经指出的那样,您应该查看模块或动态创建类。 但是,您可以使用evil-ruby来更改超类。 甚至还有一个Ruby 1.9的分支 。 这仅适用于MRI。 应该很容易建立Rubinius(清除方法缓存将是主要问题),没有关于JRuby的线索。 这是代码:

 require 'evil' class Agent def self.hook_up(calling_class, desired_parent_class) calling_class.superclass = desired_parent_class end end class Parent def bar puts "bar" end end class Child def foo puts "foo" end Agent.hook_up(self, Parent) end Child.new.bar 

Ruby的SimpleDelegator类(在委托库中)可能会有所帮助,前提是对象嘎嘎像基类一样,而不是实际上基类的实例

 require 'delegate' class Agent < SimpleDelegator def baz puts "baz" end end class BarParent def bar puts "bar" end end class FooParent def foo puts "foo" end end agent = Agent.new(FooParent.new) agent.baz # => baz agent.foo # => foo agent.__setobj__(BarParent.new) agent.baz # => baz agent.bar # => bar 

看这个

  class MyClass < inherit_orm("Adapter") end 

和类选择器:

  def inherit_orm(model="Activity", orm=nil) orm = Config.orm || orm require "orm/#{orm.to_s}" "ORM::#{orm.to_s.classify}::#{model}".constantize end 

因此,当实例MyClass将根据ormmodel从动态类inheritance。 务必在模块中定义两者。 它在public_activity gem( 选择器示例 )中工作正常。

我希望能帮助......再见!