views:

182

answers:

1

Let's say I have a singleton class like this:

class Settings
  include Singleton

  def timeout
    # lazy-load timeout from config file, or whatever
  end
end

Now if I want to know what timeout to use I need to write something like:

Settings.instance.timeout

but I'd rather shorten that to

Settings.timeout

One obvious way to make this work would be to modify the implementation of Settings to:

class Settings
  include Singleton

  def self.timeout
    instance.timeout
  end

  def timeout
    # lazy-load timeout from config file, or whatever
  end
end

That works, but it would be rather tedious to manually write out a class method for each instance method. This is ruby, there must be a clever-clever dynamic way to do this.

+3  A: 

One way to do it is like this:

require 'singleton'
class Settings
  include Singleton

  # All instance methods will be added as class methods
  def self.method_added(name) 
     instance_eval %Q{
       def #{name}
         instance.send '#{name}'
       end
     }
  end 


  def timeout
    # lazy-load timeout from config file, or whatever
  end
end

Settings.instance.timeout
Settings.timeout

If you want more fine grained control on which methods to delegate, then you can use delegation techniques:

require 'singleton'
require 'forwardable'
class Settings
  include Singleton
  extend SingleForwardable

  # More fine grained control on specifying what methods exactly 
  # to be class methods
  def_delegators :instance,:timeout,:foo#, other methods

  def timeout
    # lazy-load timeout from config file, or whatever
  end

  def foo
    # some other stuff
  end

end

Settings.timeout

Settings.foo

On the other side, I recommend using modules if the intended functionality is limited to behavior, such a solution would be:

module Settings
  extend self 

  def timeout
    # lazy-load timeout from config file, or whatever
  end

end

Settings.timeout
khelll
Awesome answer. In my particular case SingleForwardable is exactly what I was looking for. Thanks!
Pete Hodgson