scorpion-ioc 0.3.1 → 0.4.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/.gitignore +2 -1
- data/.rspec +2 -1
- data/README.md +111 -44
- data/lib/scorpion/attribute.rb +0 -1
- data/lib/scorpion/attribute_set.rb +15 -7
- data/lib/scorpion/dependency/argument_dependency.rb +25 -0
- data/lib/scorpion/{prey/builder_prey.rb → dependency/builder_dependency.rb} +8 -8
- data/lib/scorpion/dependency/captured_dependency.rb +44 -0
- data/lib/scorpion/dependency/class_dependency.rb +25 -0
- data/lib/scorpion/dependency/module_dependency.rb +14 -0
- data/lib/scorpion/dependency.rb +137 -0
- data/lib/scorpion/dependency_map.rb +135 -0
- data/lib/scorpion/hunt.rb +158 -0
- data/lib/scorpion/hunter.rb +21 -20
- data/lib/scorpion/locale/en.yml +5 -1
- data/lib/scorpion/{king.rb → object.rb} +72 -53
- data/lib/scorpion/object_constructor.rb +55 -0
- data/lib/scorpion/rails/active_record/association.rb +65 -0
- data/lib/scorpion/rails/active_record/model.rb +28 -0
- data/lib/scorpion/rails/active_record/relation.rb +66 -0
- data/lib/scorpion/rails/active_record.rb +21 -0
- data/lib/scorpion/rails/controller.rb +22 -62
- data/lib/scorpion/rails/job.rb +30 -0
- data/lib/scorpion/rails/nest.rb +86 -0
- data/lib/scorpion/rails/railtie.rb +16 -0
- data/lib/scorpion/rails.rb +4 -0
- data/lib/scorpion/rspec/helper.rb +25 -0
- data/lib/scorpion/rspec.rb +17 -0
- data/lib/scorpion/stinger.rb +69 -0
- data/lib/scorpion/version.rb +1 -1
- data/lib/scorpion.rb +91 -44
- data/scorpion.gemspec +1 -1
- data/spec/internal/app/models/author.rb +17 -0
- data/spec/internal/app/models/todo.rb +14 -0
- data/spec/internal/db/schema.rb +12 -1
- data/spec/lib/scorpion/dependency/argument_dependency_spec.rb +18 -0
- data/spec/lib/scorpion/dependency/builder_dependency_spec.rb +41 -0
- data/spec/lib/scorpion/dependency/module_dependency_spec.rb +16 -0
- data/spec/lib/scorpion/dependency_map_spec.rb +108 -0
- data/spec/lib/scorpion/dependency_spec.rb +131 -0
- data/spec/lib/scorpion/hunt_spec.rb +93 -0
- data/spec/lib/scorpion/hunter_spec.rb +53 -14
- data/spec/lib/scorpion/object_constructor_spec.rb +49 -0
- data/spec/lib/scorpion/object_spec.rb +214 -0
- data/spec/lib/scorpion/rails/active_record/association_spec.rb +26 -0
- data/spec/lib/scorpion/rails/active_record/model_spec.rb +33 -0
- data/spec/lib/scorpion/rails/active_record/relation_spec.rb +72 -0
- data/spec/lib/scorpion/rails/controller_spec.rb +9 -9
- data/spec/lib/scorpion/rails/job_spec.rb +34 -0
- data/spec/lib/scorpion/rspec/helper_spec.rb +44 -0
- data/spec/lib/scorpion_spec.rb +0 -35
- data/spec/spec_helper.rb +1 -0
- metadata +54 -26
- data/lib/scorpion/hunting_map.rb +0 -139
- data/lib/scorpion/prey/captured_prey.rb +0 -44
- data/lib/scorpion/prey/class_prey.rb +0 -13
- data/lib/scorpion/prey/hunted_prey.rb +0 -14
- data/lib/scorpion/prey/module_prey.rb +0 -14
- data/lib/scorpion/prey.rb +0 -94
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/lib/scorpion/hunting_map_spec.rb +0 -126
- data/spec/lib/scorpion/instance_spec.rb +0 -5
- data/spec/lib/scorpion/king_spec.rb +0 -198
- data/spec/lib/scorpion/prey/builder_prey_spec.rb +0 -42
- data/spec/lib/scorpion/prey/module_prey_spec.rb +0 -16
- data/spec/lib/scorpion/prey_spec.rb +0 -76
data/lib/scorpion/rails.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Scorpion
|
2
|
+
module Rspec
|
3
|
+
module Helper
|
4
|
+
|
5
|
+
def self.included( base )
|
6
|
+
base.let( :scorpion ){ Scorpion::Rspec.scorpion_nest.conceive }
|
7
|
+
base.send :extend, Scorpion::Rspec::Helper::Methods
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
module Methods
|
14
|
+
|
15
|
+
def scorpion( &block )
|
16
|
+
before( :each ) do
|
17
|
+
scorpion.prepare &block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'scorpion'
|
2
|
+
|
3
|
+
module Scorpion
|
4
|
+
module Rspec
|
5
|
+
require 'scorpion/rspec/helper'
|
6
|
+
|
7
|
+
def self.scorpion_nest
|
8
|
+
@scorpion ||= Scorpion::Nest.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Prepare a root scorpion for testing.
|
12
|
+
def self.prepare( &block )
|
13
|
+
scorpion_nest.prepare &block
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Scorpion
|
2
|
+
# Utility methods for propagating a Scorpion to returned objects.
|
3
|
+
module Stinger
|
4
|
+
@wrappers ||= {}
|
5
|
+
|
6
|
+
def self.wrap( instance, stinger )
|
7
|
+
return instance unless instance
|
8
|
+
|
9
|
+
klass = @wrappers[instance.class] ||=
|
10
|
+
Class.new( instance.class ) do
|
11
|
+
def initialize( instance, stinger )
|
12
|
+
@__instance__ = instance
|
13
|
+
@__stinger__ = stinger
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond_to?( *args )
|
17
|
+
@__instance__.respond_to?( *args )
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def method_missing( *args, &block )
|
22
|
+
binding.pry
|
23
|
+
@__stinger__.sting! @__instance__.__send__( *args, &block )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
klass.new instance, stinger
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sting an object so that it will be injected with the scorpion and use it
|
31
|
+
# to resolve all dependencies.
|
32
|
+
# @param [#scorpion] object to sting.
|
33
|
+
# @return [object] the object that was stung.
|
34
|
+
def sting!( object )
|
35
|
+
return object unless scorpion
|
36
|
+
|
37
|
+
if object
|
38
|
+
assign_scorpion object
|
39
|
+
assign_scorpion_to_enumerable object
|
40
|
+
end
|
41
|
+
|
42
|
+
object
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def assign_scorpion( object )
|
48
|
+
return unless object.respond_to?( :scorpion=, true )
|
49
|
+
|
50
|
+
# Only set scorpion if it hasn't been set yet.
|
51
|
+
current_scorpion = object.send :scorpion
|
52
|
+
if current_scorpion
|
53
|
+
scorpion.logger.warn I18n.translate :mixed_scorpions, scope: [:scorpion,:warnings,:messages] if current_scorpion != scorpion
|
54
|
+
else
|
55
|
+
object.send :scorpion=, scorpion
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def assign_scorpion_to_enumerable( objects )
|
60
|
+
return unless objects.respond_to? :each
|
61
|
+
|
62
|
+
# Don't eager load relations that haven't been loaded yet.
|
63
|
+
return if objects.respond_to?( :loaded? ) && ! objects.loaded?
|
64
|
+
|
65
|
+
objects.each{ |v| sting! v }
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
data/lib/scorpion/version.rb
CHANGED
data/lib/scorpion.rb
CHANGED
@@ -3,77 +3,65 @@ require 'i18n'
|
|
3
3
|
I18n.load_path += Dir[ File.expand_path( '../scorpion/locale/*.yml', __FILE__ ) ]
|
4
4
|
|
5
5
|
module Scorpion
|
6
|
+
|
6
7
|
require 'scorpion/version'
|
7
8
|
require 'scorpion/error'
|
8
|
-
require 'scorpion/
|
9
|
+
require 'scorpion/object'
|
10
|
+
require 'scorpion/object_constructor'
|
9
11
|
require 'scorpion/attribute_set'
|
10
12
|
require 'scorpion/hunter'
|
11
|
-
require 'scorpion/
|
12
|
-
require 'scorpion/
|
13
|
+
require 'scorpion/dependency_map'
|
14
|
+
require 'scorpion/hunt'
|
15
|
+
require 'scorpion/dependency'
|
13
16
|
require 'scorpion/nest'
|
17
|
+
require 'scorpion/stinger'
|
14
18
|
require 'scorpion/rails'
|
15
19
|
|
16
|
-
# @return [Scorpion] main scorpion for the app.
|
17
|
-
def self.instance
|
18
|
-
@instance
|
19
|
-
end
|
20
|
-
@instance = Scorpion::Hunter.new
|
21
|
-
|
22
|
-
# Prepare the {#instance} for hunting.
|
23
|
-
def self.prepare( &block )
|
24
|
-
instance.prepare &block
|
25
|
-
end
|
26
|
-
|
27
20
|
# Hunts for an object that satisfies the requested `contract` and `traits`.
|
28
|
-
# @param [Class,Module,Symbol] contract describing the desired behavior of the
|
29
|
-
# @param [Array<Symbol>] traits required of the
|
30
|
-
# @return [Object] an object that
|
21
|
+
# @param [Class,Module,Symbol] contract describing the desired behavior of the dependency.
|
22
|
+
# @param [Array<Symbol>] traits required of the dependency
|
23
|
+
# @return [Object] an object that satisfies the contract and traits.
|
31
24
|
# @raise [UnsuccessfulHunt] if a matching object cannot be found.
|
32
|
-
def
|
33
|
-
|
25
|
+
def fetch_by_traits( contract, traits, *args, &block )
|
26
|
+
hunt = Hunt.new( self, contract, traits, *args, &block )
|
27
|
+
execute hunt
|
34
28
|
end
|
35
|
-
alias_method :fetch_by_traits, :hunt_by_traits
|
36
29
|
|
37
30
|
# Hunts for an object that satisfies the requested `contract` regardless of
|
38
31
|
# traits.
|
39
|
-
# @see #
|
40
|
-
def
|
41
|
-
|
42
|
-
end
|
43
|
-
alias_method :fetch, :hunt
|
44
|
-
|
45
|
-
# Populate given `king` with its expected attributes.
|
46
|
-
# @param [Scorpion::King] king to be fed.
|
47
|
-
# @return [Scorpion::King] the populated king.
|
48
|
-
def feed( king )
|
49
|
-
king.injected_attributes.each do |attr|
|
50
|
-
next if king.send "#{ attr.name }?"
|
51
|
-
|
52
|
-
king.send :feed, attr, hunt_by_traits( attr.contract, attr.traits )
|
53
|
-
end
|
32
|
+
# @see #fetch_by_traits
|
33
|
+
def fetch( contract, *args, &block )
|
34
|
+
fetch_by_traits( contract, nil, *args, &block )
|
54
35
|
end
|
55
36
|
|
56
|
-
# Creates a new
|
57
|
-
# @param [Class]
|
37
|
+
# Creates a new object and feeds it it's dependencies.
|
38
|
+
# @param [Class] object_class a class that includes {Scorpion::Object}.
|
58
39
|
# @param [Array<Object>] args to pass to the constructor.
|
59
40
|
# @param [#call] block to pass to the constructor.
|
60
|
-
# @return [Scorpion::
|
61
|
-
def spawn(
|
62
|
-
if
|
63
|
-
|
41
|
+
# @return [Scorpion::Object] the spawned object.
|
42
|
+
def spawn( hunt, object_class, *args, &block )
|
43
|
+
if object_class < Scorpion::Object
|
44
|
+
object_class.spawn hunt, *args, &block
|
64
45
|
else
|
65
|
-
|
46
|
+
object_class.new *args, &block
|
66
47
|
end
|
67
48
|
end
|
68
49
|
|
50
|
+
# Execute the `hunt` returning the desired dependency.
|
51
|
+
# @param [Hunt] hunt to execute.
|
52
|
+
# @return [Object] an object that satisfies the hunt contract and traits.
|
53
|
+
def execute( hunt )
|
54
|
+
fail "Not implemented"
|
55
|
+
end
|
56
|
+
|
69
57
|
# Creates a new {Scorpion} copying the current configuration any any currently
|
70
|
-
# captured
|
58
|
+
# captured dependency.
|
71
59
|
# @return [Scorpion] the replicated scorpion.
|
72
60
|
def replicate( &block )
|
73
61
|
fail "Not implemented"
|
74
62
|
end
|
75
63
|
|
76
|
-
# Free up any captured
|
64
|
+
# Free up any captured dependency and release any long-held resources.
|
77
65
|
def destroy
|
78
66
|
end
|
79
67
|
|
@@ -82,6 +70,65 @@ module Scorpion
|
|
82
70
|
Scorpion::Nest.new( self )
|
83
71
|
end
|
84
72
|
|
73
|
+
# @!attribute
|
74
|
+
# @return [Logger] logger for the scorpion to use.
|
75
|
+
def logger
|
76
|
+
@logger || Scorpion.logger
|
77
|
+
end
|
78
|
+
def logger=( value )
|
79
|
+
@logger = value
|
80
|
+
end
|
81
|
+
|
82
|
+
# ============================================================================
|
83
|
+
# @!group Convenience Methods
|
84
|
+
#
|
85
|
+
# Module methods to make it easier to work with scorpion configurations. These
|
86
|
+
# _should not_ be used by library level classes. Instead only application
|
87
|
+
# level code (controllers, scripts, etc.) should explicitly access these
|
88
|
+
# methods.
|
89
|
+
|
90
|
+
# @return [Scorpion] main scorpion for the app.
|
91
|
+
def self.instance
|
92
|
+
@instance
|
93
|
+
end
|
94
|
+
@instance = Scorpion::Hunter.new
|
95
|
+
|
96
|
+
# Prepare the {#instance} for hunting.
|
97
|
+
# @param [Boolean] reset true to free all existing resource and initialize a
|
98
|
+
# new scorpion.
|
99
|
+
def self.prepare( reset = false, &block )
|
100
|
+
if reset
|
101
|
+
@instance.destroy
|
102
|
+
@instance = Scorpion::Hunter.new
|
103
|
+
end
|
104
|
+
instance.prepare &block
|
105
|
+
end
|
106
|
+
|
107
|
+
# Hunt for dependency from the primary Scorpion {#instance}.
|
108
|
+
# @see #fetch
|
109
|
+
def self.fetch( *args, &block )
|
110
|
+
instance.fetch *args, &block
|
111
|
+
end
|
112
|
+
|
113
|
+
# Hunt for dependency from the primary Scorpion {#instance}.
|
114
|
+
# @see #fetch_by_traits
|
115
|
+
def self.fetch_by_traits( *args, &block )
|
116
|
+
instance.fetch_by_traits *args, &block
|
117
|
+
end
|
118
|
+
|
119
|
+
# @!attribute logger
|
120
|
+
# @return [Logger] logger for the Scorpion framework to use.
|
121
|
+
def self.logger
|
122
|
+
@logger ||= defined?( ::Rails ) ? ::Rails.logger : Logger.new( STDOUT )
|
123
|
+
end
|
124
|
+
def self.logger=( value )
|
125
|
+
@logger = value
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# @!endgroup Convenience Methods
|
130
|
+
|
131
|
+
|
85
132
|
private
|
86
133
|
|
87
134
|
# Used by concrete scorpions to notify the caller that the hunt was
|
data/scorpion.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency 'rails', '~> 4.0'
|
22
|
-
spec.required_ruby_version = '>=
|
22
|
+
spec.required_ruby_version = '>= 2.0.0'
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
25
|
spec.add_development_dependency "rake", '~> 10'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Author < ActiveRecord::Base
|
2
|
+
|
3
|
+
# @!attribute name
|
4
|
+
# @return [String]
|
5
|
+
|
6
|
+
|
7
|
+
# @!attribute
|
8
|
+
# @return [ActiveRecord::Relation<Todo>]
|
9
|
+
has_many :todos, inverse_of: :author
|
10
|
+
|
11
|
+
scope :named, ->( name ) { where( name: name ) } do
|
12
|
+
def alphabetical
|
13
|
+
order( :name )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/internal/db/schema.rb
CHANGED
@@ -1,3 +1,14 @@
|
|
1
1
|
ActiveRecord::Schema.define do
|
2
|
-
#
|
2
|
+
#ActiveRecord::Schema.define do
|
3
|
+
create_table( :todos, :force => true ) do |t|
|
4
|
+
t.string :name
|
5
|
+
t.references :author
|
6
|
+
t.timestamps null: false
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table( :authors, :force => true ) do |t|
|
10
|
+
t.string :name
|
11
|
+
t.timestamps null: false
|
12
|
+
end
|
13
|
+
|
3
14
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Scorpion::Dependency::ArgumentDependency do
|
4
|
+
let( :dependency ) { Scorpion::Dependency::ArgumentDependency.new( arg ) }
|
5
|
+
let( :arg ) { "Hello" }
|
6
|
+
|
7
|
+
it "matches the same type" do
|
8
|
+
expect( dependency.satisfies?( String ) ).to be_truthy
|
9
|
+
end
|
10
|
+
|
11
|
+
it "doesn't match different types" do
|
12
|
+
expect( dependency.satisfies?( Regexp ) ).to be_falsy
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't match traits" do
|
16
|
+
expect( dependency.satisfies?( String, :password ) ).to be_falsy
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module BuilderDependency
|
5
|
+
class ClassDelegate
|
6
|
+
def call( hunt, *args, &block )
|
7
|
+
Test
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ModDelegate
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def call( hunt, *args, &block )
|
15
|
+
Test
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Scorpion::Dependency::BuilderDependency do
|
22
|
+
let( :scorpion ){ double }
|
23
|
+
let( :hunt ){ Scorpion::Hunt.new( scorpion, String, nil ) }
|
24
|
+
|
25
|
+
it "supports class hunting delegates" do
|
26
|
+
dependency = Scorpion::Dependency::BuilderDependency.new( String, nil, Test::BuilderDependency::ClassDelegate.new )
|
27
|
+
expect( dependency.fetch( hunt ) ).to be Test
|
28
|
+
end
|
29
|
+
|
30
|
+
it "supports module hunting delegates" do
|
31
|
+
dependency = Scorpion::Dependency::BuilderDependency.new( String, nil, Test::BuilderDependency::ModDelegate )
|
32
|
+
expect( dependency.fetch( hunt ) ).to be Test
|
33
|
+
end
|
34
|
+
|
35
|
+
it "supports block hunting delegates" do
|
36
|
+
dependency = Scorpion::Dependency::BuilderDependency.new( String, nil ) do
|
37
|
+
Test
|
38
|
+
end
|
39
|
+
expect( dependency.fetch( hunt ) ).to be Test
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module ModuleDependency
|
5
|
+
module Example; end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
describe Scorpion::Dependency::ModuleDependency do
|
9
|
+
let( :scorpion ){ double }
|
10
|
+
let( :dependency ) { Scorpion::Dependency::ModuleDependency.new( Test::ModuleDependency::Example ) }
|
11
|
+
|
12
|
+
it "returns the module itself" do
|
13
|
+
expect( dependency.fetch( scorpion ) ).to be Test::ModuleDependency::Example
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module DependencyMap
|
5
|
+
class Weapon; end
|
6
|
+
class Armor; end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Scorpion::DependencyMap do
|
11
|
+
let( :scorpion ){ double Scorpion }
|
12
|
+
let( :map ){ Scorpion::DependencyMap.new scorpion }
|
13
|
+
|
14
|
+
describe "#chart" do
|
15
|
+
it "yields itself when arg expected" do
|
16
|
+
map.chart do |itself|
|
17
|
+
expect( map ).to be itself
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#find" do
|
23
|
+
it "returns a match" do
|
24
|
+
map.chart do
|
25
|
+
hunt_for Test::DependencyMap::Weapon
|
26
|
+
hunt_for Test::DependencyMap::Armor
|
27
|
+
end
|
28
|
+
|
29
|
+
expect( map.find( Test::DependencyMap::Armor ).contract ).to eq Test::DependencyMap::Armor
|
30
|
+
end
|
31
|
+
|
32
|
+
it "returns nil when no match" do
|
33
|
+
map.chart do
|
34
|
+
hunt_for Test::DependencyMap::Weapon
|
35
|
+
end
|
36
|
+
|
37
|
+
expect( map.find( Test::DependencyMap::Armor ) ).to be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns nil when no match" do
|
41
|
+
map.chart do
|
42
|
+
hunt_for Test::DependencyMap::Weapon
|
43
|
+
end
|
44
|
+
|
45
|
+
expect( map.find( Test::DependencyMap::Armor ) ).to be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
context "multiple possible matches" do
|
50
|
+
before( :each ) do
|
51
|
+
map.chart do
|
52
|
+
hunt_for Test::DependencyMap::Weapon, [ :sharp, :one_handed ]
|
53
|
+
hunt_for Test::DependencyMap::Weapon, [ :blunt, :one_handed ]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns the last dependency that matches one trait" do
|
58
|
+
expect( map.find( Test::DependencyMap::Weapon, :one_handed ).traits ).to include :blunt
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns the last dependency that matches all of the traits" do
|
62
|
+
expect( map.find( Test::DependencyMap::Weapon, [ :one_handed, :blunt ] ).traits ).to include :blunt
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns the last dependency that matches a unique trait" do
|
66
|
+
expect( map.find( Test::DependencyMap::Weapon, :blunt ).traits ).to include :blunt
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#hunt_for" do
|
72
|
+
it "adds a Dependency" do
|
73
|
+
expect( map ).to be_empty
|
74
|
+
|
75
|
+
map.chart do
|
76
|
+
hunt_for Test::DependencyMap::Weapon
|
77
|
+
end
|
78
|
+
|
79
|
+
expect( map.first ).to be_a Scorpion::Dependency
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#replicate_from" do
|
84
|
+
it "does not dup shared dependency" do
|
85
|
+
map.chart do
|
86
|
+
share do
|
87
|
+
capture Test::DependencyMap::Weapon
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
replica = Scorpion::DependencyMap.new scorpion
|
92
|
+
replica.replicate_from( map )
|
93
|
+
|
94
|
+
expect( replica ).to be_empty
|
95
|
+
end
|
96
|
+
|
97
|
+
it "dups captured dependency" do
|
98
|
+
map.chart do
|
99
|
+
capture Test::DependencyMap::Weapon
|
100
|
+
end
|
101
|
+
|
102
|
+
replica = Scorpion::DependencyMap.new scorpion
|
103
|
+
replica.replicate_from( map )
|
104
|
+
|
105
|
+
expect( replica ).not_to be_empty
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module Dependency
|
5
|
+
module Mod; end
|
6
|
+
class Base; end
|
7
|
+
class Derived < Base
|
8
|
+
include Mod
|
9
|
+
end
|
10
|
+
|
11
|
+
class Footwear
|
12
|
+
def self.create( scorpion, *args, &block )
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Scorpion::Dependency do
|
21
|
+
context "inheritance" do
|
22
|
+
let( :dependency ){ Scorpion::Dependency.new( Test::Dependency::Derived ) }
|
23
|
+
|
24
|
+
it "matches more derived class when looking for base class" do
|
25
|
+
expect( dependency.satisfies? Test::Dependency::Base ).to be_truthy
|
26
|
+
end
|
27
|
+
|
28
|
+
it "matches same class when looking for base class" do
|
29
|
+
expect( dependency.satisfies? Test::Dependency::Derived ).to be_truthy
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not inherit symbols" do
|
33
|
+
expect( Scorpion::Dependency.new( :a ).satisfies? :b ).to be_falsy
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can satisfy a module with a class" do
|
37
|
+
expect( dependency.satisfies? Test::Dependency::Mod ).to be_truthy
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "traits" do
|
43
|
+
|
44
|
+
context "symbolic" do
|
45
|
+
let( :dependency ){ Scorpion::Dependency.new Test::Dependency::Base, :apples }
|
46
|
+
it "satisfies matched traits" do
|
47
|
+
expect( dependency.satisfies? Test::Dependency::Base, :apples ).to be_truthy
|
48
|
+
end
|
49
|
+
|
50
|
+
it "doesn't satisfy mis-matched traits" do
|
51
|
+
expect( dependency.satisfies? Test::Dependency::Base, :oranges ).to be_falsy
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "module" do
|
56
|
+
let( :dependency ){ Scorpion::Dependency.new Test::Dependency::Derived }
|
57
|
+
|
58
|
+
it "satisfies module traits" do
|
59
|
+
expect( dependency.satisfies? Test::Dependency::Base, Test::Dependency::Derived ).to be_truthy
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
it "can satisfy symbol contracts" do
|
66
|
+
expect( Scorpion::Dependency.new( :symbol ).satisfies? :symbol ).to be_truthy
|
67
|
+
end
|
68
|
+
|
69
|
+
it "satisfies ignores tail hash traits" do
|
70
|
+
expect( Scorpion::Dependency.new( Test::Dependency::Base ).satisfies?( Test::Dependency::Base, ) )
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "equality" do
|
74
|
+
let( :dependency ) { Scorpion::Dependency.new( Test::Dependency::Derived ) }
|
75
|
+
let( :same ) { Scorpion::Dependency.new( Test::Dependency::Derived ) }
|
76
|
+
let( :different ) { Scorpion::Dependency.new( Test::Dependency::Base ) }
|
77
|
+
|
78
|
+
specify{ expect( dependency ).to eq same }
|
79
|
+
specify{ expect( dependency ).not_to eq different }
|
80
|
+
specify{ expect( dependency.hash ).to eq same.hash }
|
81
|
+
end
|
82
|
+
|
83
|
+
describe ".define" do
|
84
|
+
let( :scorpion ){ double Scorpion }
|
85
|
+
let( :hunt ) { Scorpion::Hunt.new scorpion, String, nil }
|
86
|
+
|
87
|
+
it "is a ClassDependency for class hunts" do
|
88
|
+
dependency = Scorpion::Dependency.define String
|
89
|
+
expect( dependency ).to be_a Scorpion::Dependency::ClassDependency
|
90
|
+
end
|
91
|
+
|
92
|
+
it "is a ModuleDependency for module hunts" do
|
93
|
+
dependency = Scorpion::Dependency.define Test::Dependency::Mod
|
94
|
+
expect( dependency ).to be_a Scorpion::Dependency::ModuleDependency
|
95
|
+
end
|
96
|
+
|
97
|
+
it "is a BuilderDependency for return: instances" do
|
98
|
+
dependency = Scorpion::Dependency.define String, return: "AWESEOME"
|
99
|
+
|
100
|
+
expect( dependency ).to be_a Scorpion::Dependency::BuilderDependency
|
101
|
+
expect( dependency.fetch hunt ).to eq "AWESEOME"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "is a BuilderDependency for block hunts" do
|
105
|
+
dependency = Scorpion::Dependency.define String do
|
106
|
+
"YASS"
|
107
|
+
end
|
108
|
+
|
109
|
+
expect( dependency ).to be_a Scorpion::Dependency::BuilderDependency
|
110
|
+
end
|
111
|
+
|
112
|
+
it "is a BuilderDependency for with: option" do
|
113
|
+
dependency = Scorpion::Dependency.define String, with: ->(scorpion,*args,&block){ "YASSS" }
|
114
|
+
|
115
|
+
expect( dependency ).to be_a Scorpion::Dependency::BuilderDependency
|
116
|
+
expect( dependency.fetch hunt ).to eq "YASSS"
|
117
|
+
end
|
118
|
+
|
119
|
+
it "is a BuilderDependency when hunted class implements #create" do
|
120
|
+
dependency = Scorpion::Dependency.define Test::Dependency::Footwear
|
121
|
+
hunt = Scorpion::Hunt.new scorpion, String, nil do
|
122
|
+
"Nike"
|
123
|
+
end
|
124
|
+
|
125
|
+
expect( dependency ).to be_a Scorpion::Dependency::BuilderDependency
|
126
|
+
expect( dependency.fetch( hunt ) ).to eq "Nike"
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|