Harbor::Container
Harbor::Container is an inversion of control container for simple dependency injection. For more information on dependency injection, see martinfowler.com/articles/injection.html.
Simple Example:
services = Harbor::Container.new
services.register("mailer", Harbor::Mailer)
class Controller
attr_accessor :mailer
end
services.register("Controller", Controller)
services.get("Controller") # => #<Controller: @mailer=#<Mailer>>
Parent
Namespace
Public Instance Methods
get(name, optional_properties = {})
Retrieve a service by name from the set of registered services, initializing any dependencies from the container, and optionally setting any additional properties on the service.
class Controller
attr_accessor :request, :response, :mailer
end
services.get("Controller", :request => Request.new(env), :response => Response.new(request))
# File lib/harbor/container.rb, line 51 51: def get(name, optional_properties = {}) 52: raise ArgumentError.new("#{name} is not a registered service name") unless registered?(name) 53: service_registration = @services[name] 54: service = service_registration.service.is_a?(Class) ? service_registration.service.new : service_registration.service 55: 56: dependencies(name).each do |dependency| 57: service.send("#{dependency}=", get(dependency, optional_properties)) 58: end 59: 60: optional_instances = {} 61: optional_properties.each_pair do |k,v| 62: instance = v.is_a?(Class) ? v.new : v 63: optional_instances[k] = instance 64: end 65: 66: optional_instances.each_pair do |k, v| 67: writer = "#{k}=" 68: service.send(writer, v) if service.respond_to?(writer) 69: optional_instances.each_pair do |k2,v2| 70: next if k2 == k || !v2.respond_to?(writer) 71: v2.send(writer, v) 72: end 73: end 74: 75: service_registration.initializers.each do |initializer| 76: initializer.call(service) 77: end 78: 79: service 80: end
method_missing(method, *args, &block)
# File lib/harbor/container.rb, line 82 82: def method_missing(method, *args, &block) 83: if method.to_s =~ /^(.*)\=$/ 84: register($1, *args, &block) 85: else 86: if registered?(method.to_s) 87: get(method.to_s, args[0] || {}) 88: else 89: raise NoMethodError.new("undefined method '#{method}' for #{self}", method) 90: end 91: end 92: end
register(name, service, &setup)
Register a service by name, with an optional initializer block.
services.register("mail_server", Harbor::SendmailServer.new(:sendmail => "/sbin/sendmail"))
services.register("mailer", Harbor::Mailer)
services.get("mailer") # => #<Harbor::Mailer @from=nil @mail_server=#<SendmailServer...>>
services.register("mailer", Harbor::Mailer) { |mailer| mailer.from = "admin@example.com" }
services.get("mailer") # => #<Harbor::Mailer @from="admin@example.com" @mail_server=#<SendmailServer...>>
# File lib/harbor/container.rb, line 104 104: def register(name, service, &setup) 105: 106: type_dependencies = dependencies(name) 107: type_methods = service.is_a?(Class) ? service.instance_methods.grep(/\=$/) : [] 108: 109: @services.values.each do |service_registration| 110: if service_registration.service.is_a?(Class) && service_registration.service.instance_methods.include?("#{name}=") 111: dependencies(service_registration.name) << name 112: end 113: 114: if type_methods.include?("#{service_registration.name}=") 115: type_dependencies << service_registration.name 116: end 117: end 118: 119: @services[name] = ServiceRegistration.new(name, service) 120: @services[name].initializers << setup if setup 121: 122: self 123: end