ruby类扩展

ruby类扩展,ruby,metaprogramming,Ruby,Metaprogramming,我想用ruby编写一个方法,它接受一个具有特定方法的类,并通过添加方法或更改现有方法的工作方式来修改其行为。我希望这样做的方式不会修改基类,所以基本上我想要一个函数,它接受一个类并返回一个新修改的类,而不会损害初始类。我很确定这是可能的,但我不确定从哪里开始。我建议使用或;在我看来,使用mixin将是一个更明智的想法,尽管对新手来说使用继承更容易 请记住,您始终可以从类继承并根据需要更改行为或使用新代码包装它 class Mammal def speak "..." end en

我想用ruby编写一个方法,它接受一个具有特定方法的类,并通过添加方法或更改现有方法的工作方式来修改其行为。我希望这样做的方式不会修改基类,所以基本上我想要一个函数,它接受一个类并返回一个新修改的类,而不会损害初始类。我很确定这是可能的,但我不确定从哪里开始。

我建议使用或;在我看来,使用mixin将是一个更明智的想法,尽管对新手来说使用继承更容易

请记住,您始终可以从类继承并根据需要更改行为或使用新代码包装它

class Mammal
  def speak
    "..."
  end
end

class Cat < Mammal
  def speak
    "meow"
  end
end

class Lion < Cat
  def speak
    "get ready for a big " + super + "!"
  end
end

module Asexual_Critter
  def reproduce(critter_list)
    puts "*poink!*"
    critter_list << self.clone
  end
end

class Mutated_Kitty < Cat
  include Asexual_Critter # inane example I know, but functional...
end

否则,您将等待很长时间,直到RAM耗尽,或者SEGFULT耗尽。

您有两个选择:

您可以使用x=Class.newParent{def meth;puts hello;super;puts bye;end}动态定义一个类并重写方法&定义新的方法 你可以使用委托人 例如,如果您想动态创建记录某些方法调用的类:

class Class
  def logging_subclass(*methods)
    Class.new(self) do
      methods.each do |method|
        define_method(method) do |*args,&blk|
          puts "calling #{method}"
          ret = super(*args,&blk)
          puts "#{method} returned #{ret.inspect}"
          ret
        end
      end
    end
  end
end

class One
  def foo
    "I'm foo!"
  end
end

# this prints nothing
One.new.foo #=> returns :foo

# this prints:
#   > calling foo
#   > foo returned "I'm foo!"
One.logging_subclass(:foo).new.foo #=> returns :foo

请注意,您需要ruby 1.9来支持捕获块参数中的do |&blk |捕获块。

您不能从超级调用中完全删除参数列表吗?Super应该使用与当前方法相同的参数,除非您为它提供其他参数。但是Class.new听起来正是David在寻找的东西。您可以在普通定义中,但不能在define_方法中,这是一个运行时错误:不支持从define_方法定义的方法传递super的隐式参数。明确指定所有参数。如果davidk01总是重新定义相同的方法,则正常的定义方法。。。结束语法将起作用。
class Class
  def logging_subclass(*methods)
    Class.new(self) do
      methods.each do |method|
        define_method(method) do |*args,&blk|
          puts "calling #{method}"
          ret = super(*args,&blk)
          puts "#{method} returned #{ret.inspect}"
          ret
        end
      end
    end
  end
end

class One
  def foo
    "I'm foo!"
  end
end

# this prints nothing
One.new.foo #=> returns :foo

# this prints:
#   > calling foo
#   > foo returned "I'm foo!"
One.logging_subclass(:foo).new.foo #=> returns :foo