Skip to content

Instantly share code, notes, and snippets.

@barinek
Created September 4, 2012 15:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barinek/3622495 to your computer and use it in GitHub Desktop.
Save barinek/3622495 to your computer and use it in GitHub Desktop.
Guice-ish
require "singleton"
require "i18n"
require "active_support"
require "active_support/core_ext/string"
module Guice
def inject(*klass_symbols)
@injections = Hash.new unless @injections
@injections[self.name] = klass_symbols
end
def injections
@injections ||= Hash.new
@injections[self.name] || []
end
class Injector
include Singleton
def self.configure_injector(&block)
raise "Sorry, requires a block." unless block
raise "Sorry, already configured." if instance.configured
block.call(instance)
instance.instance_variable_set(:@configured, true)
instance
end
def initialize
@known_bindings = Hash.new
@known_instances = Hash.new
@configured = false
end
def configured
@configured
end
def bind(klass)
@known_bindings[klass.name] = klass
end
def get_instance(klass)
raise "Sorry, not configured." unless @configured
get_deep_instance(klass)
end
def get_deep_instance(klass, parents = [])
instance = @known_instances[klass.name]
return instance if instance
if klass.kind_of?(Guice)
parameters = klass.instance_method(:initialize).parameters.collect { |param| param[1] }
if (parameters.eql?(klass.injections))
parameter_instances = parameters.collect do |parameter|
return nil if parents.include?(parameter.to_s.camelize.constantize)
get_deep_instance(parameter.to_s.camelize.constantize, parents.push(klass))
end
raise "Sorry, possible circular dependency found." if parameter_instances.any? { |parameter_instance| parameter_instance.nil? }
@known_instances[klass.name] = klass.new(*parameter_instances)
end
else
begin
@known_instances[klass.name] = klass.new
rescue
raise "Sorry, unknown constructor args."
end
end
@known_instances[klass.name]
end
end
end
require "rspec"
describe Module do
before(:all) do
@injector = Guice::Injector.configure_injector do |injector|
injector.bind(Foo)
injector.bind(Bar)
injector.bind(Cart)
injector.bind(Horse)
injector.bind(Fiz)
injector.bind(Buz)
end
end
it "can't be created" do
lambda do
Guice::Injector.new
end.should raise_error
end
it "requires a block" do
lambda do
Guice::Injector.configure_injector
end.should raise_error("Sorry, requires a block.")
end
it "complains about being configured twice" do
lambda do
Guice::Injector.configure_injector do |injector|
injector.bind(Foo)
end
end.should raise_error("Sorry, already configured.")
end
it "injects bar" do
foo = @injector.get_instance(Foo)
foo.bar.should be
end
it "complains about circular dependencies" do
lambda { @injector.get_instance(Cart) }.should raise_error("Sorry, possible circular dependency found.")
lambda { @injector.get_instance(Horse) }.should raise_error("Sorry, possible circular dependency found.")
end
it "complains about unknown constructor args" do
lambda { @injector.get_instance(Fiz) }.should raise_error("Sorry, unknown constructor args.")
end
class Foo
extend Guice
inject :bar
def initialize(bar)
@bar = bar
end
def bar
@bar
end
end
class Bar
end
class Cart
extend Guice
inject :horse
def initialize(horse)
end
end
class Horse
extend Guice
inject :cart
def initialize(cart)
end
end
class Fiz
extend Guice
inject :buz
def initialize(buz)
end
end
class Buz
def initialize(bop)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment