injectable 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +43 -2
- data/lib/injectable.rb +5 -2
- data/lib/injectable/container.rb +47 -24
- data/lib/injectable/inflector.rb +30 -0
- data/lib/injectable/registerable.rb +26 -0
- data/lib/injectable/registry.rb +6 -20
- data/lib/injectable/version.rb +1 -1
- metadata +8 -21
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Durran Jordan
|
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.
|
data/README.md
CHANGED
@@ -86,6 +86,47 @@ user_service = container.get(:user_service)
|
|
86
86
|
# `user_service`'s facebook_service will be an instance of DifferentFacebookService
|
87
87
|
```
|
88
88
|
|
89
|
+
Multiple implementations for the same role can be configured - the rules on how
|
90
|
+
they will be used are as follows: Check for an already instantiated instance in
|
91
|
+
the container. If one or both exist, take the first. If none exist, then attempt to
|
92
|
+
resolve the dependency with each registered role until one succeeds. An example:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
module Portable
|
96
|
+
def charge
|
97
|
+
# Some logic here.
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Phone
|
102
|
+
include Injectable
|
103
|
+
include Portable
|
104
|
+
end
|
105
|
+
|
106
|
+
class Tablet
|
107
|
+
include Injectable
|
108
|
+
include Portable
|
109
|
+
end
|
110
|
+
|
111
|
+
class Application
|
112
|
+
include Injectable
|
113
|
+
dependencies :portable
|
114
|
+
end
|
115
|
+
|
116
|
+
Injectable.configure do |config|
|
117
|
+
config.register_implementation(:portable, Phone, Tablet)
|
118
|
+
end
|
119
|
+
|
120
|
+
container = Injectable::Container.new
|
121
|
+
application = container.get(:application)
|
122
|
+
application.portable #=> Returns a new Phone.
|
123
|
+
|
124
|
+
tablet = Tablet.new
|
125
|
+
container = Injectable::Container.new(tablet)
|
126
|
+
application = container.get(:application)
|
127
|
+
application.portable #=> Returns the existing instance of a Tablet.
|
128
|
+
```
|
129
|
+
|
89
130
|
Setter injection is not supported.
|
90
131
|
|
91
132
|
How about the real world
|
@@ -124,8 +165,8 @@ related to what one might do in a real application.
|
|
124
165
|
class UsersController < ApplicationController
|
125
166
|
|
126
167
|
def post_to_wall
|
127
|
-
container.get(
|
128
|
-
respond_with container.get(
|
168
|
+
container.get(:user_service).post_to_wall(params[:message])
|
169
|
+
respond_with container.get(:user)
|
129
170
|
end
|
130
171
|
|
131
172
|
private
|
data/lib/injectable.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "active_support/inflector"
|
3
2
|
require "injectable/container"
|
3
|
+
require "injectable/inflector"
|
4
4
|
require "injectable/macros"
|
5
5
|
require "injectable/registry"
|
6
6
|
|
@@ -41,7 +41,10 @@ module Injectable
|
|
41
41
|
#
|
42
42
|
# @since 0.0.0
|
43
43
|
def included(klass)
|
44
|
-
Registry.register_implementation(
|
44
|
+
Registry.register_implementation(
|
45
|
+
Inflector.underscore(klass.name).to_sym,
|
46
|
+
klass
|
47
|
+
)
|
45
48
|
klass.extend(Macros)
|
46
49
|
end
|
47
50
|
end
|
data/lib/injectable/container.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require "injectable/registerable"
|
3
|
+
|
2
4
|
module Injectable
|
3
5
|
|
4
6
|
# A simple container that can resolve dependencies.
|
5
7
|
#
|
6
8
|
# @since 0.0.0
|
7
9
|
class Container
|
10
|
+
include Registerable
|
8
11
|
|
9
12
|
# Get an instance of an object from the container with the provided class.
|
10
13
|
#
|
11
14
|
# @example Get an instance of an object for class UserService.
|
12
|
-
# container.get(
|
15
|
+
# container.get(:user_service)
|
13
16
|
#
|
14
17
|
# @param [ Symbol ] name the role which the returned object should perform.
|
15
18
|
#
|
@@ -20,11 +23,12 @@ module Injectable
|
|
20
23
|
#
|
21
24
|
# @since 0.0.0
|
22
25
|
def get(name)
|
23
|
-
|
24
|
-
if
|
26
|
+
classes = registered_implementations(name)
|
27
|
+
if klass = instantiated_class(classes)
|
25
28
|
instantiated_objects[klass]
|
26
29
|
else
|
27
|
-
|
30
|
+
object = instantiate(classes)
|
31
|
+
instantiated_objects[object.class] = object
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
@@ -43,19 +47,31 @@ module Injectable
|
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# @example Register that the user_finder role will be performed by
|
50
|
-
# instances of DatabaseUserFinder
|
51
|
-
# container.register_implementation(:user_finder, DatabaseUserFinder)
|
52
|
-
#
|
53
|
-
# @param [ Symbol ] name The name of the role.
|
54
|
-
# @param [ Class ] klass The name of the class performing this role.
|
50
|
+
# This error is raised when asking for an object out of the container that
|
51
|
+
# cannot be resolved.
|
55
52
|
#
|
56
|
-
# @since 0.0.
|
57
|
-
|
58
|
-
|
53
|
+
# @since 0.0.4
|
54
|
+
class Unresolvable < Exception
|
55
|
+
|
56
|
+
# @attribute [r] classes The classes that were attempted to instantiate.
|
57
|
+
attr_reader :classes
|
58
|
+
|
59
|
+
# Initialize the new error.
|
60
|
+
#
|
61
|
+
# @example Initialize the error.
|
62
|
+
# Unresolvable.new([ Persistable, Saveable ])
|
63
|
+
#
|
64
|
+
# @param [ Array<Class> ] classes The classes that were attempted to
|
65
|
+
# instantiate with.
|
66
|
+
#
|
67
|
+
# @since 0.0.4
|
68
|
+
def initialize(classes)
|
69
|
+
@classes = classes
|
70
|
+
super(
|
71
|
+
"Could not instantiate an object for any of: #{classes.join(", ")}. " +
|
72
|
+
"Please ensure all required dependencies are in the container."
|
73
|
+
)
|
74
|
+
end
|
59
75
|
end
|
60
76
|
|
61
77
|
private
|
@@ -66,20 +82,27 @@ module Injectable
|
|
66
82
|
end
|
67
83
|
end
|
68
84
|
|
69
|
-
def
|
70
|
-
|
85
|
+
def registered_implementations(name)
|
86
|
+
implementations[name] || Registry.implementation(name)
|
71
87
|
end
|
72
88
|
|
73
|
-
def
|
74
|
-
|
89
|
+
def instantiate(classes)
|
90
|
+
classes.each do |klass|
|
91
|
+
begin
|
92
|
+
return klass.new(*dependencies(klass))
|
93
|
+
rescue ArgumentError; end
|
94
|
+
end
|
95
|
+
raise Unresolvable.new(classes)
|
75
96
|
end
|
76
97
|
|
77
|
-
def
|
78
|
-
|
98
|
+
def instantiated_objects
|
99
|
+
@instantiated_objects ||= {}
|
79
100
|
end
|
80
101
|
|
81
|
-
def
|
82
|
-
|
102
|
+
def instantiated_class(classes)
|
103
|
+
classes.detect do |klass|
|
104
|
+
instantiated_objects[klass]
|
105
|
+
end
|
83
106
|
end
|
84
107
|
end
|
85
108
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Injectable
|
3
|
+
|
4
|
+
# Used so we don't need active support around to perform inflections.
|
5
|
+
#
|
6
|
+
# @since 0.0.4
|
7
|
+
module Inflector
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Underscore a string. This is partially taken from Active Support, but
|
12
|
+
# dumbed down for our purposes - we don't handle namespacing.
|
13
|
+
#
|
14
|
+
# @example Underscore a string.
|
15
|
+
# Inflector.underscore("Band")
|
16
|
+
#
|
17
|
+
# @param [ String ] string The string to underscore.
|
18
|
+
#
|
19
|
+
# @since 0.0.4
|
20
|
+
#
|
21
|
+
# @return [ String ] The underscored string.
|
22
|
+
def underscore(string)
|
23
|
+
value = string.dup
|
24
|
+
value.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
25
|
+
value.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
26
|
+
value.downcase!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Injectable
|
3
|
+
module Registerable
|
4
|
+
|
5
|
+
# Register that instances of klass will perform the given role in this
|
6
|
+
# container context.
|
7
|
+
#
|
8
|
+
# @example Register that the user_finder role will be performed by
|
9
|
+
# instances of DatabaseUserFinder
|
10
|
+
# container.register_implementation(:user_finder, DatabaseUserFinder)
|
11
|
+
#
|
12
|
+
# @param [ Symbol ] name The name of the role.
|
13
|
+
# @param [ *Class ] classes The names of the classes performing this role.
|
14
|
+
#
|
15
|
+
# @since 0.0.1
|
16
|
+
def register_implementation(name, *classes)
|
17
|
+
implementations[name] = classes.flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def implementations
|
23
|
+
@implementations ||= {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/injectable/registry.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
require "injectable/registerable"
|
3
|
+
|
2
4
|
module Injectable
|
3
5
|
|
4
6
|
# The registry keeps track of all objects and their dependencies that need
|
@@ -6,6 +8,7 @@ module Injectable
|
|
6
8
|
#
|
7
9
|
# @since 0.0.0
|
8
10
|
module Registry
|
11
|
+
include Registerable
|
9
12
|
extend self
|
10
13
|
|
11
14
|
# Get an implementation for the provided name.
|
@@ -19,22 +22,9 @@ module Injectable
|
|
19
22
|
#
|
20
23
|
# @since 0.0.2
|
21
24
|
def implementation(name)
|
22
|
-
implementations[name]
|
23
|
-
|
24
|
-
|
25
|
-
# Add an implementing class for a name to the registry.
|
26
|
-
#
|
27
|
-
# @example Add an implementation.
|
28
|
-
# Injectable::Registry.register_implementation(
|
29
|
-
# :persistable, User
|
30
|
-
# )
|
31
|
-
#
|
32
|
-
# @param [ Symbol ] name The name of the implementation.
|
33
|
-
# @param [ Class ] klass The implementing class.
|
34
|
-
#
|
35
|
-
# @since 0.0.2
|
36
|
-
def register_implementation(name, klass)
|
37
|
-
implementations[name] = klass
|
25
|
+
impl = implementations[name]
|
26
|
+
raise(NotRegistered.new(name)) unless impl && !impl.empty?
|
27
|
+
impl
|
38
28
|
end
|
39
29
|
|
40
30
|
# Add a constructor method signature to the registry.
|
@@ -92,10 +82,6 @@ module Injectable
|
|
92
82
|
|
93
83
|
private
|
94
84
|
|
95
|
-
def implementations
|
96
|
-
@implementations ||= {}
|
97
|
-
end
|
98
|
-
|
99
85
|
def signatures
|
100
86
|
@signatures ||= {}
|
101
87
|
end
|
data/lib/injectable/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: injectable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: activesupport
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '3'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '3'
|
12
|
+
date: 2013-01-17 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
30
14
|
description: Dead simple Ruby dependency injection
|
31
15
|
email:
|
32
16
|
- durran@gmail.com
|
@@ -35,11 +19,14 @@ extensions: []
|
|
35
19
|
extra_rdoc_files: []
|
36
20
|
files:
|
37
21
|
- lib/injectable/container.rb
|
22
|
+
- lib/injectable/inflector.rb
|
38
23
|
- lib/injectable/macros.rb
|
24
|
+
- lib/injectable/registerable.rb
|
39
25
|
- lib/injectable/registry.rb
|
40
26
|
- lib/injectable/version.rb
|
41
27
|
- lib/injectable.rb
|
42
28
|
- README.md
|
29
|
+
- LICENSE
|
43
30
|
- Rakefile
|
44
31
|
homepage:
|
45
32
|
licenses: []
|
@@ -55,7 +42,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
42
|
version: '0'
|
56
43
|
segments:
|
57
44
|
- 0
|
58
|
-
hash:
|
45
|
+
hash: 1285461619687616243
|
59
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
47
|
none: false
|
61
48
|
requirements:
|
@@ -64,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
51
|
version: '0'
|
65
52
|
segments:
|
66
53
|
- 0
|
67
|
-
hash:
|
54
|
+
hash: 1285461619687616243
|
68
55
|
requirements: []
|
69
56
|
rubyforge_project:
|
70
57
|
rubygems_version: 1.8.24
|