mindreframer-dim 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
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