injectable 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +35 -9
- data/lib/injectable/container.rb +29 -2
- data/lib/injectable/macros.rb +1 -1
- data/lib/injectable/registry.rb +61 -3
- data/lib/injectable/version.rb +1 -1
- data/lib/injectable.rb +1 -0
- metadata +4 -4
data/README.md
CHANGED
@@ -10,12 +10,17 @@ Usage
|
|
10
10
|
|
11
11
|
Say we have a `UserService` that has some basic logic for performing operations
|
12
12
|
related to a `User` and a `FacebookService`. We can tell the `UserService` what
|
13
|
-
its dependencies are via `Injectable
|
14
|
-
|
13
|
+
its dependencies are via `Injectable`. Note that as of `0.0.2` all objects that
|
14
|
+
can be injecteed into others must include the `Injectable` module.
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
class User
|
18
|
-
|
17
|
+
class User
|
18
|
+
include Injectable
|
19
|
+
end
|
20
|
+
|
21
|
+
class FacebookService
|
22
|
+
include Injectable
|
23
|
+
end
|
19
24
|
|
20
25
|
class UserService
|
21
26
|
include Injectable
|
@@ -46,7 +51,7 @@ object of a specific type and let the container figure out the dependencies:
|
|
46
51
|
user = User.new
|
47
52
|
facebook_service = FacebookService.new
|
48
53
|
container = Injectable::Container.new(user, facebook_service)
|
49
|
-
user_service = container.get(
|
54
|
+
user_service = container.get(:user_service)
|
50
55
|
```
|
51
56
|
|
52
57
|
Since `User` and `FacebookService` take no arguments, we don't even need to
|
@@ -54,12 +59,30 @@ pass them into the container - it will automatically instantiate new ones:
|
|
54
59
|
|
55
60
|
```ruby
|
56
61
|
container = Injectable::Container.new
|
57
|
-
user = container.get(
|
58
|
-
user_service = container.get(
|
62
|
+
user = container.get(:user)
|
63
|
+
user_service = container.get(:user_service)
|
59
64
|
```
|
60
65
|
|
61
|
-
|
62
|
-
|
66
|
+
Injectable also supports depending on roles rather than concrete classes by
|
67
|
+
allowing the registration of classes whose instances perform that role:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
container = Injectable::Container.new
|
71
|
+
container.register_implementation(:facebook_service, DifferentFacebookService)
|
72
|
+
user_service = container.get(:user_service)
|
73
|
+
# `user_service`'s facebook_service will be an instance of DifferentFacebookService
|
74
|
+
```
|
75
|
+
|
76
|
+
You can also define concrete implementations at the global level:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Injectable::Registry.register_implementation(:facebook_service, DifferentFacebookService)
|
80
|
+
container = Injectable::Container.new
|
81
|
+
user_service = container.get(:user_service)
|
82
|
+
# `user_service`'s facebook_service will be an instance of DifferentFacebookService
|
83
|
+
```
|
84
|
+
|
85
|
+
Setter injection is not supported.
|
63
86
|
|
64
87
|
How about the real world
|
65
88
|
------------------------
|
@@ -68,9 +91,12 @@ Let's look at the above classes, but say we're in a Rails application:
|
|
68
91
|
|
69
92
|
```ruby
|
70
93
|
class User < ActiveRecord::Base
|
94
|
+
include Injectable
|
71
95
|
end
|
72
96
|
|
73
97
|
class FacebookService
|
98
|
+
include Injectable
|
99
|
+
|
74
100
|
def post_to_wall(id, message)
|
75
101
|
# ...
|
76
102
|
end
|
data/lib/injectable/container.rb
CHANGED
@@ -11,12 +11,16 @@ module Injectable
|
|
11
11
|
# @example Get an instance of an object for class UserService.
|
12
12
|
# container.get(UserService)
|
13
13
|
#
|
14
|
-
# @param [
|
14
|
+
# @param [ Symbol ] name the role which the returned object should perform.
|
15
15
|
#
|
16
16
|
# @return [ Object ] The instantiated object.
|
17
17
|
#
|
18
|
+
# @raise [ Injectable::RoleNotRegistered ] if queried for a role which is not
|
19
|
+
# registered
|
20
|
+
#
|
18
21
|
# @since 0.0.0
|
19
|
-
def get(
|
22
|
+
def get(name)
|
23
|
+
klass = implementing_class(name)
|
20
24
|
if instantiated_objects.has_key?(klass)
|
21
25
|
instantiated_objects[klass]
|
22
26
|
else
|
@@ -39,6 +43,21 @@ module Injectable
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
46
|
+
# Register that instances of klass will perform the given role in this
|
47
|
+
# container context.
|
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.
|
55
|
+
#
|
56
|
+
# @since 0.0.1
|
57
|
+
def register_implementation(name, klass)
|
58
|
+
implementing_classes[name] = klass
|
59
|
+
end
|
60
|
+
|
42
61
|
private
|
43
62
|
|
44
63
|
def dependencies(klass)
|
@@ -54,5 +73,13 @@ module Injectable
|
|
54
73
|
def instantiated_objects
|
55
74
|
@instantiated_objects ||= {}
|
56
75
|
end
|
76
|
+
|
77
|
+
def implementing_class(name)
|
78
|
+
implementing_classes[name] || Registry.implementation(name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def implementing_classes
|
82
|
+
@implementing_classes ||= {}
|
83
|
+
end
|
57
84
|
end
|
58
85
|
end
|
data/lib/injectable/macros.rb
CHANGED
data/lib/injectable/registry.rb
CHANGED
@@ -8,18 +8,49 @@ module Injectable
|
|
8
8
|
module Registry
|
9
9
|
extend self
|
10
10
|
|
11
|
+
# Get an implementation for the provided name.
|
12
|
+
#
|
13
|
+
# @example Get an implementation.
|
14
|
+
# Injectable::Registry.implementation(:persistable)
|
15
|
+
#
|
16
|
+
# @param [ Symbol ] name The name of the implementation.
|
17
|
+
#
|
18
|
+
# @return [ Class ] The implementing class.
|
19
|
+
#
|
20
|
+
# @since 0.0.2
|
21
|
+
def implementation(name)
|
22
|
+
implementations[name] || raise(NotRegistered.new(name))
|
23
|
+
end
|
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
|
38
|
+
end
|
39
|
+
|
11
40
|
# Add a constructor method signature to the registry.
|
12
41
|
#
|
13
42
|
# @example Add a signature.
|
14
|
-
# Injectable::Registry.
|
43
|
+
# Injectable::Registry.register_signature(
|
44
|
+
# UserService, [ :user, :user_finder ]
|
45
|
+
# )
|
15
46
|
#
|
16
47
|
# @param [ Class ] klass The class to set the constructor signature for.
|
17
48
|
# @param [ Array<Symbol> ] dependencies The dependencies of the
|
18
49
|
# constructor.
|
19
50
|
#
|
20
51
|
# @since 0.0.0
|
21
|
-
def
|
22
|
-
signatures[klass] = dependencies.map { |name| name
|
52
|
+
def register_signature(klass, dependencies)
|
53
|
+
signatures[klass] = dependencies.map { |name| name }
|
23
54
|
end
|
24
55
|
|
25
56
|
# Get the constructor method signature for the provided class.
|
@@ -36,8 +67,35 @@ module Injectable
|
|
36
67
|
signatures[klass]
|
37
68
|
end
|
38
69
|
|
70
|
+
# This error is raised when asking for an implementing class that is not
|
71
|
+
# registered in the registry.
|
72
|
+
#
|
73
|
+
# @since 0.0.2
|
74
|
+
class NotRegistered < Exception
|
75
|
+
|
76
|
+
# @attribute [r] name The name of the requested implementation.
|
77
|
+
attr_reader :name
|
78
|
+
|
79
|
+
# Initialize the new error.
|
80
|
+
#
|
81
|
+
# @example Initialize the error.
|
82
|
+
# NotRegistered.new(:persistable)
|
83
|
+
#
|
84
|
+
# @param [ Symbol ] name The name of the implementation.
|
85
|
+
#
|
86
|
+
# @since 0.0.2
|
87
|
+
def initialize(name)
|
88
|
+
@name = name
|
89
|
+
super("No implementation registered for name: #{name.inspect}.")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
39
93
|
private
|
40
94
|
|
95
|
+
def implementations
|
96
|
+
@implementations ||= {}
|
97
|
+
end
|
98
|
+
|
41
99
|
def signatures
|
42
100
|
@signatures ||= {}
|
43
101
|
end
|
data/lib/injectable/version.rb
CHANGED
data/lib/injectable.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.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -55,7 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
55
|
version: '0'
|
56
56
|
segments:
|
57
57
|
- 0
|
58
|
-
hash:
|
58
|
+
hash: -1472989141403557370
|
59
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
60
|
none: false
|
61
61
|
requirements:
|
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
64
|
version: '0'
|
65
65
|
segments:
|
66
66
|
- 0
|
67
|
-
hash:
|
67
|
+
hash: -1472989141403557370
|
68
68
|
requirements: []
|
69
69
|
rubyforge_project:
|
70
70
|
rubygems_version: 1.8.24
|