scorpion-ioc 0.6.2 → 1.0.0

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +144 -30
  3. data/Gemfile +17 -13
  4. data/README.md +24 -69
  5. data/Rakefile +12 -0
  6. data/app/README +1 -0
  7. data/bin/rspec +2 -1
  8. data/config.ru +2 -2
  9. data/config/environment.rb +1 -0
  10. data/lib/scorpion-ioc.rb +3 -1
  11. data/lib/scorpion.rb +32 -45
  12. data/lib/scorpion/attribute.rb +14 -34
  13. data/lib/scorpion/attribute_set.rb +11 -13
  14. data/lib/scorpion/chain_hunter.rb +4 -4
  15. data/lib/scorpion/dependency.rb +22 -58
  16. data/lib/scorpion/dependency/argument_dependency.rb +4 -4
  17. data/lib/scorpion/dependency/builder_dependency.rb +5 -5
  18. data/lib/scorpion/dependency/captured_dependency.rb +4 -6
  19. data/lib/scorpion/dependency/class_dependency.rb +3 -17
  20. data/lib/scorpion/dependency/module_dependency.rb +1 -1
  21. data/lib/scorpion/dependency_map.rb +16 -16
  22. data/lib/scorpion/error.rb +12 -9
  23. data/lib/scorpion/hunt.rb +33 -34
  24. data/lib/scorpion/hunter.rb +6 -6
  25. data/lib/scorpion/locale/en.yml +2 -2
  26. data/lib/scorpion/method.rb +11 -1
  27. data/lib/scorpion/object.rb +16 -31
  28. data/lib/scorpion/rack.rb +1 -1
  29. data/lib/scorpion/rack/middleware.rb +2 -1
  30. data/lib/scorpion/rails.rb +6 -6
  31. data/lib/scorpion/rails/active_record.rb +4 -4
  32. data/lib/scorpion/rails/active_record/association.rb +3 -3
  33. data/lib/scorpion/rails/active_record/relation.rb +3 -2
  34. data/lib/scorpion/rails/controller.rb +2 -2
  35. data/lib/scorpion/rails/job.rb +1 -1
  36. data/lib/scorpion/rails/mailer.rb +1 -1
  37. data/lib/scorpion/rails/nest.rb +11 -11
  38. data/lib/scorpion/rails/railtie.rb +2 -2
  39. data/lib/scorpion/rspec.rb +2 -2
  40. data/lib/scorpion/rspec/helper.rb +3 -3
  41. data/lib/scorpion/stinger.rb +19 -18
  42. data/lib/scorpion/version.rb +3 -3
  43. data/scorpion.gemspec +13 -13
  44. data/spec/internal/db/schema.rb +1 -1
  45. data/spec/lib/scorpion/attribute_set_spec.rb +4 -22
  46. data/spec/lib/scorpion/attribute_spec.rb +3 -8
  47. data/spec/lib/scorpion/chain_hunter_spec.rb +1 -1
  48. data/spec/lib/scorpion/dependency/argument_dependency_spec.rb +3 -7
  49. data/spec/lib/scorpion/dependency/builder_dependency_spec.rb +7 -7
  50. data/spec/lib/scorpion/dependency/module_dependency_spec.rb +3 -3
  51. data/spec/lib/scorpion/dependency_map_spec.rb +4 -25
  52. data/spec/lib/scorpion/dependency_spec.rb +18 -45
  53. data/spec/lib/scorpion/error_spec.rb +1 -1
  54. data/spec/lib/scorpion/hunt_spec.rb +16 -28
  55. data/spec/lib/scorpion/hunter_spec.rb +29 -21
  56. data/spec/lib/scorpion/object_spec.rb +20 -19
  57. data/spec/lib/scorpion/rack/middleware_spec.rb +4 -4
  58. data/spec/lib/scorpion/rack_spec.rb +1 -1
  59. data/spec/lib/scorpion/rails/active_record/association_spec.rb +3 -3
  60. data/spec/lib/scorpion/rails/active_record/model_spec.rb +3 -3
  61. data/spec/lib/scorpion/rails/active_record/relation_spec.rb +3 -3
  62. data/spec/lib/scorpion/rails/controller_spec.rb +8 -8
  63. data/spec/lib/scorpion/rails/job_spec.rb +1 -1
  64. data/spec/lib/scorpion/rspec/helper_spec.rb +11 -11
  65. data/spec/lib/scorpion_spec.rb +1 -1
  66. data/spec/spec_helper.rb +8 -10
  67. metadata +6 -6
  68. data/lib/scorpion/object_constructor.rb +0 -79
  69. data/spec/lib/scorpion/object_constructor_spec.rb +0 -124
@@ -1,23 +1,23 @@
1
- require 'i18n'
1
+ require "i18n"
2
2
 
3
3
  module Scorpion
4
4
  class Error < StandardError
5
5
 
6
6
  private
7
- def translate( key, args = {} )
8
- I18n.translate key, args.merge( scope: [:scorpion,:errors,:messages] )
7
+
8
+ def translate( key, **args )
9
+ I18n.translate key, args.merge( scope: [:scorpion, :errors, :messages] )
9
10
  end
11
+
10
12
  end
11
13
 
12
14
  class UnsuccessfulHunt < Error
13
15
  attr_reader :contract
14
- attr_reader :traits
15
16
 
16
- def initialize( contract, traits = nil )
17
+ def initialize( contract )
17
18
  @contract = contract
18
- @traits = traits
19
19
 
20
- super translate( :unsuccessful_hunt, contract: contract, traits: traits )
20
+ super translate( :unsuccessful_hunt, contract: contract )
21
21
  end
22
22
  end
23
23
 
@@ -36,10 +36,13 @@ module Scorpion
36
36
  class ContractMismatchError < Error
37
37
  def initialize( message_or_module = nil, initializer_attr = nil, injected_attr = nil )
38
38
  if message_or_module.is_a?( Module )
39
- super translate( :contract_mismatch, module: message_or_module, name: initializer_attr.name, from: initializer_attr.contract, to: injected_attr.contract )
39
+ super translate( :contract_mismatch, module: message_or_module,
40
+ name: initializer_attr.name,
41
+ from: initializer_attr.contract,
42
+ to: injected_attr.contract )
40
43
  else
41
44
  super ( message || translate( :contract_mismatch ) )
42
45
  end
43
46
  end
44
47
  end
45
- end
48
+ end
data/lib/scorpion/hunt.rb CHANGED
@@ -45,17 +45,11 @@ module Scorpion
45
45
  attr_reader :trip
46
46
  private :trip
47
47
 
48
- delegate [:contract, :traits, :dependencies, :arguments, :block] => :trip
48
+ delegate [:contract, :arguments, :block] => :trip
49
49
 
50
50
  # @!attribute contract
51
51
  # @return [Class,Module,Symbol] contract being hunted for.
52
52
 
53
- # @!attribute traits
54
- # @return [Array<Symbol>] traits being hunted for.
55
-
56
- # @!attribute [r] dependencies
57
- # @return [Hash<Symbol,Dependency>] hash of dependencies to pass to initializer of {#contract} when found.
58
-
59
53
  # @!attribute [r] arguments
60
54
  # @return [Array<Object>] positional arguments to pass to the initializer of {#contract} when found.
61
55
 
@@ -65,22 +59,16 @@ module Scorpion
65
59
  #
66
60
  # @!endgroup Attributes
67
61
 
68
- def initialize( scorpion, contract, traits, *arguments, **dependencies, &block )
62
+ def initialize( scorpion, contract, *arguments, &block )
69
63
  @scorpion = scorpion
70
64
  @trips = []
71
- @trip = Trip.new contract, traits, arguments, dependencies, block
65
+ @trip = Trip.new contract, arguments, block
72
66
  end
73
67
 
74
- # Hunt for additional dependency to satisfy the main hunt's contract and traits.
68
+ # Hunt for additional dependency to satisfy the main hunt's contract.
75
69
  # @see Scorpion#hunt
76
- def fetch( contract, *arguments, **dependencies, &block )
77
- fetch_by_traits( contract, nil, *arguments, **dependencies, &block )
78
- end
79
-
80
- # Hunt for additional dependency to satisfy the main hunt's contract and traits.
81
- # @see Scorpion#hunt
82
- def fetch_by_traits( contract, traits, *arguments, **dependencies, &block )
83
- push contract, traits, arguments, dependencies, block
70
+ def fetch( contract, *arguments, &block )
71
+ push contract, arguments, block
84
72
  execute
85
73
  ensure
86
74
  pop
@@ -91,12 +79,13 @@ module Scorpion
91
79
  # @return [Scorpion::Object] the injected object.
92
80
  def inject( object )
93
81
  trip.object = object
82
+ object.send :scorpion_hunt=, self
94
83
 
95
84
  object.injected_attributes.each do |attr|
96
85
  next if object.send "#{ attr.name }?"
97
86
  next if attr.lazy?
98
87
 
99
- object.send :inject_dependency, attr, fetch_by_traits( attr.contract, attr.traits )
88
+ object.send :inject_dependency, attr, fetch( attr.contract )
100
89
  end
101
90
 
102
91
  object.send :on_injected
@@ -106,8 +95,8 @@ module Scorpion
106
95
 
107
96
  # Allow the hunt to spawn objects.
108
97
  # @see Scorpion#spawn
109
- def spawn( klass, *arguments, **dependencies, &block )
110
- scorpion.spawn( self, klass, *arguments, **dependencies, &block )
98
+ def spawn( klass, *arguments, &block )
99
+ scorpion.spawn( self, klass, *arguments, &block )
111
100
  end
112
101
  alias_method :new, :spawn
113
102
 
@@ -118,12 +107,26 @@ module Scorpion
118
107
  end
119
108
 
120
109
  def execute_from_trips
121
- return if dependencies.any?
122
-
123
110
  trips.each do |trip|
124
- return trip.object if contract === trip.object
125
- trip.dependencies.each do |key,value|
126
- return value if contract === value
111
+ if resolved = execute_from_trip( trip )
112
+ return resolved
113
+ end
114
+ end
115
+
116
+ nil
117
+ end
118
+
119
+ def execute_from_trip( trip )
120
+ return unless obj = trip.object
121
+ return obj if contract === obj
122
+
123
+ # If we have already resolved an instance of this contract in this
124
+ # hunt, then return that same object.
125
+ if obj.is_a? Scorpion::Object
126
+ obj.injected_attributes.each do |attr|
127
+ next unless attr.contract == contract
128
+
129
+ return obj.send( attr.name ) if obj.send( :"#{ attr.name }?" )
127
130
  end
128
131
  end
129
132
 
@@ -134,10 +137,10 @@ module Scorpion
134
137
  scorpion.execute self
135
138
  end
136
139
 
137
- def push( contract, traits, arguments, dependencies, block )
140
+ def push( contract, arguments, block )
138
141
  trips.push trip
139
142
 
140
- @trip = Trip.new contract, traits, arguments, dependencies, block
143
+ @trip = Trip.new contract, arguments, block
141
144
  end
142
145
 
143
146
  def pop
@@ -146,22 +149,18 @@ module Scorpion
146
149
 
147
150
  class Trip
148
151
  attr_reader :contract
149
- attr_reader :traits
150
152
  attr_reader :arguments
151
- attr_reader :dependencies
152
153
  attr_reader :block
153
154
 
154
155
  attr_accessor :object
155
156
 
156
- def initialize( contract, traits, arguments, dependencies, block )
157
+ def initialize( contract, arguments, block )
157
158
  @contract = contract
158
- @traits = traits
159
159
  @arguments = arguments
160
- @dependencies = dependencies
161
160
  @block = block
162
161
  end
163
162
  end
164
163
 
165
164
  class InitializerTrip < Trip; end
166
165
  end
167
- end
166
+ end
@@ -33,8 +33,8 @@ module Scorpion
33
33
  end
34
34
 
35
35
  # Expose dependency injection definitions as top-level methods.
36
- [:hunt_for,:capture,:share].each do |delegate|
37
- define_method delegate do |*args,&block|
36
+ [:hunt_for, :capture, :share].each do |delegate|
37
+ define_method delegate do |*args, &block|
38
38
  prepare do |hunter|
39
39
  hunter.send delegate, *args, &block
40
40
  end
@@ -51,9 +51,9 @@ module Scorpion
51
51
  # @see Scorpion#execute
52
52
  def execute( hunt, explicit_only = false )
53
53
  dependency = find_dependency( hunt )
54
- dependency ||= Dependency.define( hunt.contract ) if hunt.traits.blank? && !explicit_only
54
+ dependency ||= Dependency.define( hunt.contract ) unless explicit_only
55
55
 
56
- unsuccessful_hunt( hunt.contract, hunt.traits ) unless dependency
56
+ unsuccessful_hunt( hunt.contract ) unless dependency
57
57
 
58
58
  dependency.fetch hunt
59
59
  end
@@ -62,7 +62,7 @@ module Scorpion
62
62
  # @param [Hunt] hunt being resolved.
63
63
  # @return [Dependency] the matching dependency if found
64
64
  def find_dependency( hunt )
65
- dependency = dependency_map.find( hunt.contract, hunt.traits )
65
+ dependency = dependency_map.find( hunt.contract )
66
66
  dependency ||= parent.find_dependency( hunt ) if parent
67
67
 
68
68
  dependency
@@ -83,4 +83,4 @@ module Scorpion
83
83
  end
84
84
 
85
85
  end
86
- end
86
+ end
@@ -2,11 +2,11 @@ en:
2
2
  scorpion:
3
3
  errors:
4
4
  messages:
5
- unsuccessful_hunt: "Couldn't find a %{contract} builder with traits '%{traits}'"
5
+ unsuccessful_hunt: "Couldn't find a %{contract} builder"
6
6
  builder_required: A custom builder must be provided to resolve this dependency
7
7
  arity_mismatch: The block must accept %{expected} arguments, but actually expects %{actual}
8
8
  rack_missing_scorpion: Scorpion not set. Add Scorpion::Rack::Middleware before %{middleware}.
9
9
  contract_mismatch: "%{module} changed the contract for `%{name}` from `%{from}` to `%{to}` but did not update `initialize` block."
10
10
  warnings:
11
11
  messages:
12
- mixed_scorpions: A scorpion has already been assigned. Mixing scorpions can result in unexpected results.
12
+ mixed_scorpions: A scorpion has already been assigned. Mixing scorpions can result in unexpected results.
@@ -20,5 +20,15 @@ module Scorpion
20
20
  @scorpion = value
21
21
  end
22
22
 
23
+ # @!attribute
24
+ # @return [Hunt] the scorpion hunt that captured the object.
25
+ def scorpion_hunt
26
+ @scorpion_hunt
27
+ end
28
+
29
+ private def scorpion_hunt=( hunt )
30
+ @scorpion_hunt = hunt
31
+ end
32
+
23
33
  end
24
- end
34
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/attribute_set'
1
+ require "scorpion/attribute_set"
2
2
 
3
3
  module Scorpion
4
4
  # Identifies objects that are injected by {Scorpion scorpions} that inject
@@ -41,15 +41,8 @@ module Scorpion
41
41
  # Create a new instance of this class with all non-lazy dependencies
42
42
  # satisfied.
43
43
  # @param [Hunt] hunt that this instance will be used to satisfy.
44
- def self.spawn( hunt, *args, **dependencies, &block )
45
- object =
46
- if dependencies.any?
47
- new( *args, **dependencies, &block )
48
- else
49
- new( *args, &block )
50
- end
51
-
52
-
44
+ def self.spawn( hunt, *args, &block )
45
+ object = new( *args, &block )
53
46
  object.send :scorpion=, hunt.scorpion
54
47
 
55
48
  # Go hunt for dependencies that are not lazy and initialize the
@@ -92,8 +85,8 @@ module Scorpion
92
85
  injected_attributes.each do |attr|
93
86
  next unless dependencies.key? attr.name
94
87
 
95
- if overwrite || !self.send( "#{ attr.name }?" )
96
- self.send( "#{ attr.name }=", dependencies[ attr.name ] )
88
+ if overwrite || !send( "#{ attr.name }?" )
89
+ send( "#{ attr.name }=", dependencies[ attr.name ] )
97
90
  end
98
91
  end
99
92
 
@@ -107,8 +100,8 @@ module Scorpion
107
100
  next unless dependencies.key? attr.name
108
101
  val = dependencies.delete( attr.name )
109
102
 
110
- if overwrite || !self.send( "#{ attr.name }?" )
111
- self.send( "#{ attr.name }=", val )
103
+ if overwrite || !send( "#{ attr.name }?" )
104
+ send( "#{ attr.name }=", val )
112
105
  end
113
106
  end
114
107
 
@@ -117,18 +110,10 @@ module Scorpion
117
110
 
118
111
  module ClassMethods
119
112
 
120
- # Define an initializer that accepts injections.
121
- # @param [Hash] arguments to accept in the initializer.
122
- # @yield to initialize itself.
123
- def initialize( arguments = {}, &block )
124
- Scorpion::ObjectConstructor.new( self, arguments, &block ).define
125
- end
126
-
127
113
  # Tells a {Scorpion} what to inject into the class when it is constructed
128
114
  # @return [nil]
129
115
  # @see AttributeSet#define
130
- def depend_on( arguments = nil, &block )
131
- Scorpion::ObjectConstructor.new( self, arguments ).define if arguments.present?
116
+ def depend_on( &block )
132
117
  injected_attributes.define &block
133
118
  build_injected_attributes
134
119
  validate_initializer_injections
@@ -137,11 +122,10 @@ module Scorpion
137
122
  # Define a single dependency and accessor.
138
123
  # @param [Symbol] name of the dependency.
139
124
  # @param [Class,Module,Symbol] contract describing the desired behavior of the dependency.
140
- # @param [Array<Symbol>] traits found on the {Dependency}.
141
- def attr_dependency( name, contract, *traits, &block )
142
- attr = injected_attributes.define_attribute name, contract, *traits, &block
125
+ def attr_dependency( name, contract, &block )
126
+ attr = injected_attributes.define_attribute name, contract, &block
143
127
  build_injected_attribute attr
144
- set_injected_attribute_visibility attr
128
+ adjust_injected_attribute_visibility attr
145
129
  validate_initializer_injections
146
130
  attr
147
131
  end
@@ -169,6 +153,7 @@ module Scorpion
169
153
  end
170
154
 
171
155
  private
156
+
172
157
  def validate_initializer_injections
173
158
  initializer_injections.each do |attr|
174
159
  injected = injected_attributes[ attr.name ]
@@ -181,7 +166,7 @@ module Scorpion
181
166
  def build_injected_attributes
182
167
  injected_attributes.each do |attr|
183
168
  build_injected_attribute attr
184
- set_injected_attribute_visibility attr
169
+ adjust_injected_attribute_visibility attr
185
170
  end
186
171
  end
187
172
 
@@ -190,7 +175,7 @@ module Scorpion
190
175
  def #{ attr.name }
191
176
  @#{ attr.name } ||= begin
192
177
  attr = injected_attributes[ :#{ attr.name } ]
193
- scorpion.fetch_by_traits( attr.contract, attr.traits )
178
+ ( scorpion_hunt || scorpion ).fetch( attr.contract )
194
179
  end
195
180
  end
196
181
 
@@ -204,7 +189,7 @@ module Scorpion
204
189
  RUBY
205
190
  end
206
191
 
207
- def set_injected_attribute_visibility( attr )
192
+ def adjust_injected_attribute_visibility( attr )
208
193
  unless attr.public?
209
194
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
210
195
  private :#{ attr.name }=
@@ -220,4 +205,4 @@ module Scorpion
220
205
  end
221
206
  end
222
207
  end
223
- end
208
+ end
data/lib/scorpion/rack.rb CHANGED
@@ -5,7 +5,7 @@ module Scorpion
5
5
  private
6
6
 
7
7
  def scorpion( env )
8
- env[ Middleware::ENV_KEY ] || fail( MissingScorpionError.new( self.class.name ) )
8
+ env[ Middleware::ENV_KEY ] || fail( MissingScorpionError, self.class.name )
9
9
  end
10
10
  end
11
11
  end
@@ -4,7 +4,7 @@ module Scorpion
4
4
  module Rack
5
5
  class Middleware
6
6
 
7
- ENV_KEY = 'scorpion.rack.instance'.freeze
7
+ ENV_KEY = "scorpion.rack.instance".freeze
8
8
 
9
9
  def initialize( app, nest = nil )
10
10
  @app = app
@@ -19,6 +19,7 @@ module Scorpion
19
19
  end
20
20
 
21
21
  private
22
+
22
23
  attr_reader :nest
23
24
 
24
25
  def prepare_scorpion( scorpion, env )
@@ -1,10 +1,10 @@
1
1
  module Scorpion
2
2
  module Rails
3
- require 'scorpion/rails/nest'
4
- require 'scorpion/rails/job'
5
- require 'scorpion/rails/mailer'
6
- require 'scorpion/rails/active_record'
7
- require 'scorpion/rails/controller'
8
- require 'scorpion/rails/railtie'
3
+ require "scorpion/rails/nest"
4
+ require "scorpion/rails/job"
5
+ require "scorpion/rails/mailer"
6
+ require "scorpion/rails/active_record"
7
+ require "scorpion/rails/controller"
8
+ require "scorpion/rails/railtie"
9
9
  end
10
10
  end
@@ -1,9 +1,9 @@
1
1
  module Scorpion
2
2
  module Rails
3
3
  module ActiveRecord
4
- require 'scorpion/rails/active_record/model'
5
- require 'scorpion/rails/active_record/relation'
6
- require 'scorpion/rails/active_record/association'
4
+ require "scorpion/rails/active_record/model"
5
+ require "scorpion/rails/active_record/relation"
6
+ require "scorpion/rails/active_record/association"
7
7
 
8
8
  # Setup scorpion support for activerecord
9
9
  def self.install!
@@ -13,7 +13,7 @@ module Scorpion
13
13
  ::ActiveRecord::Relation.send :prepend, Scorpion::Rails::ActiveRecord::Relation
14
14
  ::ActiveRecord::Associations::Association.send :prepend, Scorpion::Rails::ActiveRecord::Association
15
15
 
16
- # TODO extend Scorpion::Hunter to support AR
16
+ # TODO: extend Scorpion::Hunter to support AR
17
17
  end
18
18
  end
19
19
  end
@@ -46,11 +46,11 @@ module Scorpion
46
46
  next unless klass.instance_methods.include? method
47
47
 
48
48
  mod = Module.new do
49
- module_eval <<-EOS, __FILE__, __LINE__ + 1
49
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
50
50
  def #{ method }( *args, &block )
51
51
  sting! super
52
52
  end
53
- EOS
53
+ RUBY
54
54
  end
55
55
 
56
56
  klass.prepend mod
@@ -61,4 +61,4 @@ module Scorpion
61
61
 
62
62
  end
63
63
  end
64
- end
64
+ end