【问题标题】:Ruby module that delegates methods to an object将方法委托给对象的 Ruby 模块
【发布时间】:2018-04-07 21:29:01
【问题描述】:

我有一个名为 Run 的 AR 对象,它保存运行开始、结束、禁用等时间的信息。我正在尝试创建一个类 Something 并希望使其“可运行”。所以我创建了一个名为Runnable 的模块,它在初始化时接收一个运行对象。现在说我把这个模块混入一个类Something。我希望 something 对象将 run 上定义的所有方法委托给 run 对象。

module Runnable
  def initialize(run)
    @run = run
  end

  def self.method_missing(name, *args)
    super unless @run.respond_to?(name)
    @run.send(name, args)
  end
end

class Something
  include Runnable
end

现在如果我这样做:

run = Run.find(123)
run.start_date # works!
something = Something.new(run)
something.start_date # NoMethodError: undefined method `start_date' for #<Something:0x007fb4a276b0c0>

知道我错过了什么吗?有没有更好的方法来做我想做的事情?

【问题讨论】:

    标签: ruby-on-rails ruby rails-activerecord metaprogramming


    【解决方案1】:

    你有两个错误:

    • method_missing 需要是实例方法,而不是类方法
    • @run.send(name, args) 应该是 @run.send(name, *args)。前者在执行Run#start_date 时会产生ArgumentError: wrong number of arguments (given 1, expected 0)

    class Run
      def start_date
        "Any time now"
      end
    end
    
    module Runnable
      def initialize(run)
        @run = run
      end
    
      def method_missing(name, *args)
        super unless @run.respond_to?(name)
        @run.send(name, *args)
      end
    end
    
    class Something
      include Runnable
    end
    
    run = Run.new
    run.start_date
      #=> "Any time now"
    something = Something.new(run)
      #=> #<Something:0x00000002642100 @run=#<Run:0x0000000266d558>>
    something.start_date 
      #=> "Any time now"
    

    【讨论】:

      【解决方案2】:

      在我看来,SimpleDelegator 可以实现您在此处寻找的内容。

      【讨论】:

      • 我想过,但我不能在模块中使用它,可以吗?
      • 不知道为什么你想要一个模块在这里。你在里面定义了initialize,看来这不会是一个很灵活的模块。为什么不使用继承并做class Something &lt; Runnable
      • 因为我只有一次机会从一个类继承。一旦我的Something 类从Runnable 继承,它就不能从其他任何东西继承。
      【解决方案3】:

      暂时使用Forwardable

      module Runnable
        extend Forwardable
        def_delegator :@run, :start_date, :end_date
      
        def initialize(run)
          @run = run
        end
      end
      

      【讨论】:

        猜你喜欢
        • 2013-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多