Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: DRY class methods calling Singleton instance methods [duplicate]

I have the a Singleton class ExchangeRegistry which keeps all the Exchange objects.

Instead of needing to call: ExchangeRegistry.instance.exchanges

I want to be able to use: ExchangeRegistry.exchanges

This works, but I'm not happy with the repetition:

require 'singleton'

# Ensure an Exchange is only created once
class ExchangeRegistry
  include Singleton

  # Class Methods  ###### Here be duplication and dragons

  def self.exchanges
    instance.exchanges
  end

  def self.get(exchange)
    instance.get(exchange)
  end

  # Instance Methods

  attr_reader :exchanges

  def initialize
    @exchanges = {} # Stores every Exchange created
  end

  def get(exchange)
    @exchanges[Exchange.to_sym exchange] ||= Exchange.create(exchange)
  end
end

I'm not happy with the duplication in the class methods.

I've tried using Forwardable and SimpleDelegator but can't seem to get this to DRY out. (Most examples out there are not for class methods but for instance methods)

like image 873
Tom Hale Avatar asked Jan 07 '23 19:01

Tom Hale


2 Answers

The forwardable module will do this. Since you are forwarding class methods, you have to open up the eigenclass and define the forwarding there:

require 'forwardable'
require 'singleton'

class Foo

  include Singleton

  class << self
    extend Forwardable
    def_delegators :instance, :foo, :bar
  end

  def foo
    'foo'
  end

  def bar
    'bar'
  end

end

p Foo.foo    # => "foo"
p Foo.bar    # => "bar"
like image 81
Wayne Conrad Avatar answered Jan 10 '23 19:01

Wayne Conrad


The accepted answer is clever, but seems needlessly complex (not to mention to performance penalty of method_missing.

The usual way to solve this is to just assign the instance to a constant.

class ExchangeRegistrySingleton
  include Singleton

  # ...
end

ExchangeRegistry = ExchangeRegistrySingleton.instance
like image 23
Jordan Running Avatar answered Jan 10 '23 18:01

Jordan Running