module MinDI::Container
Advanced services
↑ topPublic Instance Methods
Define a singleton service with deferred instantiation. Syntax and semantics are the same as singleton
, except that the block is not called when the service is requested, but only when a method is called on the service.
# File lib/mindi.rb 162 def deferred(name, &impl) # :yields: 163 impl_name = Container.impl_method_name(name) 164 define_implementation(impl_name, impl) 165 166 proxy_name = Container.impl_method_name("#{name}_proxy") 167 168 ivname = Container.iv(name) 169 proxy_ivname = Container.iv("#{name}_proxy") 170 171 define_method(name) do 172 instance_variable_get(ivname) || send(proxy_name) 173 end 174 175 define_method(proxy_name) do 176 proxy = instance_variable_get(proxy_ivname) 177 178 unless proxy 179 proxy = proc {instance_variable_set(ivname, send(impl_name))} 180 def proxy.method_missing(*args, &block) 181 call.__send__(*args, &block) 182 end 183 instance_variable_set(proxy_ivname, proxy) 184 class << proxy; self; end.class_eval do 185 (proxy.methods - PROXY_METHODS).each do |m| 186 undef_method m 187 end 188 end 189 end 190 191 proxy 192 end 193 end
Define a service with per-thread instantiation. For each thread, the service appears to be a singleton service. The block will be called at most once per thread. There is no shortcut. The block may take a single argument, in which case it will be passed the current thread.
threaded(:service_name) { |thr| ... }
# File lib/mindi.rb 141 def threaded(name, &impl) # :yields: thread 142 impl_name = Container.impl_method_name(name) 143 define_implementation(impl_name, impl) 144 arity = impl.arity 145 146 ivname = Container.iv(name) 147 define_method(name) do 148 key = Thread.current 149 map = instance_variable_get(ivname) 150 map ||= instance_variable_set(ivname, {}) 151 map[key] ||= (arity == 1 ? send(impl_name, key) : send(impl_name)) 152 end 153 end
Basic services
↑ topPublic Instance Methods
Define a generic service, which has no built-in rules for existence or uniqueness. There is no shortcut for generic service definition. Calling the service simply calls the associated block. This is also known as a prototype service.
# File lib/mindi.rb 50 def generic(name, &impl) # :yields: 51 define_implementation(name, impl) 52 end
Define a multiton service with multiple keys:
multiton(:service_name) { |arg0, arg1, ...| ... }
The block will be called once per distinct (in the sense of hash keys) argument list to instantiate a unique value corresponding to the argument list. The shortcut for defining a multikey_multiton
with multiple keys is:
service_name { |arg0, arg1, ...| ... }
The service is invoked as service_name(arg0, arg1, ...)
. Variable length argument lists, using the splat notation, are permitted.
# File lib/mindi.rb 115 def multikey_multiton(name, &impl) # :yields: arg0, arg1, ... 116 impl_name = Container.impl_method_name(name) 117 define_implementation(impl_name, impl) 118 119 ivname = Container.iv(name) 120 define_method(name) do |*key| 121 map = instance_variable_get(ivname) 122 map ||= instance_variable_set(ivname, {}) 123 map.key?(key) ? map[key] : map[key] = send(impl_name, *key) 124 end 125 end
Define a multiton service:
multiton(:service_name) { |arg| ... }
The block will be called once per distinct (in the sense of hash keys) argument to instantiate a unique value corresponding to the argument. The shortcut for defining a multiton is:
service_name { |arg| ... }
The service is invoked as service_name(arg)
.
# File lib/mindi.rb 90 def multiton(name, &impl) # :yields: arg 91 impl_name = Container.impl_method_name(name) 92 define_implementation(impl_name, impl) 93 94 ivname = Container.iv(name) 95 define_method(name) do |key| 96 map = instance_variable_get(ivname) 97 map ||= instance_variable_set(ivname, {}) 98 map.key?(key) ? map[key] : map[key] = send(impl_name, key) 99 end 100 end
Define a singleton service:
singleton(:service_name) { ... }
The block will be called at most once to instantiate a unique value for the service. The shortcut for defining a singleton is:
service_name { ... }
The service is invoked as service_name
.
# File lib/mindi.rb 65 def singleton(name, &impl) # :yields: 66 impl_name = Container.impl_method_name(name) 67 define_implementation(impl_name, impl) 68 69 ivname = Container.iv(name) 70 define_method(name) do 71 box = instance_variable_get(ivname) 72 box ||= instance_variable_set(ivname, []) 73 box << send(impl_name) if box.empty? 74 box.first 75 end 76 end
Internal methods
↑ topProtected Class Methods
The name of a method used internally to implement the service named name.
# File lib/mindi.rb 236 def self.impl_method_name(name) # :doc: 237 "___#{name}___implementation" 238 end
The name of an instance variable that stores the state of the service named name.
# File lib/mindi.rb 230 def self.iv(name) # :doc: 231 "@___#{name}___value" 232 end
Protected Instance Methods
# File lib/mindi.rb 216 def define_implementation impl_name, impl 217 if @__services_are_injected__ 218 preinject_method = impl_name + "__preinject" 219 define_method(preinject_method, &impl) 220 define_method(impl_name) do |*args| 221 inject_into send(preinject_method, *args) 222 end 223 else 224 define_method(impl_name, &impl) 225 end 226 end