代码之家  ›  专栏  ›  技术社区  ›  Grant McLean

如何在Ruby中动态改变继承

  •  10
  • Grant McLean  · 技术社区  · 16 年前

    我想为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 Agent.hook_up 为了使 起源 超类 孩子 (例如 孩子

    我的第二个问题是:我知道吗 把第一个论点传给 hook_up 方法是否可以通过编程方式确定从中调用它的类?

    7 回复  |  直到 16 年前
        1
  •  6
  •   sepp2k    16 年前

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

        2
  •  24
  •   Joshua Cheek    16 年前

    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"
    
        3
  •  4
  •   horseyguy    16 年前

    仅Ruby1.9:(1.8类似,但使用RCLASS(self)—>(改为超级)

    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)
    
        4
  •  3
  •   Konstantin Haase    16 年前

    如前所述,您可能应该研究模块或动态创建类。但是,您可以使用 evil-ruby 更改超类。甚至还有一个 fork for Ruby 1.9 可用。这只适用于核磁共振成像。在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
    
        5
  •  0
  •   Wayne Conrad    11 年前

    鲁比的 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
    
        6
  •  0
  •   CristianOrellanaBak    11 年前

    看看这个

      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 宝石( selector example ).

    我希望能帮上忙。。再见!

        7
  •  0
  •   3limin4t0r    7 年前

    如果您的目的不是动态地分配超类,而是创建一个钩子来执行继承上的一些代码( 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 .