1

I have an AR object called Run that keeps information of when the run was started, ended, disabled, etc. I am trying to create a class Something and want to make it "runnable". So I created a module called Runnable that takes in a run object on initialization. Now say I mix in this module into a class Something. I want the something object to delegate all the methods defined on run to the run object.

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

Now if I do:

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

Any idea what I am missing? Is there a better way of doing what I am trying to do?

3 Answers 3

1

You have two mistakes:

  • method_missing needs to be an instance method, not a class method
  • @run.send(name, args) should be @run.send(name, *args). The former results in ArgumentError: wrong number of arguments (given 1, expected 0) when Run#start_date is executed.

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"
Sign up to request clarification or add additional context in comments.

Comments

1

It seems to me a SimpleDelegator would achieve what you are looking for here.

3 Comments

I thought about that but I can't use that in modules, can I?
Not sure why you want a module here though. You define initialize in it, it seems that this will not be a very flexible module. Why not using inheritance and do class Something < Runnable ?
Because I have only one shot at inheriting from a class. Once my Something class inherits from Runnable, it cannot inherit from anything else.
0

Using Forwardable for now

module Runnable
  extend Forwardable
  def_delegator :@run, :start_date, :end_date

  def initialize(run)
    @run = run
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.