Skip to content

Instantly share code, notes, and snippets.

@andypike
Last active December 15, 2015 22:09
Show Gist options
  • Save andypike/5330927 to your computer and use it in GitHub Desktop.
Save andypike/5330927 to your computer and use it in GitHub Desktop.
My first experiment with a simple IoC container in Ruby. To run this sample do this: $ ruby ioc.rb
# defining various components of the system
# notice the classes know nothing about the container
# as they require the dependencies to operate, they should be passed into the constructor
class Nails
def to_s
"nails"
end
end
class Glue
def to_s
"glue"
end
end
class PowerSaw
def initialize(power_source)
@power_source = power_source
end
def to_s
"#{@power_source} power saw"
end
end
class HandSaw
def to_s
"hand saw"
end
end
class Electricity
def to_s
"electrical"
end
end
class Carpenter
def initialize(tool, fixings)
@tool = tool
@fixings = fixings
end
def build_something
puts "Building something in wood with #{@fixings} and #{@tool}"
end
end
class Container
attr_reader :registry
def self.create_container
@container = self.new
yield @container
end
def self.resolve(key)
klass = @container.registry[key]
constructor_params = klass.instance_method(:initialize).parameters
required_dependancies = constructor_params.select{|p| p.first == :req}
.map{|p| resolve(p.last)}
klass.new(*required_dependancies) # add some options for lifecycle etc
end
def initialize
@registry = {}
end
def register(key, klass)
@registry[key] = klass
end
end
require './container'
require './classes'
# register the components of the system with the container
# as we can't use types to inject the correct dependency we rely on the convention
# of the constructor parameter names matching the keys registered
# this is where you swap implementations to change behaviour without touching your classes
Container.create_container do |c|
c.register :craftsman, Carpenter
c.register :tool, PowerSaw
c.register :fixings, Nails
c.register :power_source, Electricity
end
# resolve the root object, all dependencies will be instantiated and injected
craftsman = Container.resolve(:craftsman)
craftsman.build_something
# $ ruby ioc.rb
# => Building something in wood with nails and electrical power saw
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment