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 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` (Objects that have no dependencies do not)
14
- need to include the module.
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; end
18
- class FacebookService; end
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(UserService)
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(User)
58
- user_service = container.get(UserService)
62
+ user = container.get(:user)
63
+ user_service = container.get(:user_service)
59
64
  ```
60
65
 
61
- Polymorphism is not supported since we don't have interfaces in Ruby. Setter
62
- injection is also not supported.
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
@@ -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 [ Class ] klass The type of the object to return.
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(klass)
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
@@ -29,7 +29,7 @@ module Injectable
29
29
  def dependencies(*injectables)
30
30
  define_constructor(*injectables)
31
31
  define_readers(*injectables)
32
- Registry.add(self, injectables)
32
+ Registry.register_signature(self, injectables)
33
33
  end
34
34
 
35
35
  private
@@ -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.add(UserService, [ :user, :user_finder ])
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 add(klass, dependencies)
22
- signatures[klass] = dependencies.map { |name| name.to_s.classify.constantize }
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
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Injectable
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
data/lib/injectable.rb CHANGED
@@ -26,6 +26,7 @@ module Injectable
26
26
  #
27
27
  # @since 0.0.0
28
28
  def included(klass)
29
+ Registry.register_implementation(klass.name.underscore.to_sym, klass)
29
30
  klass.extend(Macros)
30
31
  end
31
32
  end
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.1
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-11-20 00:00:00.000000000 Z
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: 3211559438392956621
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: 3211559438392956621
67
+ hash: -1472989141403557370
68
68
  requirements: []
69
69
  rubyforge_project:
70
70
  rubygems_version: 1.8.24