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 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