我想在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
Parent
和Child
类定义都没有指定父类,所以它们都从Object继承。我的第一个问题是:我需要在Agent.hook_up
中做些什么才能使Parent
成为Child
的超类(因此例如Child
个对象可以继承'bar'法)。
我的第二个问题是:我需要将第一个参数传递给Agent.hook_up
,还是某种方式hook_up
方法可以通过编程方式确定它的类被称为?
答案 0 :(得分:23)
也许你正在寻找这个
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"
答案 1 :(得分:6)
Joshua已经为您提供了很多替代方案,但是要回答您的问题:在ruby中创建类之后,您无法更改类的超类。这根本不可能。
答案 2 :(得分:4)
仅限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)
答案 3 :(得分:3)
正如已经指出的那样,您应该查看模块或动态创建类。但是,您可以使用evil-ruby来更改超类。甚至还有fork for 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
答案 4 :(得分:0)
Ruby的SimpleDelegator类(在delegate库中)可能会有所帮助,前提是对象嘎嘎像基类,而不是实际 基类的实例。
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
答案 5 :(得分:0)
看看这个
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
将根据orm
和model
从动态类继承。
务必在模块中定义两者。它在public_activity gem(selector example)中运行良好。
我希望能帮助......再见!
答案 6 :(得分:0)
我知道这个问题已经很老了,已经有了一些很好的答案。但是我仍然想办法解决。
如果您不是要动态分配超类,而是要创建一个挂钩来执行有关继承的某些代码(XY Problem)。有内置的方法可以做到这一点。
继承(子类)
在创建当前类的子类时调用回调。
示例:
class Foo def self.inherited(subclass) puts "New subclass: #{subclass}" end end class Bar < Foo end class Baz < Bar end
产生:
New subclass: Bar New subclass: Baz
请参阅:Class#inherited
如果您打算动态创建类,则建议查看the answer of Joshua Cheek。