module MinDI::Container

Advanced services

↑ top

Public Instance Methods

deferred(name) { || ... } click to toggle source

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
threaded(name) { |thread| ... } click to toggle source

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

↑ top

Public Instance Methods

generic(name) { || ... } click to toggle source

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
multikey_multiton(name) { |arg0, arg1, ...| ... } click to toggle source

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
multiton(name) { |arg| ... } click to toggle source

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
singleton(name) { || ... } click to toggle source

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

↑ top

Protected Class Methods

impl_method_name(name) click to toggle source

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
iv(name) click to toggle source

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

define_implementation(impl_name, impl) click to toggle source
    # 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