dim 0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ .project_env.rc
2
+ .togglerc
3
+ .gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -I. -I/Users/jim/working/git/rspec-given/lib --color
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@dim --create
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2004, 2010 Jim Weirich
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,16 @@
1
+ # DIM: Dependency Injection - Minimal
2
+
3
+ DIM is Jim Weirich's minimalistic dependency injection framework,
4
+ maintained in Gem form by [Mike Subelsky](http://subelsky.com).
5
+ For more background information, read Jim's [Dependency Injection](http://onestepback.org/articles/depinj/dim/dim_rb.html))
6
+ slides.
7
+
8
+ # License
9
+
10
+ DIM is available under the MIT license (see the file MIT-LICENSE for
11
+ details).
12
+
13
+ # More Information:
14
+
15
+ Read [this](http://onestepback.org/articles/depinj/appendixa.html) for
16
+ more information about using DIM.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby"
2
+
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+
6
+ task :default => :spec
7
+
8
+ task :spec do
9
+ sh "rspec spec"
10
+ end
@@ -0,0 +1,21 @@
1
+ require './lib/dim/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{dim}
5
+ s.version = Dim::VERSION
6
+ s.authors = ["Jim Weirich", "Mike Subelsky"]
7
+ s.date = Time.now.utc.strftime("%Y-%m-%d")
8
+ s.email = %q{mike@subelsky.com}
9
+ s.extra_rdoc_files = [
10
+ "README.md"
11
+ ]
12
+ s.files = `git ls-files`.split("\n")
13
+ s.homepage = %q{http://github.com/subelsky/dim}
14
+ s.rdoc_options = ["--charset=UTF-8"]
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = %q{1.5.0}
17
+ s.summary = %q{Minimalistic dependency injection framework}
18
+ s.description = %q{Minimalistic dependency injection framework}
19
+ s.test_files = `git ls-files spec`.split("\n")
20
+ s.add_development_dependency 'rspec'
21
+ end
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2005, 2010 by Jim Weirich (jim.weirich@gmail.com).
4
+ # All rights reserved.
5
+ #
6
+ # This software is available under the MIT license. See the
7
+ # MIT-LICENSE file for details.
8
+ #++
9
+ #
10
+ # = Dependency Injection - Minimal (DIM)
11
+ #
12
+ # The DIM module provides a minimal dependency injection framework for
13
+ # Ruby programs.
14
+ #
15
+ # Example:
16
+ #
17
+ # require 'dim'
18
+ #
19
+ # container = Dim::Container.new
20
+ # container.register(:log_file) { "logfile.log" }
21
+ # container.register(:logger) { |c| FileLogger.new(c.log_file) }
22
+ # container.register(:application) { |c|
23
+ # app = Application.new
24
+ # app.logger = c.logger
25
+ # app
26
+ # }
27
+ #
28
+ # c.application.run
29
+ #
30
+ module Dim
31
+ # Thrown when a service cannot be located by name.
32
+ class MissingServiceError < StandardError; end
33
+
34
+ # Thrown when a duplicate service is registered.
35
+ class DuplicateServiceError < StandardError; end
36
+
37
+ # Dim::Container is the central data store for registering services
38
+ # used for dependency injuction. Users register services by
39
+ # providing a name and a block used to create the service. Services
40
+ # may be retrieved by asking for them by name (via the [] operator)
41
+ # or by selector (via the method_missing technique).
42
+ #
43
+ class Container
44
+ attr_reader :parent
45
+
46
+ # Create a dependency injection container. Specify a parent
47
+ # container to use as a fallback for service lookup.
48
+ def initialize(parent=nil)
49
+ @services = {}
50
+ @cache = {}
51
+ @parent = parent || Container
52
+ end
53
+
54
+ # Register a service named +name+. The +block+ will be used to
55
+ # create the service on demand. It is recommended that symbols be
56
+ # used as the name of a service.
57
+ def register(name, &block)
58
+ if @services[name]
59
+ fail DuplicateServiceError, "Duplicate Service Name '#{name}'"
60
+ end
61
+ @services[name] = block
62
+ end
63
+
64
+ # Lookup a service by name. Throw an exception if no service is
65
+ # found.
66
+ def [](name)
67
+ @cache[name] ||= service_block(name).call(self)
68
+ end
69
+
70
+ # Lookup a service by message selector. A service with the same
71
+ # name as +sym+ will be returned, or an exception is thrown if no
72
+ # matching service is found.
73
+ def method_missing(sym, *args, &block)
74
+ self[sym]
75
+ end
76
+
77
+ # Return the block that creates the named service. Throw an
78
+ # exception if no service creation block of the given name can be
79
+ # found in the container or its parents.
80
+ def service_block(name)
81
+ @services[name] || @parent.service_block(name)
82
+ end
83
+
84
+ # Searching for a service block only reaches the Container class
85
+ # when all the containers in the hierarchy search chain have no
86
+ # entry for the service. In this case, the only thing to do is
87
+ # signal a failure.
88
+ def self.service_block(name)
89
+ fail(MissingServiceError, "Unknown Service '#{name}'")
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,3 @@
1
+ module Dim
2
+ VERSION = "0.9"
3
+ end
@@ -0,0 +1,165 @@
1
+ require 'dim'
2
+ require 'rspec/given'
3
+
4
+ class ConsoleAppender
5
+ end
6
+
7
+ class Logger
8
+ attr_accessor :appender
9
+ end
10
+
11
+ class MockDB
12
+ end
13
+
14
+ class RealDB
15
+ attr_accessor :username, :password
16
+ def initialize(username, password)
17
+ @username, @password = username, password
18
+ end
19
+ end
20
+
21
+ class App
22
+ attr_accessor :logger, :db
23
+ def initialize(logger=nil)
24
+ @logger = logger
25
+ end
26
+ end
27
+
28
+ describe Dim::Container do
29
+ let(:container) { Dim::Container.new }
30
+
31
+ Scenario "creating objects" do
32
+ Given { container.register(:app) { App.new } }
33
+ Then { container.app.should be_a(App) }
34
+ end
35
+
36
+ Scenario "returning the same object every time" do
37
+ Given { container.register(:app) { App.new } }
38
+ Given(:app) { container.app }
39
+ Then { container.app.should be(app) }
40
+ end
41
+
42
+ Scenario "contructing dependent objects" do
43
+ Given { container.register(:app) { |c| App.new(c.logger) } }
44
+ Given { container.register(:logger) { Logger.new } }
45
+ Given(:app) { container.app }
46
+ Then { app.logger.should be(container.logger) }
47
+ end
48
+
49
+ Scenario "constructing dependent objects with setters" do
50
+ Given {
51
+ container.register(:app) { |c|
52
+ App.new.tap { |obj|
53
+ obj.db = c.database
54
+ }
55
+ }
56
+ }
57
+ Given { container.register(:database) { MockDB.new } }
58
+ Given(:app) { container.app }
59
+
60
+ Then { app.db.should be(container.database) }
61
+ end
62
+
63
+ Scenario "constructing multiple dependent objects" do
64
+ Given {
65
+ container.register(:app) { |c|
66
+ App.new(c.logger).tap { |obj|
67
+ obj.db = c.database
68
+ }
69
+ }
70
+ }
71
+ Given { container.register(:logger) { Logger.new } }
72
+ Given { container.register(:database) { MockDB.new } }
73
+ Given(:app) { container.app }
74
+ Then { app.logger.should be(container.logger) }
75
+ Then { app.db.should be(container.database) }
76
+ end
77
+
78
+ Scenario "constructing chains of dependencies" do
79
+ Given { container.register(:app) { |c| App.new(c.logger) } }
80
+ Given {
81
+ container.register(:logger) { |c|
82
+ Logger.new.tap { |obj|
83
+ obj.appender = c.logger_appender
84
+ }
85
+ }
86
+ }
87
+ Given { container.register(:logger_appender) { ConsoleAppender.new } }
88
+ Given { container.register(:database) { MockDB.new } }
89
+ Given(:logger) { container.app.logger }
90
+
91
+ Then { logger.appender.should be(container.logger_appender) }
92
+ end
93
+
94
+ Scenario "constructing literals" do
95
+ Given { container.register(:database) { |c| RealDB.new(c.username, c.userpassword) } }
96
+ Given { container.register(:username) { "user_name_value" } }
97
+ Given { container.register(:userpassword) { "password_value" } }
98
+ Given(:db) { container.database }
99
+
100
+ Then { db.username.should == "user_name_value" }
101
+ Then { db.password.should == "password_value" }
102
+ end
103
+
104
+ describe "Errors" do
105
+ Scenario "missing services" do
106
+ Then {
107
+ lambda {
108
+ container.undefined_service_name
109
+ }.should raise_error(Dim::MissingServiceError, /undefined_service_name/)
110
+ }
111
+ end
112
+
113
+ Scenario "duplicate service names" do
114
+ Given { container.register(:duplicate_name) { 0 } }
115
+ Then {
116
+ lambda {
117
+ container.register(:duplicate_name) { 0 }
118
+ }.should raise_error(Dim::DuplicateServiceError, /duplicate_name/)
119
+ }
120
+ end
121
+ end
122
+
123
+ describe "Parent/Child Container Interaction" do
124
+ Given(:parent) { container }
125
+ Given(:child) { Dim::Container.new(parent) }
126
+
127
+ Given { parent.register(:cell) { :parent_cell } }
128
+ Given { parent.register(:gene) { :parent_gene } }
129
+ Given { child.register(:gene) { :child_gene } }
130
+
131
+ Scenario "reusing a service from the parent" do
132
+ Then { child.cell.should == :parent_cell }
133
+ end
134
+
135
+ Scenario "overiding a service from the parent" do
136
+ Then "the child service overrides the parent" do
137
+ child.gene.should == :child_gene
138
+ end
139
+ end
140
+
141
+ Scenario "wrapping a service from a parent" do
142
+ Given { child.register(:cell) { |c| [c.parent.cell] } }
143
+ Then { child.cell.should == [:parent_cell] }
144
+ end
145
+
146
+ Scenario "overriding an indirect dependency" do
147
+ Given { parent.register(:wrapped_cell) { |c| [c.cell] } }
148
+ Given { child.register(:cell) { :child_cell } }
149
+ Then { child.wrapped_cell.should == [:child_cell] }
150
+ end
151
+
152
+ Scenario "parent / child service conflicts from parents view" do
153
+ Then { parent.gene.should == :parent_gene }
154
+ end
155
+
156
+ Scenario "child / child service name conflicts" do
157
+ Given(:other_child) { Dim::Container.new(parent) }
158
+ Given { other_child.register(:gene) { :other_child_gene } }
159
+
160
+ Then { child.gene.should == :child_gene }
161
+ Then { other_child.gene.should == :other_child_gene }
162
+ end
163
+ end
164
+
165
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dim
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.9"
6
+ platform: ruby
7
+ authors:
8
+ - Jim Weirich
9
+ - Mike Subelsky
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-02-08 00:00:00 -05:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: rspec
19
+ prerelease: false
20
+ requirement: &id001 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "0"
26
+ type: :development
27
+ version_requirements: *id001
28
+ description: Minimalistic dependency injection framework
29
+ email: mike@subelsky.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files:
35
+ - README.md
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - .rvmrc
40
+ - MIT-LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - dim.gemspec
44
+ - lib/dim.rb
45
+ - lib/dim/version.rb
46
+ - spec/dim_spec.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/subelsky/dim
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.5.0
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Minimalistic dependency injection framework
75
+ test_files:
76
+ - spec/dim_spec.rb