Skip to content

Instantly share code, notes, and snippets.

@toretore
Created January 24, 2011 18:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save toretore/793728 to your computer and use it in GitHub Desktop.
Save toretore/793728 to your computer and use it in GitHub Desktop.
#Keeps a list of registered names associated with classes at a "base" class
#Example:
#
# class Base
# extend Registerable
# end
#
# class Foo < Base
# register :foo
# end
#
# class Bar < Base
# register :bar
# end
#
# Base.registered == {'foo' => Foo, 'bar' => Bar}
# Base.class_for(:foo) == Base::Foo
# Base::Foo.identifier == :foo
module Registerable
class NotRegisteredError < StandardError
end
#Create a registry on the class to which this module has been extended to contain
#a map of names to classes inheriting from it.
def self.extended(klass)
#All registered classes inheriting from klass are stores in a class
#instance variable on klass.
class << klass; def registered; @registered ||= {}; end; end
#Save the class using a closure, defining a singleton method on klass.
#User define_method to get the closure (block), but define_method defines
#instance methods on the receiver, so we need to get klass's metaclass first.
(class << klass;self;end).send(:define_method, :base){ klass }
end
def register(identifier)
base.registered[identifier.to_s] = self
end
def class_for(identifier)
base.registered[identifier.to_s] || raise(NotRegisteredError, "Couldn't find class registered with \"#{identifier}\"")
end
def create(identifier, *a, &b)
class_for(identifier).new(*a, &b)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment