# MinDI 0.3

**URL:** <https://www.ruby-forum.com/t/mindi-0-3/94444>\
**Category:** Ruby\
**Created:** [May 3, 2006, 7:10pm UTC](https://www.ruby-forum.com/t/mindi-0-3/94444 "2006-05-03T19:10:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 3, 2006, 7:10pm UTC](https://www.ruby-forum.com/t/mindi-0-3/94444/1 "2006-05-03T19:10:30Z")

</div>

[http://raa.ruby-lang.org/project/mindi/](http://raa.ruby-lang.org/project/mindi/)

This version of MinDI adds a new container type, InjectableContainer,  
which lets you hook up services via method\_missing. See the second  
example below. I’d be interested if anyone knows the correct term for  
this kind of DI. It’s definitely not setter or constructor injection.  
(The first example below is constructor injection.) Maybe “fallback  
injection”, or “duck interface injection” ?

An excerpt from the intro.txt file:

== MinDI

MinDI is Minimalist Dependency Injection for Ruby. It is inspired by  
Jamis B.'s Needle ([http://needle.rubyforge.org](http://needle.rubyforge.org)) and Jim W.'s  
article on DI in Ruby  
([http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc](http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc)).

MinDI is minimalist in that it attempts to map concepts of DI into basic  
ruby  
constructs, rather than into a layer of specialized constructs. In  
particular, classes and modules function as containers and registries,  
and methods and method definitions function as service points and  
services. There are some inherent advantages and disadvantages to this  
approach, discussed below.

MinDI builds on this minimal DI container by adding the  
InjectableContainer concept, which is a kind of DI available only in  
dynamic languages: through the magic of method\_missing, a  
service may invoke other services without having explicit setter or  
constructor references to those services.

=== Synopsis

_Using the BasicContainer module for constructor injection:_

require ‘mindi’

class SimpleContainer  
include MinDI::BasicContainer

```
greeting { "Hello, world\n" }

point_at { |x,y| [x,y] }

stuff { [greeting, point_at(100,200)] }

```

end

cont = SimpleContainer.new

p cont.stuff # ==\> [“Hello, world\n”, [100, 200]]

_Using the InjectableContainer module for “dynamic” or “fallback”  
injection, using method\_missing:_

require ‘mindi’

class Transformer  
def transform string  
string.gsub(pattern, &replacement)  
end  
end

class TransformerContainer  
include MinDI::InjectableContainer

```
pattern { /foo/ }
replacement { proc {|match| match.upcase } }
transformer { Transformer.new }
transform { |str| transformer.transform(str) }

```

end

cont = TransformerContainer.new  
s1 = cont.transform(“fo foo fee”)  
s2 = cont.transform(“fo foo fee”)  
p s1 # ==\> “fo FOO fee”  
p s1.equal?(s2) # ==\> true

Note that the Transformer class is written without explicitly linking up  
to services (either in initialize or in setters). It just assumes that  
the services will be defined in the container.

Note also that the #transform service is a multiton service, and (like  
singleton services) it caches its value for each argument.

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 3, 2006, 7:11pm UTC](https://www.ruby-forum.com/t/mindi-0-3/94444/2 "2006-05-03T19:11:02Z")

</div>

Joel VanderWerf [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> s1 = cont.transform(“fo foo fee”)  
> s2 = cont.transform(“fo foo fee”)  
> p s1 # ==\> “fo FOO fee”  
> p s1.equal?(s2) # ==\> true
> 
> Note that the Transformer class is written without explicitly linking up  
> to services (either in initialize or in setters). It just assumes that  
> the services will be defined in the container.

So, if I get that right… the Transformer instance gets extended with  
the TransformerContainer automatically? Or how does it know about  
“pattern” and “replacement”?

Isn’t that a clear and obvious violation of encapsulation?  
And won’t it hide lots of bugs due to typos or doubly defined methods?

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 3, 2006, 9:54pm UTC](https://www.ruby-forum.com/t/mindi-0-3/94444/3 "2006-05-03T21:54:31Z")

</div>

Christian N. wrote:

> > ```
> > end
> > 
> > ```
> 
> So, if I get that right… the Transformer instance gets extended with  
> the TransformerContainer automatically? Or how does it know about  
> “pattern” and “replacement”?

The Transformer instance is not extended with the TransformerContainer.  
It’s extended with a simpler module that just has a #method\_missing.  
More precisely…

Here’s what happens when the service is instantiated (i.e. the “{  
Transformer.new }” block is called in response to the #transformer  
method on the container):

The service object (the Transformer instance returned by the block) is  
given an instance variable, @ **injectable\_\_object** , whose value is set  
to the container.

Also, the service object is extended, but only with a fairly minimal  
module called Injected:

module Injected  
def method\_missing(\*args, &block)  
@ **injectable\_\_object** || super  
@ **injectable\_\_object**.send(\*args, &block)  
rescue NoInjectedMethodError  
super  
end  
end

The NoInjectedMethodError is raised by the container’s own  
method\_missing. So the method search order for the service object is:

1. the service object itself (the Transformer instance)

2. other services in the container (this is how “replacement” and  
“pattern” are resolved)

3. method\_missing, as defined in the ancestry of the service object

> Isn’t that a clear and obvious violation of encapsulation?

Yes. Better to be clear and obvious about it 😉

I’m not completely convinced by this style of DI. It may be no worse  
than others, though. In (say) setter injection DI there is a coupling  
between the container and the service, because the two need to agree on  
some list of accessors that the container will write to and the service  
will read from. In this proposed style of DI, the coupling is via  
references in the service to as-yet-undefined methods. It’s sort of like  
defining a class that will have Enumerable mixed into it, but not  
providing any methods other than #each. Or like delegating and assuming  
that the target will define certain methods.

> And won’t it hide lots of bugs due to typos or doubly defined methods?

If the container defines some method that is already defined in the  
service and which the service is not expecting the container to provide,  
the service will not be affected–it will continue to use its own  
method, as it should.

The service and the container just need to agree (implicitly, at least)  
on the list of methods the service expects the container to provide.

A typo in the service could invoke a container method (i.e., another  
service) by mistake.

I suppose the Injected class could, instead of defining #method\_missing,  
provide just a class method, called #uses or #uses\_services, which lets  
you specify explicitly what services it uses (and defines a method for  
each one):

class Transformer  
extend SomeModuleThatDefinesTheUsesServicesMethod  
uses\_services :pattern, :replacement  
def transform string  
string.gsub(pattern, &replacement)  
end  
end

(This approach would still need the @ **injectable\_\_object** hackery.)

But I’m not sure that typos are a serious enough danger to require this  
much explicitness. It would be that much harder to subclass Transformer  
and add mocked versions of pattern and replacement, for example, or to  
mix in a module that provided pattern and replacement in some other way.  
I’d prefer the service not to have to know it is going to be used in a  
container and only to know that certain methods will be defined somehow.

“Duck services” anyone?

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 3, 2006, 11:28pm UTC](https://www.ruby-forum.com/t/mindi-0-3/94444/4 "2006-05-03T23:28:23Z")

</div>

Joel VanderWerf [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> > Isn’t that a clear and obvious violation of encapsulation?
> 
> Yes. Better to be clear and obvious about it 😉

_g_

> I’m not completely convinced by this style of DI. It may be no worse  
> than others, though.

My DI library, Dissident, has a style that works similarily, but  
services that should be injected need to be declared… personally  
I like it.

```
class Transformer
  inject :pattern
  inject :replacement

  def transform string
    string.gsub(pattern, &replacement)
  end
end

```

(Note that this easily can be decoupled by adding “alias inject  
attr\_accessor”  
somewhere.)

That would work as you describe, I think:

> ```
> end
> 
> ```
> 
> end
> 
> (This approach would still need the @ **injectable\_\_object** hackery.)
> 
> But I’m not sure that typos are a serious enough danger to require this  
> much explicitness. It would be that much harder to subclass Transformer  
> and add mocked versions of pattern and replacement, for example, or to  
> mix in a module that provided pattern and replacement in some other way.  
> I’d prefer the service not to have to know it is going to be used in a  
> container and only to know that certain methods will be defined somehow.

> “Duck services” anyone?

IMO, PicoContainer-style constructor injection based on _argument name_  
would be very nifty to have… to bad we can’t inspect those in Ruby.
