mindreframer-dim 1.2.5

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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .project_env.rc
2
+ .togglerc
3
+ *.gem
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3-turbo@dim --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ..gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dim (1.2.5)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.1)
10
+ rspec (2.13.0)
11
+ rspec-core (~> 2.13.0)
12
+ rspec-expectations (~> 2.13.0)
13
+ rspec-mocks (~> 2.13.0)
14
+ rspec-core (2.13.0)
15
+ rspec-expectations (2.13.0)
16
+ diff-lcs (>= 1.1.3, < 2.0)
17
+ rspec-given (2.4.0)
18
+ rspec (>= 2.11)
19
+ sorcerer (>= 0.3.7)
20
+ rspec-mocks (2.13.0)
21
+ sorcerer (0.3.10)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ dim!
28
+ rspec
29
+ rspec-given
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Mike Subelsky
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,81 @@
1
+ # DIM: Dependency Injection - Minimal
2
+
3
+ DIM is [Jim Weirich's](http://onestepback.org) minimalistic dependency injection framework, maintained in
4
+ gem form by [Mike Subelsky](http://subelsky.com).
5
+
6
+ Dependency injection lets you organize all of your app's object setup code in one place by creating a
7
+ container. Whenver an object in your application needs access to another object or resource, it asks
8
+ the container to provide it (using lazily-evaluated code blocks).
9
+
10
+ When testing your code, you can either stub out services on the container, or you can provide a substitute container.
11
+
12
+ ## Example
13
+
14
+ The following could be in a "lib.init.rb" file or in a Rails app, "config/initializers/container.rb":
15
+
16
+ require "dim"
17
+ require "logger"
18
+ require 'game'
19
+ require 'event_handler'
20
+ require 'transmitter'
21
+
22
+ ServerContainer = Dim::Container.new
23
+
24
+ ServerContainer.register(:transmitter) { |c| Transmitter.new(c.logger) }
25
+
26
+ ServerContainer.register(:event_handler) do |c|
27
+ eh = EventHandler.new
28
+ eh.transmitter = c.transmitter
29
+ eh.logger = c.logger
30
+ eh
31
+ end
32
+
33
+ ServerContainer.register(:listening_host) { "0.0.0.0" }
34
+ ServerContainer.register(:listening_port) { "8080" }
35
+
36
+ ServerContainer.register(:game) do |c|
37
+ game = Game.new
38
+ game.logger = c.logger
39
+ game.event_handler = c.event_handler
40
+ game.host = c.listening_host
41
+ game.port = c.listening_port
42
+ game
43
+ end
44
+
45
+ ServerContainer.register(:root_dir) do |c|
46
+ Pathname.new(File.expand_path(File.dirname(__FILE__) + "/.."))
47
+ end
48
+
49
+ ServerContainer.register(:log_file_path) do |c|
50
+ "#{c.root_dir}/log/#{c.environment}.log"
51
+ end
52
+
53
+ ServerContainer.register(:logger) do |c|
54
+ Logger.new(c.log_file_path)
55
+ end
56
+
57
+ # attempts to read ENV["API_PASSWORD"], otherwise makes sure that the parent container has
58
+ # a service named api_password registered
59
+ ServerContainer.register_env(:api_password)
60
+
61
+ Using the above code elsewhere in the app, when you want a reference to the app's logger object:
62
+
63
+ ServerContainer.logger.info("I didn't have to setup my own logger")
64
+
65
+ Or if you wanted access to the game instance created during setup (which already is configured with everything it needs):
66
+
67
+ current_game = ServerContainer.game
68
+
69
+ If you don't like creating even the one dependency on the global constant ServerContainer, you could
70
+ inject ServerContainer itself into your objects like so:
71
+
72
+ World.new(GameContainer)
73
+
74
+ ## More Background
75
+
76
+ Jim wrote a [nice article](http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc) explaining
77
+ the rationale for this code and how it works. Also check out [his slides](http://onestepback.org/articles/depinj/).
78
+
79
+ # License
80
+
81
+ Dim is available under the MIT license (see the file LICENSE for details).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+
7
+ task :default => :spec
8
+
9
+ task :spec do
10
+ sh "rspec spec"
11
+ end
data/dim.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'lib/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{mindreframer-dim}
6
+ s.version = Dim::VERSION
7
+ s.authors = ["Jim Weirich", "Mike Subelsky"]
8
+ s.date = Time.now.utc.strftime("%Y-%m-%d")
9
+ s.email = %q{mike@subelsky.com}
10
+ s.extra_rdoc_files = %w(README.markdown)
11
+ s.files = `git ls-files`.split("\n")
12
+ s.homepage = %q{http://github.com/subelsky/dim}
13
+ s.rdoc_options = ["--charset=UTF-8"]
14
+ s.require_paths = ["lib"]
15
+ s.summary = %q{Minimalistic dependency injection framework}
16
+ s.description = %q{Minimalistic dependency injection framework keeps all of your object setup code in one place.}
17
+ s.test_files = `git ls-files spec`.split("\n")
18
+ s.add_development_dependency 'rspec'
19
+ s.add_development_dependency 'rspec-given'
20
+ s.license = "MIT"
21
+ end
data/lib/dim.rb ADDED
@@ -0,0 +1,134 @@
1
+ #--
2
+ # Copyright 2004, 2005, 2010, 2012 by Jim Weirich (jim.weirich@gmail.com)
3
+ # and Mike Subelsky (mike@subelsky.com)
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # This software is available under the MIT license. See the 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
+ MissingServiceError = Class.new(StandardError)
33
+
34
+ # Thrown when a duplicate service is registered.
35
+ DuplicateServiceError = Class.new(StandardError)
36
+
37
+ # Thrown by register_env when a suitable ENV variable can't be found
38
+ EnvironmentVariableNotFound = Class.new(StandardError)
39
+
40
+ # Dim::Container is the central data store for registering services
41
+ # used for dependency injuction. Users register services by
42
+ # providing a name and a block used to create the service. Services
43
+ # may be retrieved by asking for them by name (via the [] operator)
44
+ # or by selector (via the method_missing technique).
45
+ #
46
+ class Container
47
+ attr_reader :parent
48
+
49
+ # Create a dependency injection container. Specify a parent
50
+ # container to use as a fallback for service lookup.
51
+ def initialize(parent=nil)
52
+ @services = {}
53
+ @cache = {}
54
+ @parent = parent || Container
55
+ end
56
+
57
+ def to_s
58
+ info = " services: #{service_list}"
59
+ "<Dim::Container::#{self.__id__}:#{info}>"
60
+ end
61
+
62
+ # Register a service named +name+. The +block+ will be used to
63
+ # create the service on demand. It is recommended that symbols be
64
+ # used as the name of a service.
65
+ def register(name, &block)
66
+ if @services[name]
67
+ fail DuplicateServiceError, "Duplicate Service Name '#{name}'"
68
+ end
69
+ @services[name] = block
70
+
71
+ self.class.send(:define_method, name) do
72
+ self[name]
73
+ end
74
+ end
75
+
76
+ # Lookup a service from ENV variables; fall back to searching the container and its parents for a default value
77
+ def register_env(name)
78
+ if value = ENV[name.to_s.upcase]
79
+ register(name) { value }
80
+ else
81
+ begin
82
+ @parent.service_block(name)
83
+ rescue MissingServiceError
84
+ raise EnvironmentVariableNotFound, "Could not find an ENV variable named #{name.to_s.upcase} nor could we find a service named #{name} in the parent container"
85
+ end
86
+ end
87
+ end
88
+
89
+ # Lookup a service by name. Throw an exception if no service is
90
+ # found.
91
+ def [](name)
92
+ @cache[name] ||= service_block(name).call(self)
93
+ end
94
+
95
+ ##
96
+ # a list with services, that this container provides
97
+ # @return [Array]
98
+ def service_list
99
+ (@services.keys + @parent.service_list).flatten.uniq
100
+ end
101
+
102
+ # initial implementation for a clean Container
103
+ def self.service_list
104
+ []
105
+ end
106
+
107
+ # Lookup a service by message selector. A service with the same
108
+ # name as +sym+ will be returned, or an exception is thrown if no
109
+ # matching service is found.
110
+ def method_missing(sym, *args, &block)
111
+ self[sym]
112
+ end
113
+
114
+ # Return the block that creates the named service. Throw an
115
+ # exception if no service creation block of the given name can be
116
+ # found in the container or its parents.
117
+ def service_block(name)
118
+ @services[name] || @parent.service_block(name)
119
+ end
120
+
121
+ # Resets the cached services
122
+ def clear_cache!
123
+ @cache = {}
124
+ end
125
+
126
+ # Searching for a service block only reaches the Container class
127
+ # when all the containers in the hierarchy search chain have no
128
+ # entry for the service. In this case, the only thing to do is
129
+ # signal a failure.
130
+ def self.service_block(name)
131
+ fail(MissingServiceError, "Unknown Service '#{name}'")
132
+ end
133
+ end
134
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Dim
2
+ VERSION = "1.2.5"
3
+ end
data/spec/dim_spec.rb ADDED
@@ -0,0 +1,221 @@
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
+ describe "creating objects" do
32
+ Given { container.register(:app) { App.new } }
33
+ Then { container.app.should be_a(App) }
34
+ end
35
+
36
+ describe "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
+ it "clears cache explicitly" do
43
+ container.register(:app) { App.new }
44
+ app_before = container.app
45
+ container.clear_cache!
46
+ app_after = container.app
47
+ app_before.should_not == app_after
48
+ end
49
+
50
+ describe "contructing dependent objects" do
51
+ Given { container.register(:app) { |c| App.new(c.logger) } }
52
+ Given { container.register(:logger) { Logger.new } }
53
+ Given(:app) { container.app }
54
+ Then { app.logger.should be(container.logger) }
55
+ end
56
+
57
+ describe "constructing dependent objects with setters" do
58
+ Given {
59
+ container.register(:app) { |c|
60
+ App.new.tap { |obj|
61
+ obj.db = c.database
62
+ }
63
+ }
64
+ }
65
+ Given { container.register(:database) { MockDB.new } }
66
+ Given(:app) { container.app }
67
+
68
+ Then { app.db.should be(container.database) }
69
+ end
70
+
71
+ describe "constructing multiple dependent objects" do
72
+ Given {
73
+ container.register(:app) { |c|
74
+ App.new(c.logger).tap { |obj|
75
+ obj.db = c.database
76
+ }
77
+ }
78
+ }
79
+ Given { container.register(:logger) { Logger.new } }
80
+ Given { container.register(:database) { MockDB.new } }
81
+ Given(:app) { container.app }
82
+ Then { app.logger.should be(container.logger) }
83
+ Then { app.db.should be(container.database) }
84
+ end
85
+
86
+ describe "constructing chains of dependencies" do
87
+ Given { container.register(:app) { |c| App.new(c.logger) } }
88
+ Given {
89
+ container.register(:logger) { |c|
90
+ Logger.new.tap { |obj|
91
+ obj.appender = c.logger_appender
92
+ }
93
+ }
94
+ }
95
+ Given { container.register(:logger_appender) { ConsoleAppender.new } }
96
+ Given { container.register(:database) { MockDB.new } }
97
+ Given(:logger) { container.app.logger }
98
+
99
+ Then { logger.appender.should be(container.logger_appender) }
100
+ end
101
+
102
+ describe "constructing literals" do
103
+ Given { container.register(:database) { |c| RealDB.new(c.username, c.userpassword) } }
104
+ Given { container.register(:username) { "user_name_value" } }
105
+ Given { container.register(:userpassword) { "password_value" } }
106
+ Given(:db) { container.database }
107
+
108
+ Then { db.username.should == "user_name_value" }
109
+ Then { db.password.should == "password_value" }
110
+ end
111
+
112
+ describe "Errors" do
113
+ describe "missing services" do
114
+ Then {
115
+ lambda {
116
+ container.undefined_service_name
117
+ }.should raise_error(Dim::MissingServiceError, /undefined_service_name/)
118
+ }
119
+ end
120
+
121
+ describe "duplicate service names" do
122
+ Given { container.register(:duplicate_name) { 0 } }
123
+ Then {
124
+ lambda {
125
+ container.register(:duplicate_name) { 0 }
126
+ }.should raise_error(Dim::DuplicateServiceError, /duplicate_name/)
127
+ }
128
+ end
129
+ end
130
+
131
+ describe "Parent/Child Container Interaction" do
132
+ Given(:parent) { container }
133
+ Given(:child) { Dim::Container.new(parent) }
134
+
135
+ Given { parent.register(:cell) { :parent_cell } }
136
+ Given { parent.register(:gene) { :parent_gene } }
137
+ Given { child.register(:gene) { :child_gene } }
138
+
139
+ describe "reusing a service from the parent" do
140
+ Then { child.cell.should == :parent_cell }
141
+ end
142
+
143
+ describe "overiding a service from the parent" do
144
+ Then { child.gene.should == :child_gene }
145
+ end
146
+
147
+ describe "wrapping a service from a parent" do
148
+ Given { child.register(:cell) { |c| [c.parent.cell] } }
149
+ Then { child.cell.should == [:parent_cell] }
150
+ end
151
+
152
+ describe "overriding an indirect dependency" do
153
+ Given { parent.register(:wrapped_cell) { |c| [c.cell] } }
154
+ Given { child.register(:cell) { :child_cell } }
155
+ Then { child.wrapped_cell.should == [:child_cell] }
156
+ end
157
+
158
+ describe "parent / child service conflicts from parents view" do
159
+ Then { parent.gene.should == :parent_gene }
160
+ end
161
+
162
+ describe "child / child service name conflicts" do
163
+ Given(:other_child) { Dim::Container.new(parent) }
164
+ Given { other_child.register(:gene) { :other_child_gene } }
165
+
166
+ Then { child.gene.should == :child_gene }
167
+ Then { other_child.gene.should == :other_child_gene }
168
+ end
169
+ end
170
+
171
+ describe "Registering env variables" do
172
+ describe "which exist in ENV" do
173
+ Given { ENV["SHAZ"] = "bot" }
174
+ Given { container.register_env(:shaz) }
175
+ Then { container.shaz.should == "bot" }
176
+ end
177
+
178
+ describe "which exist in optional hash" do
179
+ Given(:parent) { container }
180
+ Given { parent.register(:foo) { "bar" } }
181
+ Given(:child) { Dim::Container.new(parent) }
182
+
183
+ Given { ENV["FOO"] = nil }
184
+ Given { child.register_env(:foo) }
185
+ Then { container.foo.should == "bar" }
186
+ end
187
+
188
+ describe "which don't exist in optional hash" do
189
+ Then {
190
+ lambda {
191
+ container.register_env(:dont_exist_in_env_or_optional_hash)
192
+ }.should raise_error(Dim::EnvironmentVariableNotFound)
193
+ }
194
+ end
195
+ end
196
+
197
+
198
+ describe "output in terminal" do
199
+ describe "contains a short list of services" do
200
+ Given(:parent) { container }
201
+ Given { parent.register(:parent_foo) { "bar" } }
202
+ Then { parent.to_s.should include("services: [:parent_foo]") }
203
+ end
204
+
205
+ describe "also from parent" do
206
+ Given(:parent) { container }
207
+ Given { parent.register(:parent_foo) { "bar" } }
208
+ Given(:child) { Dim::Container.new(parent) }
209
+ Given { child.register(:child_foo) {"bar"} }
210
+ Then { child.to_s.should include("services: [:child_foo, :parent_foo]") }
211
+ end
212
+
213
+ describe "also when overridden from parent without duplicates" do
214
+ Given(:parent) { container }
215
+ Given { parent.register(:overriden_foo) { "parent" } }
216
+ Given(:child) { Dim::Container.new(parent) }
217
+ Given { child.register(:overriden_foo) {"child"} }
218
+ Then { child.to_s.should include("services: [:overriden_foo]") }
219
+ end
220
+ end
221
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mindreframer-dim
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jim Weirich
9
+ - Mike Subelsky
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-03-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rspec-given
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Minimalistic dependency injection framework keeps all of your object
48
+ setup code in one place.
49
+ email: mike@subelsky.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - README.markdown
54
+ files:
55
+ - .gitignore
56
+ - .rvmrc
57
+ - Gemfile
58
+ - Gemfile.lock
59
+ - LICENSE
60
+ - README.markdown
61
+ - Rakefile
62
+ - dim.gemspec
63
+ - lib/dim.rb
64
+ - lib/version.rb
65
+ - spec/dim_spec.rb
66
+ homepage: http://github.com/subelsky/dim
67
+ licenses:
68
+ - MIT
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 1.8.25
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Minimalistic dependency injection framework
92
+ test_files:
93
+ - spec/dim_spec.rb