2

I like Ruby's singleton but I would like to make usage of it better so here is example

require 'singleton'

class Foo
  include Singleton

  def initialize
    # code to setup singleton here 
  end

  def self.get_bar
    Foo.instance.get_bar
  end

  def get_bar
  end

  def get_nar
  end
end

Usage

Foo.instance.get_bar (default) or Foo.get_bar (due to static self.get_bar method I made)

Is there elegant way to make all methods accessible without me having to write static wrapper for each method? Just seems redundant to have to write for each method .instance

UPDATE

Ruby 1.8.7

7
  • Do you actually need to use the Singleton module? Foo is already a singleton and you can just do Foo.get_bar. Commented Sep 6, 2012 at 12:13
  • This is just example. I have Configuration singleton which hold configuration from many files in hash map. So I need singleton which will read those files only once and persist hash map... Commented Sep 6, 2012 at 12:19
  • You can also do that without the Singleton module. Commented Sep 6, 2012 at 12:24
  • Yes, but prefer it this way since its much cleaner implementation. Commented Sep 6, 2012 at 12:26
  • How? Updated question to show it is not RoR project. Commented Sep 6, 2012 at 12:47

2 Answers 2

3

You could mix this module:

module DelegateToSingleton

  def respond_to_missing?(method)
    super || instance.respond_to?(method)
  end

  def method_missing(method, *args)
    instance.send(method, *args)
  end

end

into your singleton:

class Foo

  extend DelegateToSingleton
  include Singleton

  def foo
    'foo'
  end

  def bar
    'bar'
  end

end

with these results:

p Foo.foo    # => "foo"
p Foo.bar    # => "bar"

DelegateToSingleton::method_missing is what makes it work: Whenever Foo receives a method it doesn't know about, it just forwards it to its instance.

DelegateToSingleton::respond_to_missing? is not strictly needed, but having it is good manners whenever playing tricks with method_missing.

For Ruby earlier than 1.9.2: Override respond_to? instead of respond_to_missing?

Sign up to request clarification or add additional context in comments.

Comments

3

Just separate the class from the instance:

class Foo
  def initialize 
  end

  def get_bar
  end

  def get_nar
  end
end

MyFoo = Foo.new
MyFoo.get_bar

6 Comments

Than it is not singleton it is just instance.
Pedantry. It gives you the interface and behaviour you're going for in a much better way (better meaning more testable, more flexible, more obvious).
Like said before this example was just to simplify my problem. Real problem needs to be solved with singleton, since creation of instance is expensive. Passing reference of this instance would be just creating spaghetti code.
There is only one instance (the instance stored at MyFoo) and you incur more overhead delegating to it than you do just directly referencing it, as this does. Furthermore, this is a singleton in that it gives you a global point of access to a single instance. It only differs in that it doesn't restrict you from creating new ones. I think you're confusing the GoF's implementation with its definition. And frankly, I think the mentioned difference only exists because they defined it from the POV of Java where you can't do things like the above (which also explains their implementation)
@Dolphin, The dynamic assignment is a symptom of a problem with your program: Some files, when required, are being loaded more than once. The reason 1.9 fixes that is because it normalizes the path before checking to see if a file has already been required; 1.8.7 does not. Change your requires so that they all use the same literal as the path, or to use File.expand_path to normalize the paths, and you won't get the dynamic assignment anymore. Once you've fixed the problem with required files being loaded more than once, which you ought to anyway, then this is the better solution.
|

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.