injectable 0.0.1 → 0.0.2
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/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
|