scorpion-ioc 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19c5f928b91989643e0db1c9fef98016958d5813
4
- data.tar.gz: 7e03d874e6714dae07b4da0fd3481404087df760
3
+ metadata.gz: e60f46d66df09f4c6f7615fd2710d4fe3527c965
4
+ data.tar.gz: 57c9523e72aa665056649295c6453c7ce255b724
5
5
  SHA512:
6
- metadata.gz: 3e8b8889dafadd148472b73921eb1a1da3af9a0f006870c083abfb9bb600b2e9b21fdb24ab696f6f258621cd4ad3d6a497e0c143817399621f6dc0f2383758ad
7
- data.tar.gz: bfee710c8d61409b0915dc98a206e0493d9c4b30a5406f41ab1817a0077c46418b27be3d960899b6bcb1904becde4978ab5ec9d1f34b6cff21af97f062fa38fb
6
+ metadata.gz: 09b2275087d17e93753be0d51c44306b8dc3c18586ab7120821eb5aac16fbdb82b1a9df4ae5a2c67bdb411fe4ea6c629524fdbc2b5bdfd3fdb2d2401552989aa
7
+ data.tar.gz: 6188ca0ac77ef49985acf0e5d044eec89210d243479ade15d63d6f51289b273ceab9c4ca5f5fe5969353f79082a9d4e4b913341ff8e3c3f04adb1c723d750703
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/scorpion-ioc.svg)](http://badge.fury.io/rb/scorpion-ioc)
4
4
  [![Code Climate](https://codeclimate.com/github/phallguy/scorpion.png)](https://codeclimate.com/github/phallguy/scorpion)
5
5
  [![Test Coverage](https://codeclimate.com/github/phallguy/scorpion/badges/coverage.svg)](https://codeclimate.com/github/phallguy/scorpion/coverage)
6
+ [![Inch CI](https://inch-ci.org/github/phallguy/scorpion.svg?branch=master)](https://inch-ci.org/github/phallguy/scorpion)
6
7
  [![Circle CI](https://circleci.com/gh/phallguy/scorpion.svg?style=svg)](https://circleci.com/gh/phallguy/scorpion)
7
8
 
8
9
  Add IoC to rails with minimal fuss and ceremony.
@@ -32,13 +32,13 @@ module Scorpion
32
32
  hunting_map.chart &block
33
33
  end
34
34
 
35
- # @see Scorpion#hunt!
36
- def hunt_by_traits!( contract, traits = nil, *args, &block )
35
+ # @see Scorpion#hunt
36
+ def hunt_by_traits( contract, traits = nil, *args, &block )
37
37
  unless prey = hunting_map.find( contract, traits )
38
- return parent.hunt_by_traits! contract, traits if parent
38
+ return parent.hunt_by_traits contract, traits if parent
39
39
 
40
- prey = Scorpion::Prey::ClassPrey.new( contract, nil ) if contract.is_a?( Class ) && traits.nil?
41
- unsuccessful_hunt!( contract, traits ) unless prey
40
+ prey = Scorpion::Prey::ClassPrey.new( contract, nil ) if contract.is_a?( Class ) && traits.blank?
41
+ unsuccessful_hunt( contract, traits ) unless prey
42
42
  end
43
43
  prey.fetch self, *args, &block
44
44
  end
data/lib/scorpion/king.rb CHANGED
@@ -2,7 +2,7 @@ require 'scorpion/attribute_set'
2
2
 
3
3
  module Scorpion
4
4
  # Identifies objects that are served by {Scorpion scorpions} that feed on
5
- # {Scorpion#hunt! hunted} prey.
5
+ # {Scorpion#hunt hunted} prey.
6
6
  module King
7
7
 
8
8
  # ============================================================================
@@ -48,7 +48,7 @@ module Scorpion
48
48
  king.instance_variable_set :@scorpion, scorpion
49
49
  # Go hunt for dependencies that are not lazy and initialize the
50
50
  # references.
51
- scorpion.feed! king
51
+ scorpion.feed king
52
52
  king.send :on_fed
53
53
  end
54
54
  end
@@ -76,17 +76,49 @@ module Scorpion
76
76
  end
77
77
 
78
78
  # Convenience method to ask the {#scorpion} to hunt for an object.
79
- # @see Scorpion#hunt!
80
- def hunt!( contract, *args, &block )
81
- scorpion.hunt! contract, *args, &block
79
+ # @see Scorpion#hunt
80
+ def hunt( contract, *args, &block )
81
+ scorpion.hunt contract, *args, &block
82
82
  end
83
83
 
84
84
  # Convenience method to ask the {#scorpion} to hunt for an object.
85
- # @see Scorpion#hunt_by_traits!
86
- def hunt_by_traits!( contract, traits, *args, &block )
87
- scorpion.hunt_by_traits! contract, *args, &block
85
+ # @see Scorpion#hunt_by_traits
86
+ def hunt_by_traits( contract, traits, *args, &block )
87
+ scorpion.hunt_by_traits contract, *args, &block
88
88
  end
89
89
 
90
+ # Feed dependencies from a hash into their associated attributes.
91
+ # @param [Hash] dependencies hash describing attributes to inject.
92
+ # @param [Boolean] overwrite existing attributes with values in in the hash.
93
+ def feast_on( dependencies, overwrite = false )
94
+ injected_attributes.each do |attr|
95
+ next unless dependencies.key? attr.name
96
+
97
+ if overwrite || !self.send( "#{ attr.name }?" )
98
+ self.send( "#{ attr.name }=", dependencies[ attr.name ] )
99
+ end
100
+ end
101
+
102
+ dependencies
103
+ end
104
+ alias_method :inject_from, :feast_on
105
+
106
+ # Injects dependenices from the hash and removes them from the hash.
107
+ # @see #feast_on
108
+ def feast_on!( dependencies, overwrite = false )
109
+ injected_attributes.each do |attr|
110
+ next unless dependencies.key? attr.name
111
+ val = dependencies.delete( attr.name )
112
+
113
+ if overwrite || !self.send( "#{ attr.name }?" )
114
+ self.send( "#{ attr.name }=", val )
115
+ end
116
+ end
117
+
118
+ dependencies
119
+ end
120
+ alias_method :inject_from!, :feast_on!
121
+
90
122
  module ClassMethods
91
123
 
92
124
  # Tells a {Scorpion} what to inject into the class when it is constructed
@@ -113,36 +145,42 @@ module Scorpion
113
145
 
114
146
  def build_injected_attributes
115
147
  injected_attributes.each do |attr|
116
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
117
- def #{ attr.name }
118
- @#{ attr.name } ||= begin
119
- attr = injected_attributes[ :#{ attr.name } ]
120
- scorpion.hunt!( attr.contract, attr.traits )
121
- end
122
- end
123
-
124
- def #{ attr.name }=( value )
125
- @#{ attr.name } = value
126
- end
148
+ build_injected_attribute attr
149
+ set_injected_attribute_visibility attr
150
+ end
151
+ end
127
152
 
128
- def #{ attr.name }?
129
- !!@#{ attr.name }
153
+ def build_injected_attribute( attr )
154
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
155
+ def #{ attr.name }
156
+ @#{ attr.name } ||= begin
157
+ attr = injected_attributes[ :#{ attr.name } ]
158
+ scorpion.hunt( attr.contract, attr.traits )
130
159
  end
131
- RUBY
160
+ end
132
161
 
133
- unless attr.public?
134
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
135
- private :#{ attr.name }=
136
- private :#{ attr.name }?
137
- RUBY
162
+ def #{ attr.name }=( value )
163
+ @#{ attr.name } = value
138
164
  end
139
165
 
140
- if attr.private?
141
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
142
- private :#{ attr.name }
143
- RUBY
166
+ def #{ attr.name }?
167
+ !!@#{ attr.name }
144
168
  end
169
+ RUBY
170
+ end
145
171
 
172
+ def set_injected_attribute_visibility( attr )
173
+ unless attr.public?
174
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
175
+ private :#{ attr.name }=
176
+ private :#{ attr.name }?
177
+ RUBY
178
+ end
179
+
180
+ if attr.private?
181
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
182
+ private :#{ attr.name }
183
+ RUBY
146
184
  end
147
185
  end
148
186
  end
@@ -71,14 +71,14 @@ module Scorpion
71
71
  end
72
72
  # Allow dependencies to access the current request/response
73
73
  hunter.hunt_for ActionDispatch::Request do |hunter|
74
- hunter.hunt!( AbstractController::Base ).request
74
+ hunter.hunt( AbstractController::Base ).request
75
75
  end
76
76
  hunter.hunt_for ActionDispatch::Response do |hunter|
77
- hunter.hunt!( AbstractController::Base ).response
77
+ hunter.hunt( AbstractController::Base ).response
78
78
  end
79
79
  end
80
80
 
81
- @scorpion.feed! self
81
+ @scorpion.feed self
82
82
 
83
83
  yield
84
84
  ensure
@@ -1,5 +1,5 @@
1
1
  module Scorpion
2
- VERSION_NUMBER = "0.1.0"
2
+ VERSION_NUMBER = "0.2.0"
3
3
  VERSION_SUFFIX = ""
4
4
  VERSION = "#{VERSION_NUMBER}#{VERSION_SUFFIX}"
5
5
  end
data/lib/scorpion.rb CHANGED
@@ -29,25 +29,27 @@ module Scorpion
29
29
  # @param [Array<Symbol>] traits required of the prey
30
30
  # @return [Object] an object that matches the requirements defined in `attribute`.
31
31
  # @raise [UnsuccessfulHunt] if a matching object cannot be found.
32
- def hunt_by_traits!( contract, traits, *args, &block )
32
+ def hunt_by_traits( contract, traits, *args, &block )
33
33
  fail "Not implemented"
34
34
  end
35
- alias_method :fetch_by_traits!, :hunt_by_traits!
35
+ alias_method :fetch_by_traits, :hunt_by_traits
36
36
 
37
37
  # Hunts for an object that satisfies the requested `contract` regardless of
38
38
  # traits.
39
- # @see #hunt_by_traits!
40
- def hunt!( contract, *args, &block )
41
- hunt_by_traits!( contract, nil, *args, &block )
39
+ # @see #hunt_by_traits
40
+ def hunt( contract, *args, &block )
41
+ hunt_by_traits( contract, nil, *args, &block )
42
42
  end
43
- alias_method :fetch!, :hunt!
43
+ alias_method :fetch, :hunt
44
44
 
45
45
  # Populate given `king` with its expected attributes.
46
46
  # @param [Scorpion::King] king to be fed.
47
47
  # @return [Scorpion::King] the populated king.
48
- def feed!( king )
48
+ def feed( king )
49
49
  king.injected_attributes.each do |attr|
50
- king.send :feed, attr, hunt_by_traits!( attr.contract, attr.traits )
50
+ next if king.send "#{ attr.name }?"
51
+
52
+ king.send :feed, attr, hunt_by_traits( attr.contract, attr.traits )
51
53
  end
52
54
  end
53
55
 
@@ -84,7 +86,7 @@ module Scorpion
84
86
 
85
87
  # Used by concrete scorpions to notify the caller that the hunt was
86
88
  # unsuccessful.
87
- def unsuccessful_hunt!( contract, traits )
89
+ def unsuccessful_hunt( contract, traits )
88
90
  fail UnsuccessfulHunt.new contract, traits
89
91
  end
90
92
 
@@ -39,31 +39,35 @@ describe Scorpion::Hunter do
39
39
  end
40
40
 
41
41
  it "spawns prey" do
42
- expect( hunter.hunt! Test::Hunter::Beast ).to be_a Test::Hunter::Bear
42
+ expect( hunter.hunt Test::Hunter::Beast ).to be_a Test::Hunter::Bear
43
43
  end
44
44
 
45
45
  it "spawns a new instance for multiple requests" do
46
- first = hunter.hunt! Test::Hunter::Beast
47
- expect( hunter.hunt! Test::Hunter::Beast ).not_to eq first
46
+ first = hunter.hunt Test::Hunter::Beast
47
+ expect( hunter.hunt Test::Hunter::Beast ).not_to eq first
48
48
  end
49
49
 
50
50
  it "spawns the same instance for captured prey" do
51
- first = hunter.hunt_by_traits! Test::Hunter::Beast, :tame
52
- expect( hunter.hunt_by_traits! Test::Hunter::Beast, :tame ).to be first
51
+ first = hunter.hunt_by_traits Test::Hunter::Beast, :tame
52
+ expect( hunter.hunt_by_traits Test::Hunter::Beast, :tame ).to be first
53
53
  end
54
54
 
55
55
  it "injects nested kings" do
56
- zoo = hunter.hunt! Test::Hunter::Zoo
56
+ zoo = hunter.hunt Test::Hunter::Zoo
57
57
  expect( zoo.bear ).to be_a Test::Hunter::Bear
58
58
  end
59
59
 
60
60
  it "accepts arguments that are passed to constructor" do
61
- obj = hunter.hunt! Test::Hunter::Argumented, :awesome
61
+ obj = hunter.hunt Test::Hunter::Argumented, :awesome
62
62
  expect( obj.arg ).to eq :awesome
63
63
  end
64
64
 
65
65
  it "implicitly spawns Class contracts" do
66
- expect( hunter.hunt! Test::Hunter::Implicit ).to be_a Test::Hunter::Implicit
66
+ expect( hunter.hunt Test::Hunter::Implicit ).to be_a Test::Hunter::Implicit
67
+ end
68
+
69
+ it "implicitly spawns Class contracts with empty traits" do
70
+ expect( hunter.hunt_by_traits Test::Hunter::Implicit, [] ).to be_a Test::Hunter::Implicit
67
71
  end
68
72
 
69
73
  end
@@ -13,7 +13,8 @@ module Test
13
13
  def initialize( family, parent = nil, options={}, &block )
14
14
  @family = family
15
15
  @parent = parent
16
- @options = options
16
+ @options = feast_on! options
17
+
17
18
 
18
19
  yield if block_given?
19
20
  end
@@ -55,7 +56,7 @@ describe Scorpion::King do
55
56
  let( :scorpion ){ double Scorpion }
56
57
 
57
58
  before( :each ) do
58
- allow( scorpion ).to receive( :feed! )
59
+ allow( scorpion ).to receive( :feed )
59
60
  end
60
61
 
61
62
  describe ".spawn" do
@@ -65,6 +66,11 @@ describe Scorpion::King do
65
66
  expect( mamal ).to be_a Test::King::Mamal
66
67
  end
67
68
 
69
+ it "calls feed" do
70
+ expect( scorpion ).to receive( :feed )
71
+ Test::King::Mouse.spawn scorpion
72
+ end
73
+
68
74
  it "can inherit" do
69
75
  mouse = Test::King::Mouse.spawn scorpion, name: 'name'
70
76
  expect( mouse.family ).to eq 'mouse'
@@ -125,5 +131,68 @@ describe Scorpion::King do
125
131
 
126
132
  end
127
133
 
134
+ describe "feasting" do
135
+ let( :logger ) { Test::King::Logger.new }
136
+ let( :options ) { { manager: logger, color: :red } }
137
+ let( :king ) { Test::King::Mouse.new name: 'mighty' }
138
+
139
+
140
+ describe "#feast_on" do
141
+ it "assigns attributes" do
142
+ king.send :feast_on, options
143
+ expect( king.manager ).to be logger
144
+ end
145
+
146
+ it "doesn't overwrite" do
147
+ king.manager = Test::King::Logger.new
148
+ king.send :feast_on, options
149
+ expect( king.manager ).not_to be logger
150
+ end
151
+
152
+ it "overwrites when asked" do
153
+ king.manager = Test::King::Logger.new
154
+ king.send :feast_on, options, true
155
+ expect( king.manager ).to be logger
156
+ end
157
+ end
158
+
159
+ describe "feast_on!" do
160
+ it "assigns attributes" do
161
+ king.send :feast_on!, options
162
+ expect( king.manager ).to be logger
163
+ end
164
+
165
+ it "doesn't overwrite" do
166
+ king.manager = Test::King::Logger.new
167
+ king.send :feast_on!, options
168
+ expect( king.manager ).not_to be logger
169
+ end
170
+
171
+ it "overwrites when asked" do
172
+ king.manager = Test::King::Logger.new
173
+ king.send :feast_on!, options, true
174
+ expect( king.manager ).to be logger
175
+ end
176
+
177
+ it "removes injected attributes" do
178
+ expect( options ).to have_key :manager
179
+ king.send :feast_on!, options
180
+ expect( options ).not_to have_key :manager
181
+ end
182
+
183
+ it "removes injected attribute even if already set" do
184
+ expect( options ).to have_key :manager
185
+ king.manager = Test::King::Logger.new
186
+ king.send :feast_on!, options
187
+ expect( options ).not_to have_key :manager
188
+ end
189
+
190
+ it "doesn't remove other options" do
191
+ king.send :feast_on!, options
192
+ expect( options ).to have_key :color
193
+ end
194
+
195
+ end
196
+ end
128
197
 
129
198
  end
@@ -18,8 +18,8 @@ describe Scorpion::Rails::Controller, type: :controller do
18
18
  end
19
19
 
20
20
  def index
21
- @guard1 = scorpion.hunt! Test::Nest::Guard
22
- @guard2 = scorpion.hunt! Test::Nest::Guard
21
+ @guard1 = scorpion.hunt Test::Nest::Guard
22
+ @guard2 = scorpion.hunt Test::Nest::Guard
23
23
  render nothing: true
24
24
  end
25
25
  end
@@ -62,8 +62,8 @@ describe Scorpion::Rails::Controller, type: :controller do
62
62
 
63
63
  it "spawns the same service during the same request" do
64
64
  allow( subject ).to receive( :index ) do
65
- service = subject.service
66
- expect( subject.scorpion.hunt! Test::Nest::Service ).to be service
65
+ service = subject.scorpion.hunt Test::Nest::Service
66
+ expect( subject.scorpion.hunt Test::Nest::Service ).to be service
67
67
  controller.render nothing: true
68
68
  end
69
69
 
@@ -74,7 +74,7 @@ describe Scorpion::Rails::Controller, type: :controller do
74
74
  service = subject.service
75
75
 
76
76
  allow( subject ).to receive( :index ) do
77
- expect( subject.scorpion.hunt! Test::Nest::Service ).not_to be service
77
+ expect( subject.scorpion.hunt Test::Nest::Service ).not_to be service
78
78
  controller.render nothing: true
79
79
  end
80
80
 
@@ -83,7 +83,7 @@ describe Scorpion::Rails::Controller, type: :controller do
83
83
 
84
84
  it "hunts for controller" do
85
85
  allow( subject ).to receive( :index ) do
86
- expect( subject.scorpion.hunt!( AbstractController::Base ) ).to be subject
86
+ expect( subject.scorpion.hunt( AbstractController::Base ) ).to be subject
87
87
  controller.render nothing: true
88
88
  end
89
89
 
@@ -92,7 +92,7 @@ describe Scorpion::Rails::Controller, type: :controller do
92
92
 
93
93
  it "hunts for response" do
94
94
  allow( subject ).to receive( :index ) do
95
- expect( subject.scorpion.hunt!( ActionDispatch::Response ) ).to be subject.response
95
+ expect( subject.scorpion.hunt( ActionDispatch::Response ) ).to be subject.response
96
96
  controller.render nothing: true
97
97
  end
98
98
 
@@ -101,7 +101,7 @@ describe Scorpion::Rails::Controller, type: :controller do
101
101
 
102
102
  it "hunts for request" do
103
103
  allow( subject ).to receive( :index ) do
104
- expect( subject.scorpion.hunt!( ActionDispatch::Request ).object_id ).to be subject.request.object_id
104
+ expect( subject.scorpion.hunt( ActionDispatch::Request ).object_id ).to be subject.request.object_id
105
105
  controller.render nothing: true
106
106
  end
107
107
 
@@ -1,4 +1,40 @@
1
1
  require 'spec_helper'
2
2
 
3
+ module Test
4
+ module Scorpion
5
+ class Logger; end
6
+
7
+ class Target
8
+ include ::Scorpion::King
9
+
10
+ feed_on do
11
+ logger Logger, public: true
12
+ end
13
+ end
14
+ end
15
+ end
16
+
3
17
  describe Scorpion do
18
+ let( :scorpion ){ Scorpion::Hunter.new }
19
+ let( :target ) do
20
+ Test::Scorpion::Target.new.tap do |target|
21
+ target.instance_variable_set :@scorpion, scorpion
22
+ end
23
+ end
24
+
25
+ describe "#feed" do
26
+ it "injects attributes" do
27
+ scorpion.feed target
28
+
29
+ expect( target.logger ).to be_a Test::Scorpion::Logger
30
+ end
31
+
32
+ it "does not overwrite existing attributes" do
33
+ logger = Test::Scorpion::Logger.new
34
+ target.logger = logger
35
+ scorpion.feed target
36
+
37
+ expect( target.logger ).to be logger
38
+ end
39
+ end
4
40
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scorpion-ioc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Alexander
@@ -174,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
174
  version: '0'
175
175
  requirements: []
176
176
  rubyforge_project:
177
- rubygems_version: 2.4.5
177
+ rubygems_version: 2.4.6
178
178
  signing_key:
179
179
  specification_version: 4
180
180
  summary: Add IoC to rails with minimal fuss and ceremony