scorpion-ioc 0.4.0 → 0.5.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 +4 -4
- data/.rspec +0 -1
- data/Gemfile +0 -1
- data/README.md +4 -1
- data/lib/scorpion.rb +38 -11
- data/lib/scorpion/attribute.rb +4 -1
- data/lib/scorpion/chain_hunter.rb +58 -0
- data/lib/scorpion/dependency.rb +7 -3
- data/lib/scorpion/dependency/builder_dependency.rb +5 -1
- data/lib/scorpion/dependency/class_dependency.rb +10 -7
- data/lib/scorpion/dependency_map.rb +11 -2
- data/lib/scorpion/error.rb +6 -0
- data/lib/scorpion/hunt.rb +32 -21
- data/lib/scorpion/hunter.rb +15 -2
- data/lib/scorpion/locale/en.yml +1 -0
- data/lib/scorpion/method.rb +24 -0
- data/lib/scorpion/nest.rb +5 -0
- data/lib/scorpion/object.rb +30 -23
- data/lib/scorpion/object_constructor.rb +23 -14
- data/lib/scorpion/rails.rb +1 -0
- data/lib/scorpion/rails/active_record/association.rb +5 -6
- data/lib/scorpion/rails/active_record/model.rb +4 -5
- data/lib/scorpion/rails/active_record/relation.rb +2 -4
- data/lib/scorpion/rails/controller.rb +31 -2
- data/lib/scorpion/rails/job.rb +12 -0
- data/lib/scorpion/rails/mailer.rb +42 -0
- data/lib/scorpion/rails/nest.rb +23 -20
- data/lib/scorpion/rails/railtie.rb +1 -0
- data/lib/scorpion/rspec/helper.rb +47 -0
- data/lib/scorpion/stinger.rb +0 -1
- data/lib/scorpion/version.rb +1 -1
- data/scorpion.gemspec +1 -0
- data/spec/lib/scorpion/attribute_spec.rb +10 -0
- data/spec/lib/scorpion/hunt_spec.rb +9 -3
- data/spec/lib/scorpion/hunter_spec.rb +13 -2
- data/spec/lib/scorpion/object_constructor_spec.rb +63 -6
- data/spec/lib/scorpion/object_spec.rb +9 -5
- data/spec/lib/scorpion/rails/controller_spec.rb +33 -1
- data/spec/lib/scorpion/rspec/helper_spec.rb +10 -0
- data/spec/spec_helper.rb +5 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93ebd370c4020bf58ad8fb775368a16a8949ebca
|
4
|
+
data.tar.gz: 5d3d644a4688b8f310f065e8d3431574c7fe142c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fb8f746aaf8ec843dc91ce3ea468c89d04c8cf1f442aebe65facb4a73a3a71c25f2f2204f3438f389a0c3323781b9565f32f5ef854936774047ffd8a8625847
|
7
|
+
data.tar.gz: 49fca90cccdcba2f232709c08a1f703371fbf293c53ee0fd5652eae969cf6a653f3d12a2f347b387b93bdd2070911cded579b867c6699b78c96adfa092160395
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
|
9
9
|
Add IoC to rails with minimal fuss and ceremony.
|
10
10
|
|
11
|
+
(Also check out [shog](http://github.com/phallguy/shog) for better rails logs)
|
12
|
+
|
11
13
|
<!-- MarkdownTOC depth=4 -->
|
12
14
|
|
13
15
|
- [Dependency Injection](#dependency-injection)
|
@@ -519,6 +521,7 @@ class SessionsController < ActionController::Base
|
|
519
521
|
|
520
522
|
def create
|
521
523
|
user = User.with_scorpion( scorpion ).find params[:id]
|
524
|
+
user = scorpion( User ).find params[:id]
|
522
525
|
sign_in if user.check_password( params[:password] )
|
523
526
|
end
|
524
527
|
end
|
@@ -538,4 +541,4 @@ end
|
|
538
541
|
|
539
542
|
[The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
540
543
|
|
541
|
-
Copyright (c) 2015 Paul Alexander
|
544
|
+
Copyright (c) 2015 Paul Alexander
|
data/lib/scorpion.rb
CHANGED
@@ -6,10 +6,12 @@ module Scorpion
|
|
6
6
|
|
7
7
|
require 'scorpion/version'
|
8
8
|
require 'scorpion/error'
|
9
|
+
require 'scorpion/method'
|
9
10
|
require 'scorpion/object'
|
10
11
|
require 'scorpion/object_constructor'
|
11
12
|
require 'scorpion/attribute_set'
|
12
13
|
require 'scorpion/hunter'
|
14
|
+
require 'scorpion/chain_hunter'
|
13
15
|
require 'scorpion/dependency_map'
|
14
16
|
require 'scorpion/hunt'
|
15
17
|
require 'scorpion/dependency'
|
@@ -20,18 +22,19 @@ module Scorpion
|
|
20
22
|
# Hunts for an object that satisfies the requested `contract` and `traits`.
|
21
23
|
# @param [Class,Module,Symbol] contract describing the desired behavior of the dependency.
|
22
24
|
# @param [Array<Symbol>] traits required of the dependency
|
25
|
+
# @param [Hash<Symbol,Object>] dependencies to inject into the object.
|
23
26
|
# @return [Object] an object that satisfies the contract and traits.
|
24
27
|
# @raise [UnsuccessfulHunt] if a matching object cannot be found.
|
25
|
-
def fetch_by_traits( contract, traits, *
|
26
|
-
hunt = Hunt.new( self, contract, traits, *
|
28
|
+
def fetch_by_traits( contract, traits, *arguments, **dependencies, &block )
|
29
|
+
hunt = Hunt.new( self, contract, traits, *arguments, **dependencies, &block )
|
27
30
|
execute hunt
|
28
31
|
end
|
29
32
|
|
30
33
|
# Hunts for an object that satisfies the requested `contract` regardless of
|
31
34
|
# traits.
|
32
35
|
# @see #fetch_by_traits
|
33
|
-
def fetch( contract, *
|
34
|
-
fetch_by_traits( contract, nil, *
|
36
|
+
def fetch( contract, *arguments, **dependencies, &block )
|
37
|
+
fetch_by_traits( contract, nil, *arguments, **dependencies, &block )
|
35
38
|
end
|
36
39
|
|
37
40
|
# Creates a new object and feeds it it's dependencies.
|
@@ -39,14 +42,33 @@ module Scorpion
|
|
39
42
|
# @param [Array<Object>] args to pass to the constructor.
|
40
43
|
# @param [#call] block to pass to the constructor.
|
41
44
|
# @return [Scorpion::Object] the spawned object.
|
42
|
-
def spawn( hunt, object_class, *
|
45
|
+
def spawn( hunt, object_class, *arguments, **dependencies, &block )
|
43
46
|
if object_class < Scorpion::Object
|
44
|
-
object_class.spawn hunt, *
|
47
|
+
object_class.spawn hunt, *arguments, **dependencies, &block
|
45
48
|
else
|
46
|
-
object_class.new *
|
49
|
+
object_class.new *arguments, &block
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
# Inject the {#target} with all non-lazy dependencies.
|
54
|
+
# @param [Scorpion::Object] target to inject.
|
55
|
+
# @return [target]
|
56
|
+
def inject( target )
|
57
|
+
hunt = Scorpion::Hunt.new self, nil, nil
|
58
|
+
hunt.inject target
|
59
|
+
|
60
|
+
target
|
61
|
+
end
|
62
|
+
|
63
|
+
# Explicitly spawn an instance of {#object_class} and inject it's dependencies.
|
64
|
+
# @param [Array<Object>] args to pass to the constructor.
|
65
|
+
# @param [#call] block to pass to the constructor.
|
66
|
+
# @return [Scorpion::Object] the spawned object.
|
67
|
+
def new( object_class, *arguments, **dependencies, &block )
|
68
|
+
hunt = Hunt.new( self, object_class, nil, *arguments, **dependencies, &block )
|
69
|
+
Scorpion::Dependency::ClassDependency.new( object_class ).fetch( hunt )
|
70
|
+
end
|
71
|
+
|
50
72
|
# Execute the `hunt` returning the desired dependency.
|
51
73
|
# @param [Hunt] hunt to execute.
|
52
74
|
# @return [Object] an object that satisfies the hunt contract and traits.
|
@@ -63,6 +85,11 @@ module Scorpion
|
|
63
85
|
|
64
86
|
# Free up any captured dependency and release any long-held resources.
|
65
87
|
def destroy
|
88
|
+
reset
|
89
|
+
end
|
90
|
+
|
91
|
+
# Reset the hunting map and clear all dependencies.
|
92
|
+
def reset
|
66
93
|
end
|
67
94
|
|
68
95
|
# @return [Scorpion::Nest] a nest that uses this scorpion as the mother.
|
@@ -106,14 +133,14 @@ module Scorpion
|
|
106
133
|
|
107
134
|
# Hunt for dependency from the primary Scorpion {#instance}.
|
108
135
|
# @see #fetch
|
109
|
-
def self.fetch(
|
110
|
-
instance.fetch
|
136
|
+
def self.fetch( dependencies, &block )
|
137
|
+
instance.fetch dependencies, &block
|
111
138
|
end
|
112
139
|
|
113
140
|
# Hunt for dependency from the primary Scorpion {#instance}.
|
114
141
|
# @see #fetch_by_traits
|
115
|
-
def self.fetch_by_traits(
|
116
|
-
instance.fetch_by_traits
|
142
|
+
def self.fetch_by_traits( dependencies, &block )
|
143
|
+
instance.fetch_by_traits dependencies, &block
|
117
144
|
end
|
118
145
|
|
119
146
|
# @!attribute logger
|
data/lib/scorpion/attribute.rb
CHANGED
@@ -13,7 +13,10 @@ module Scorpion
|
|
13
13
|
# @!attribute
|
14
14
|
# @return [Class,Module,Symbol] contract that describes the desired behavior
|
15
15
|
# of the injected object.
|
16
|
-
|
16
|
+
def contract
|
17
|
+
@contract = @contract.constantize if @contract.is_a? String
|
18
|
+
@contract
|
19
|
+
end
|
17
20
|
|
18
21
|
# @!attribute
|
19
22
|
# @return [Array<Symbol>] traits that must match on instances of the {#contract}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Scorpion
|
2
|
+
|
3
|
+
# Chains hunting calls to one or more managed scorpions.
|
4
|
+
class ChainHunter
|
5
|
+
include Scorpion
|
6
|
+
|
7
|
+
# ============================================================================
|
8
|
+
# @!group Attributes
|
9
|
+
#
|
10
|
+
|
11
|
+
# @!attribute
|
12
|
+
# @return [Array<Scorpion>] scorpions to chain hunting calls to.
|
13
|
+
attr_reader :scorpions
|
14
|
+
|
15
|
+
#
|
16
|
+
# @!endgroup Attributes
|
17
|
+
|
18
|
+
|
19
|
+
def initialize( *scorpions )
|
20
|
+
@scorpions = scorpions
|
21
|
+
end
|
22
|
+
|
23
|
+
# Prepare the scorpion for hunting.
|
24
|
+
# @see DependencyMap#chart
|
25
|
+
def prepare( &block )
|
26
|
+
if top = scorpions.first
|
27
|
+
top.prepare &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see Scorpion#replicate
|
32
|
+
def replicate
|
33
|
+
self.class.new scorpions
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Scorpion#hunt
|
37
|
+
def execute( hunt )
|
38
|
+
# Try explicitly defined dependencies first
|
39
|
+
scorpions.each do |hunter|
|
40
|
+
begin
|
41
|
+
return hunter.execute( hunt, true )
|
42
|
+
rescue UnsuccessfulHunt
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Then allow implicit
|
47
|
+
scorpions.each do |hunter|
|
48
|
+
begin
|
49
|
+
return hunter.execute( hunt )
|
50
|
+
rescue UnsuccessfulHunt
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
unsuccessful_hunt hunt.contract, hunt.traits
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/scorpion/dependency.rb
CHANGED
@@ -92,7 +92,7 @@ module Scorpion
|
|
92
92
|
|
93
93
|
# Define dependency based on the desired contract and traits.
|
94
94
|
# @return [Dependency] the defined dependency.
|
95
|
-
def define( contract, traits = nil
|
95
|
+
def define( contract, traits = nil, &builder )
|
96
96
|
options, traits = extract_options!( traits )
|
97
97
|
|
98
98
|
if options.key?( :return )
|
@@ -104,8 +104,12 @@ module Scorpion
|
|
104
104
|
elsif block_given?
|
105
105
|
Scorpion::Dependency::BuilderDependency.new( contract, traits, builder )
|
106
106
|
elsif contract.respond_to?( :create )
|
107
|
-
Scorpion::Dependency::BuilderDependency.new( contract, traits ) do |
|
108
|
-
|
107
|
+
Scorpion::Dependency::BuilderDependency.new( contract, traits ) do |hunt,*args,**dependencies,&block|
|
108
|
+
if dependencies.present?
|
109
|
+
contract.create hunt, *args, **dependencies, &block
|
110
|
+
else
|
111
|
+
contract.create hunt, *args, &block
|
112
|
+
end
|
109
113
|
end
|
110
114
|
else
|
111
115
|
dependency_class( contract ).new( contract, traits, &builder )
|
@@ -24,7 +24,11 @@ module Scorpion
|
|
24
24
|
|
25
25
|
# @see Scorpion::Dependency#fetch
|
26
26
|
def fetch( hunt )
|
27
|
-
|
27
|
+
if hunt.dependencies.any?
|
28
|
+
builder.call( hunt, *hunt.arguments, **hunt.dependencies, &hunt.block )
|
29
|
+
else
|
30
|
+
builder.call( hunt, *hunt.arguments, &hunt.block )
|
31
|
+
end
|
28
32
|
end
|
29
33
|
|
30
34
|
end
|
@@ -6,20 +6,23 @@ module Scorpion
|
|
6
6
|
class ClassDependency < Scorpion::Dependency
|
7
7
|
|
8
8
|
def fetch( hunt )
|
9
|
-
|
9
|
+
resolved = resolve_dependencies( hunt )
|
10
|
+
hunt.scorpion.spawn hunt, hunt.contract, *hunt.arguments, **resolved, &hunt.block
|
10
11
|
end
|
11
12
|
|
12
13
|
private
|
13
14
|
|
14
|
-
def
|
15
|
-
|
16
|
-
return
|
15
|
+
def resolve_dependencies( hunt )
|
16
|
+
dependencies = hunt.dependencies
|
17
|
+
return dependencies unless hunt.contract.respond_to? :initializer_injections
|
17
18
|
|
18
|
-
hunt.contract.initializer_injections.each_with_object(
|
19
|
-
|
20
|
-
end
|
19
|
+
hunt.contract.initializer_injections.each_with_object(dependencies.dup) do |attr,deps|
|
20
|
+
next if attr.lazy?
|
21
21
|
|
22
|
+
deps[attr.name] ||= hunt.fetch_by_traits( attr.contract, attr.traits )
|
23
|
+
end
|
22
24
|
end
|
25
|
+
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -30,8 +30,7 @@ module Scorpion
|
|
30
30
|
|
31
31
|
def initialize( scorpion )
|
32
32
|
@scorpion = scorpion
|
33
|
-
|
34
|
-
@shared_dependency_set = []
|
33
|
+
reset
|
35
34
|
end
|
36
35
|
|
37
36
|
# Find {Dependency} that matches the requested `contract` and `traits`.
|
@@ -126,6 +125,16 @@ module Scorpion
|
|
126
125
|
self
|
127
126
|
end
|
128
127
|
|
128
|
+
# Remove all dependency mappings.
|
129
|
+
def reset
|
130
|
+
|
131
|
+
@dependency_set.each &:release if @dependency_set
|
132
|
+
@shared_dependency_set.each &:release if @shared_dependency_set
|
133
|
+
|
134
|
+
@dependency_set = @active_dependency_set = []
|
135
|
+
@shared_dependency_set = []
|
136
|
+
end
|
137
|
+
|
129
138
|
private
|
130
139
|
|
131
140
|
def define_dependency( contract, traits, &builder )
|
data/lib/scorpion/error.rb
CHANGED
@@ -21,6 +21,12 @@ module Scorpion
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
class ArityMismatch < Error
|
25
|
+
def initialize( block, expected_count )
|
26
|
+
super translate( :arity_mismatch, expected: expected_count, actual: block.arity )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
class BuilderRequiredError < Error
|
25
31
|
def initialize( message = nil )
|
26
32
|
super ( message || translate( :builder_required ) )
|
data/lib/scorpion/hunt.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Scorpion
|
2
|
-
# Captures state for a specific hunt so that constructor
|
2
|
+
# Captures state for a specific hunt so that constructor dependencies can be
|
3
3
|
# shared with child dependencies.
|
4
4
|
#
|
5
5
|
# @example
|
@@ -45,7 +45,7 @@ module Scorpion
|
|
45
45
|
attr_reader :trip
|
46
46
|
private :trip
|
47
47
|
|
48
|
-
delegate [:contract, :traits, :arguments, :block] => :trip
|
48
|
+
delegate [:contract, :traits, :dependencies, :arguments, :block] => :trip
|
49
49
|
|
50
50
|
# @!attribute contract
|
51
51
|
# @return [Class,Module,Symbol] contract being hunted for.
|
@@ -53,8 +53,11 @@ module Scorpion
|
|
53
53
|
# @!attribute traits
|
54
54
|
# @return [Array<Symbol>] traits being hunted for.
|
55
55
|
|
56
|
+
# @!attribute [r] dependencies
|
57
|
+
# @return [Hash<Symbol,Dependency>] hash of dependencies to pass to initializer of {#contract} when found.
|
58
|
+
|
56
59
|
# @!attribute [r] arguments
|
57
|
-
# @return [Array<
|
60
|
+
# @return [Array<Object>] positional arguments to pass to the initializer of {#contract} when found.
|
58
61
|
|
59
62
|
# @!attribute block
|
60
63
|
# @return [#call] block to pass to constructor of contract when found.
|
@@ -62,22 +65,22 @@ module Scorpion
|
|
62
65
|
#
|
63
66
|
# @!endgroup Attributes
|
64
67
|
|
65
|
-
def initialize( scorpion, contract, traits, *arguments, &block )
|
68
|
+
def initialize( scorpion, contract, traits, *arguments, **dependencies, &block )
|
66
69
|
@scorpion = scorpion
|
67
70
|
@trips = []
|
68
|
-
@trip = Trip.new contract, traits, arguments, block
|
71
|
+
@trip = Trip.new contract, traits, arguments, dependencies, block
|
69
72
|
end
|
70
73
|
|
71
74
|
# Hunt for additional dependency to satisfy the main hunt's contract and traits.
|
72
75
|
# @see Scorpion#hunt
|
73
|
-
def fetch( contract, *arguments, &block )
|
74
|
-
fetch_by_traits( contract, nil, *arguments, &block )
|
76
|
+
def fetch( contract, *arguments, **dependencies, &block )
|
77
|
+
fetch_by_traits( contract, nil, *arguments, **dependencies, &block )
|
75
78
|
end
|
76
79
|
|
77
80
|
# Hunt for additional dependency to satisfy the main hunt's contract and traits.
|
78
81
|
# @see Scorpion#hunt
|
79
|
-
def fetch_by_traits( contract, traits, *arguments, &block )
|
80
|
-
push contract, traits, arguments, block
|
82
|
+
def fetch_by_traits( contract, traits, *arguments, **dependencies, &block )
|
83
|
+
push contract, traits, arguments, dependencies, block
|
81
84
|
execute
|
82
85
|
ensure
|
83
86
|
pop
|
@@ -88,6 +91,7 @@ module Scorpion
|
|
88
91
|
# @return [Scorpion::Object] the injected object.
|
89
92
|
def inject( object )
|
90
93
|
trip.object = object
|
94
|
+
|
91
95
|
object.injected_attributes.each do |attr|
|
92
96
|
next if object.send "#{ attr.name }?"
|
93
97
|
next if attr.lazy?
|
@@ -95,14 +99,17 @@ module Scorpion
|
|
95
99
|
object.send :inject, attr, fetch_by_traits( attr.contract, attr.traits )
|
96
100
|
end
|
97
101
|
|
102
|
+
object.send :on_injected
|
103
|
+
|
98
104
|
object
|
99
105
|
end
|
100
106
|
|
101
107
|
# Allow the hunt to spawn objects.
|
102
108
|
# @see Scorpion#spawn
|
103
|
-
def spawn( klass, *arguments, &block )
|
104
|
-
scorpion.spawn( self, klass, *arguments, &block )
|
109
|
+
def spawn( klass, *arguments, **dependencies, &block )
|
110
|
+
scorpion.spawn( self, klass, *arguments, **dependencies, &block )
|
105
111
|
end
|
112
|
+
alias_method :new, :spawn
|
106
113
|
|
107
114
|
private
|
108
115
|
|
@@ -111,12 +118,12 @@ module Scorpion
|
|
111
118
|
end
|
112
119
|
|
113
120
|
def execute_from_trips
|
114
|
-
return if
|
121
|
+
return if dependencies.any?
|
115
122
|
|
116
123
|
trips.each do |trip|
|
117
124
|
return trip.object if contract === trip.object
|
118
|
-
trip.
|
119
|
-
return
|
125
|
+
trip.dependencies.each do |key,value|
|
126
|
+
return value if contract === value
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
@@ -127,10 +134,10 @@ module Scorpion
|
|
127
134
|
scorpion.execute self
|
128
135
|
end
|
129
136
|
|
130
|
-
def push( contract, traits, arguments, block )
|
137
|
+
def push( contract, traits, arguments, dependencies, block )
|
131
138
|
trips.push trip
|
132
139
|
|
133
|
-
@trip = Trip.new contract, traits, arguments, block
|
140
|
+
@trip = Trip.new contract, traits, arguments, dependencies, block
|
134
141
|
end
|
135
142
|
|
136
143
|
def pop
|
@@ -141,15 +148,19 @@ module Scorpion
|
|
141
148
|
attr_reader :contract
|
142
149
|
attr_reader :traits
|
143
150
|
attr_reader :arguments
|
151
|
+
attr_reader :dependencies
|
144
152
|
attr_reader :block
|
145
153
|
|
146
154
|
attr_accessor :object
|
147
155
|
|
148
|
-
def initialize( contract, traits, arguments, block )
|
149
|
-
@contract
|
150
|
-
@traits
|
151
|
-
@arguments
|
152
|
-
@
|
156
|
+
def initialize( contract, traits, arguments, dependencies, block )
|
157
|
+
@contract = contract
|
158
|
+
@traits = traits
|
159
|
+
@arguments = arguments
|
160
|
+
@dependencies = dependencies
|
161
|
+
@block = block
|
162
|
+
|
163
|
+
@caller = caller
|
153
164
|
end
|
154
165
|
end
|
155
166
|
|