Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Ruby中动态改变继承_Ruby_Metaprogramming - Fatal编程技术网

如何在Ruby中动态改变继承

如何在Ruby中动态改变继承,ruby,metaprogramming,Ruby,Metaprogramming,我想为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

我想为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
父类定义和子类定义都没有指定父类,因此它们都从对象继承。我的第一个问题是:我需要在
Agent.hook\u
中做什么才能使
Parent
成为
Child
的超类(例如
Child
对象可以继承'bar'方法)


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

也许您正在寻找这一点

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"

Joshua已经给了您一个很好的备选方案列表,但是为了回答您的问题:在ruby中创建类之后,您不能更改类的超类。这根本不可能。

正如前面指出的,您可能应该研究模块或动态创建类。但是,可以使用更改超类。甚至还有一个可用的。这只适用于核磁共振成像。应该很容易在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
仅Ruby1.9:(1.8类似,但使用RCLASS(self)->super)

Ruby的类(在库中)可能会有所帮助,只要对象像基类一样嘎嘎作响,而不是实际上是基类的实例就足够了

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
需要“委托”
类代理baz
agent.foo#=>foo
代理。\uuuu setobj\uuuuu(BarParent.new)
agent.baz#=>baz
agent.bar#=>bar
看看这个

  class MyClass < inherit_orm("Adapter")
  end
因此,当instance
MyClass
时,它将根据
orm
model
从动态类继承。 请确保在模块中同时定义这两个选项。它在gem()中运行良好


我希望能帮上忙。。再见

我知道这个问题很老了,已经有了一些很好的答案。然而,我仍然错过了某种解决方案

如果您的目的不是动态分配超类,而是创建一个钩子来执行继承()上的一些代码。有一种内置的方法可以做到这一点

继承(子类) 每当创建当前类的子类时调用回调

例如:

class Foo
  def self.inherited(subclass)
    puts "New subclass: #{subclass}"
  end
end

class Bar < Foo
end

class Baz < Bar
end
见:


如果您打算动态创建类,我建议您查看。

Um,如果您要动态设置或更改类的父级,那么可以合理地断言您的对象模型没有反映真正的is-a关系。一个更合适的解决方案可能是组合。你应该弄清楚这是否是一个思维练习,或者为什么你想在实践中使用它。动态反射语言并不意味着动态更改继承是干净的。伟大的(表达)力量带来了巨大的责任:)@cletus我一般不太喜欢继承,但对于我目前所关注的问题,继承和is-a关系完美地描述了这种关系。唯一的问题是,一个对象在运行时之前不知道它是什么。我猜在生产代码中使用“邪恶”可能会受到反对:-)动态创建一个类可能是我最终使用的解决方案。谢谢谢谢你,约书亚。由于我似乎无法在运行时更改继承链,因此我可能会在解决方案中使用您的第一个选项的一些变体。我很感激你花了这么多时间来回应。如果这真的是你想做的,你可以看看Ryan Davis写的《改变课堂》。这是他在5:00介绍代码的视频,这是该项目的主页。注意免责声明“是的,这很危险……如果您的计算机点火,请不要向我哭诉。”@Borromakot挑战状态?@Borromakot,除非您覆盖了它们的内存位置:)
  def inherit_orm(model="Activity", orm=nil)
    orm = Config.orm || orm
    require "orm/#{orm.to_s}"
    "ORM::#{orm.to_s.classify}::#{model}".constantize
  end
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