dim 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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