ioc 4.1.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: beb7d05c11433d3fd20a45084e0c41ff64f166cf
4
- data.tar.gz: cb699ee843c95a790b4af1b16d547f7d4e21ad79
3
+ metadata.gz: 45cfdeec3bba0d8515b0cb35b5237b66a028ce85
4
+ data.tar.gz: 13fcee15a0d44787e8f79017ec0c5cb81c0bf126
5
5
  SHA512:
6
- metadata.gz: f0a1c1617334862a57ae5e65e86d8cd23ad7aaeae8b47b0b5f9ae5e3b450ddd4e16fa8999d055b9a227d3f630be94715424e3d0112ec0d663fc8e8543266d82e
7
- data.tar.gz: 2f4aeb3e70503c3746ba63f5eb71870be9a17567be715ba4f091551d25cf9733e644ba290e62f753e8c41d7acc059e0bb5cc20e02dcc85b835e7e9d35f65fadb
6
+ metadata.gz: 8b880eeb06d15ddf14edcc384ba270d0ec8d7c23364a043a43af2a1211889909d42531d05bb0cbe7f012489c2407f06bc5af8ce1a831751a3bd708930a051326
7
+ data.tar.gz: 21b1a31d877de30d7fac725a40208c2e1eeecce806f1e0812eaedd992f95fedad60b68f55bc4c073c3afd5be38334403e88553b836227434cec4d46966823d69
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Erik Lott
1
+ Copyright (c) 2015 Erik Lott
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
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.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # IOC
2
2
 
3
- TODO: Write a gem description
3
+ Minimal dependency injection container for ruby.
4
+
5
+ Tested on the following Rubies: MRI 2.2.1, 2.0.0, 1.9.3
4
6
 
5
7
  ## Installation
6
8
 
@@ -17,8 +19,77 @@ Or install it yourself as:
17
19
  $ gem install ioc
18
20
 
19
21
  ## Usage
22
+ ### Block Registration
23
+ This example illustrates how to register a service/component with the container by passing a block to the register method.
24
+ ```ruby
25
+ require "ioc"
26
+
27
+ class AccountRepository
28
+ def initialize(database, logger)
29
+ @database = database
30
+ @logger = logger
31
+ end
32
+ # ... some store & finder methods here
33
+ end
34
+
35
+ class UserRepository
36
+ def initialize(database, logger)
37
+ @database = database
38
+ @logger = logger
39
+ end
40
+ # ... some store & finder methods here
41
+ end
42
+
43
+ class CreateAccountService
44
+ def initialize(account_repository, user_repository, logger)
45
+ @account_repository = account_repository
46
+ @user_repository = user_repository
47
+ @logger = logger
48
+ end
49
+
50
+ def call(req, res)
51
+ # ... create account code
52
+ end
53
+ end
54
+
55
+ # Register Services
56
+ container = IOC::Container.new
57
+ container.register(:create_account_service) do |c|
58
+ CreateAccountService.new(c.account_repository, c.user_repository, c.logger)
59
+ end
60
+ container.register(:user_repository) do |c|
61
+ UserRepository.new(c.database, c.logger)
62
+ end
63
+ container.register(:account_repository) do |c|
64
+ AccountRepository.new(c.database, c.logger)
65
+ end
66
+ container.register(:logger){|c| Logger.new}
67
+ container.register(:database){|c| DB}
68
+
69
+ # Resolve Service
70
+ container.resolve(:create_account_service).call(req, res)
71
+
72
+ # Release the object graph for garbage collection
73
+ container.release
74
+ ```
75
+ ### Automatic Dependency Resolution
76
+ Rather than assigning each service's dependencies manually like in the example above, we can allow the container to build and inject each service's dependencies automatically.
77
+ ```ruby
78
+ # Register Services
79
+ container = IOC::Container.new
80
+ container.register(:create_account_service, CreateAccountService)
81
+ container.register(:user_repository, UserRepository)
82
+ container.register(:account_repository, AccountRepository)
83
+ container.register(:logger){|c| Logger.new}
84
+ container.register(:database){|c| DB}
85
+
86
+ # Resolve Service
87
+ container.resolve(:create_account_service).call(req, res)
88
+
89
+ # Release the object graph for garbage collection
90
+ container.release
91
+ ```
20
92
 
21
- TODO: Write usage instructions here
22
93
 
23
94
  ## Contributing
24
95
 
@@ -1,19 +1,20 @@
1
1
  # coding: utf-8
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = 'ioc'
5
- spec.version = '4.1.0'
6
- spec.authors = ['Erik Lott']
7
- spec.email = ['erik.lott@kodio.io']
8
- spec.summary = 'Minimal inversion of control container for Ruby'
9
- spec.homepage = ''
10
- spec.license = 'MIT'
11
- spec.files = ['LICENSE.txt', 'README.md', 'Rakefile', 'ioc.gemspec']
12
- spec.files += Dir.glob('lib/**/*.rb')
13
- spec.files += Dir.glob('spec/**/*')
14
- spec.test_files = Dir.glob('spec/**/*')
4
+ spec.name = "ioc"
5
+ spec.version = "6.0.0"
6
+ spec.authors = ["Erik Lott"]
7
+ spec.email = ["erik.lott@kodio.io"]
8
+ spec.summary = "Minimal dependency injection container for Ruby"
9
+ spec.homepage = ""
10
+ spec.license = "MIT"
11
+ spec.files = ["LICENSE.txt", "README.md", "Rakefile", "ioc.gemspec"]
12
+ spec.files += Dir.glob("lib/**/*.rb")
13
+ spec.files += Dir.glob("spec/**/*")
14
+ spec.test_files = Dir.glob("spec/**/*")
15
15
  spec.require_paths = ["lib"]
16
16
 
17
17
  spec.add_development_dependency "bundler", "~> 1.5"
18
18
  spec.add_development_dependency "rake"
19
+ spec.add_development_dependency "minitest"
19
20
  end
data/lib/ioc.rb CHANGED
@@ -1 +1,37 @@
1
- require "ioc/container"
1
+ module IOC
2
+ class IOCError < ::StandardError; end
3
+ class DuplicateServiceError < IOCError; end
4
+ class RegistrationError < IOCError; end
5
+ class UnknownServiceError < IOCError; end
6
+
7
+ class Container
8
+ def initialize
9
+ @services = {}
10
+ @cache = {}
11
+ end
12
+
13
+ def register(key, klass=nil, &block)
14
+ raise(DuplicateServiceError, "Service '#{key}' has already been registered") if @services.key?(key)
15
+ raise(RegistrationError, "expected class or block") unless klass || block_given?
16
+ @services[key] = klass ? klass : block
17
+ end
18
+
19
+ def resolve(key)
20
+ return @cache[key] if @cache.key?(key)
21
+ raise(UnknownServiceError, "Service '#{key}' not registered") unless @services.key?(key)
22
+
23
+ @cache[key] =
24
+ if @services[key].is_a?(Proc)
25
+ @services[key].call(self)
26
+ else
27
+ dependencies = @services[key].instance_method(:initialize).parameters.map(&:last)
28
+ resolved_dependencies = dependencies.map{|dependency| resolve(dependency)}
29
+ @services[key].new(*resolved_dependencies)
30
+ end
31
+ end
32
+
33
+ def release
34
+ @cache = {}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ require "minitest"
2
+ require "minitest/autorun"
3
+ require "ioc"
4
+
5
+ class CarFixture
6
+ attr_reader :engine
7
+ def initialize(engine)
8
+ @engine = engine
9
+ end
10
+ end
11
+
12
+ class EngineFixture; end
13
+
14
+ describe IOC do
15
+ it "can resolve a service class" do
16
+ container = IOC::Container.new
17
+ container.register(:myclass, EngineFixture)
18
+ inst = container.resolve(:myclass)
19
+ inst.must_be_instance_of(EngineFixture)
20
+ end
21
+
22
+ it "can resolve a service classes dependencies" do
23
+ container = IOC::Container.new
24
+ container.register(:engine, EngineFixture)
25
+ container.register(:car, CarFixture)
26
+ car = container.resolve(:car)
27
+ car.engine.must_be_instance_of(EngineFixture)
28
+ end
29
+
30
+ it "caches resolved services" do
31
+ container = IOC::Container.new
32
+ container.register(:engine, EngineFixture)
33
+ engine1 = container.resolve(:engine)
34
+ engine2 = container.resolve(:engine)
35
+ (engine1 === engine2).must_equal(true)
36
+ end
37
+
38
+ it "can resolve a service block" do
39
+ myobject = "mystring"
40
+ container = IOC::Container.new
41
+ container.register(:myobject){|c| myobject }
42
+ container.resolve(:myobject).must_equal(myobject)
43
+ end
44
+
45
+ it "complains when resolving unknown service" do
46
+ container = IOC::Container.new
47
+ proc {
48
+ container.resolve(:some_unknown_service)
49
+ }.must_raise(IOC::UnknownServiceError)
50
+ end
51
+
52
+ it "complains when service name registered more than once" do
53
+ container = IOC::Container.new
54
+ container.register(:myclass, EngineFixture)
55
+ proc {
56
+ container.register(:myclass, EngineFixture)
57
+ }.must_raise(IOC::DuplicateServiceError)
58
+ end
59
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ioc
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Lott
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-07 00:00:00.000000000 Z
11
+ date: 2015-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description:
42
56
  email:
43
57
  - erik.lott@kodio.io
@@ -50,12 +64,7 @@ files:
50
64
  - Rakefile
51
65
  - ioc.gemspec
52
66
  - lib/ioc.rb
53
- - lib/ioc/container.rb
54
- - lib/ioc/service_block.rb
55
- - lib/ioc/service_class.rb
56
- - lib/ioc/unresolvable_container.rb
57
- - spec/container_spec.rb
58
- - spec/spec_helper.rb
67
+ - spec/ioc_spec.rb
59
68
  homepage: ''
60
69
  licenses:
61
70
  - MIT
@@ -76,10 +85,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
85
  version: '0'
77
86
  requirements: []
78
87
  rubyforge_project:
79
- rubygems_version: 2.2.2
88
+ rubygems_version: 2.4.5
80
89
  signing_key:
81
90
  specification_version: 4
82
- summary: Minimal inversion of control container for Ruby
91
+ summary: Minimal dependency injection container for Ruby
83
92
  test_files:
84
- - spec/container_spec.rb
85
- - spec/spec_helper.rb
93
+ - spec/ioc_spec.rb
@@ -1,41 +0,0 @@
1
- require "ioc/service_class"
2
- require "ioc/service_block"
3
- require "ioc/unresolvable_container"
4
-
5
- module IOC
6
- class Container
7
- def initialize(parent=UnresolvableContainer.new, &block)
8
- @services = {}
9
- @cache = {}
10
- @parent = parent
11
-
12
- self.instance_eval(&block) if block_given?
13
- end
14
-
15
- def register(service_name, klass=nil, &block)
16
- raise(ArgumentError, "Service '#{service_name}' has already been registered") if @services.key?(service_name)
17
- @services[service_name] =
18
- if klass
19
- ServiceClass.new(klass)
20
- elsif block_given?
21
- ServiceBlock.new(block)
22
- else
23
- raise(ArgumentError, "expected service")
24
- end
25
- end
26
-
27
- def resolve(name)
28
- @cache[name] ||= service_locator(name)
29
- end
30
-
31
- def [](key)
32
- resolve(key)
33
- end
34
-
35
- private
36
-
37
- def service_locator(name)
38
- @services.key?(name) ? @services[name].resolve(self) : @parent.resolve(name)
39
- end
40
- end
41
- end
@@ -1,11 +0,0 @@
1
- module IOC
2
- class ServiceBlock
3
- def initialize(block)
4
- @block = block
5
- end
6
-
7
- def resolve(container)
8
- @block.call(container)
9
- end
10
- end
11
- end
@@ -1,16 +0,0 @@
1
- module IOC
2
- class ServiceClass
3
- def initialize(klass)
4
- klass.instance_method(:initialize)
5
- @klass = klass
6
- rescue NoMethodError => e
7
- raise(ArgumentError, "Expected initialize method on registered service")
8
- end
9
-
10
- def resolve(container)
11
- dependencies = @klass.instance_method(:initialize).parameters.map(&:last)
12
- resolved_dependencies = dependencies.map{ |dependency| container.resolve(dependency) }
13
- @klass.new(*resolved_dependencies)
14
- end
15
- end
16
- end
@@ -1,7 +0,0 @@
1
- module IOC
2
- class UnresolvableContainer
3
- def resolve(name)
4
- raise(ArgumentError, "Service '#{name}' not registered")
5
- end
6
- end
7
- end
@@ -1,130 +0,0 @@
1
- require "spec_helper"
2
- require "ioc"
3
-
4
- describe IOC::Container do
5
- context "when class is registered" do
6
- it "resolves a class instance" do
7
- container = define_container
8
- myclass = define_class
9
- container.register(:myclass, myclass)
10
- inst = container.resolve(:myclass)
11
- inst.must_be_instance_of(myclass)
12
- end
13
-
14
- it "caches resolved instance" do
15
- container = define_container
16
- myclass = define_class
17
- container.register(:myclass, myclass)
18
- inst1 = container.resolve(:myclass)
19
- inst2 = container.resolve(:myclass)
20
- inst1.must_equal(inst2)
21
- end
22
-
23
- context "when class has dependencies" do
24
- it "injects dependencies into instance" do
25
- container = define_container
26
-
27
- engine_class = define_class
28
- container.register(:engine, engine_class)
29
-
30
- car_class = define_class_with_engine_dependency
31
- container.register(:car, car_class)
32
-
33
- car = container.resolve(:car)
34
- car.engine.must_be_instance_of(engine_class)
35
- end
36
-
37
- it "caches dependencies" do
38
- container = define_container
39
-
40
- engine_class = define_class
41
- container.register(:engine, engine_class)
42
-
43
- car_class = define_class_with_engine_dependency
44
- container.register(:car, car_class)
45
-
46
- car = container.resolve(:car)
47
- engine = container.resolve(:engine)
48
-
49
- car.engine.must_equal(engine)
50
- end
51
- end
52
- end
53
-
54
- context "when block is registered" do
55
- it "returns result of block" do
56
- myobject = "a string object"
57
- container = define_container
58
- container.register(:myobject){|c| myobject }
59
- container.resolve(:myobject).must_equal(myobject)
60
- end
61
- end
62
-
63
- it "raises error when service not found" do
64
- container = define_container
65
- proc {
66
- container.resolve(:some_service)
67
- }.must_raise(ArgumentError)
68
- end
69
-
70
- it "raises error when service registered more than once" do
71
- myclass = define_class
72
- container = define_container
73
- container.register(:myclass, myclass)
74
- proc {
75
- container.register(:myclass, myclass)
76
- }.must_raise(ArgumentError)
77
- end
78
-
79
- it "raises error when object registered as class" do
80
- myclass = define_class
81
- myobject = myclass.new
82
- container = define_container
83
- proc {
84
- container.register(:myclass, myobject)
85
- }.must_raise(ArgumentError)
86
- end
87
-
88
- it "supports resolving via hash syntax" do
89
- container = define_container
90
- myclass = Class.new
91
- container.register(:myclass, myclass)
92
- inst = container[:myclass]
93
- inst.must_be_instance_of(myclass)
94
- end
95
-
96
- it "can resolve service from parent container" do
97
- myobject = Object.new
98
- parent_container = define_container
99
- parent_container.register(:myobject){ myobject }
100
-
101
- child_container = define_container(parent_container)
102
- child_container.resolve(:myobject).must_equal(myobject)
103
- end
104
-
105
- it "can be initialized with a block" do
106
- myobject = "a string object"
107
- container = define_container do
108
- register(:myobject){|c| myobject }
109
- end
110
- container.resolve(:myobject).must_equal(myobject)
111
- end
112
-
113
- def define_container(*args, &block)
114
- IOC::Container.new(*args, &block)
115
- end
116
-
117
- def define_class_with_engine_dependency
118
- Class.new do
119
- attr_reader :engine
120
-
121
- def initialize(engine)
122
- @engine = engine
123
- end
124
- end
125
- end
126
-
127
- def define_class
128
- Class.new
129
- end
130
- end
@@ -1,5 +0,0 @@
1
- require "minitest/autorun"
2
-
3
- def context *args, &block
4
- describe *args, &block
5
- end