rubyclass-methodinstance-method

Delegating instance methods to the class method


In Ruby, suppose I have a class Foo to allow me to catalogue my large collection of Foos. It's a fundamental law of nature that all Foos are green and spherical, so I have defined class methods as follows:

class Foo
  def self.colour
    "green"
  end

  def self.is_spherical?
    true
  end
end

This lets me do

Foo.colour # "green"

but not

my_foo = Foo.new
my_foo.colour # Error!

despite the fact that my_foo is plainly green.

Obviously, I could define an instance method colour which calls self.class.colour, but that gets unwieldy if I have many such fundamental characteristics.

I can also presumably do it by defining method_missing to try the class for any missing methods, but I'm unclear whether this is something I should be doing or an ugly hack, or how to do it safely (especially as I'm actually under ActiveRecord in Rails, which I understand does some Clever Fun Stuff with method_missing).

What would you recommend?


Solution

  • You could define a passthrough facility:

    module Passthrough
      def passthrough(*methods)
        methods.each do |method|
          ## make sure the argument is the right type.
          raise ArgumentError if ! method.is_a?(Symbol)
          method_str = method.to_s
          self.class_eval("def #{method_str}(*args) ; self.class.#{method_str}(*args) ; end")
        end
      end
    end
    
    class Foo
      extend Passthrough
    
      def self::colour ; "green" ; end
      def self::is_spherical? ; true ; end
      passthrough :colour, :is_spherical?
    end
    
    f = Foo.new
    puts(f.colour)
    puts(Foo.colour)
    

    I don't generally like using eval, but it should be pretty safe, here.