scorpion-ioc 0.6.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -18,56 +18,36 @@ module Scorpion
18
18
  @contract
19
19
  end
20
20
 
21
- # @!attribute
22
- # @return [Array<Symbol>] traits that must match on instances of the {#contract}
23
- attr_reader :traits
24
-
25
21
  # @!attribute
26
22
  # @return [Boolean] true if the attribute is not immediately required and
27
23
  # will be hunted down on first use.
28
- def lazy?; @lazy end
24
+ def lazy?
25
+ @lazy
26
+ end
29
27
 
30
28
  # @!attribute
31
29
  # @return [Boolean] true if the attribute should have a public writer.
32
- def public?; @public end
30
+ def public?
31
+ @public
32
+ end
33
33
 
34
34
  # @!attribute
35
35
  # @return [Boolean] true if the attribute should have a public writer.
36
- def private?; @private end
36
+ def private?
37
+ @private
38
+ end
37
39
 
38
40
  #
39
41
  # @!endgroup Attributes
40
42
 
41
43
 
42
- def initialize( name, contract, traits = nil, options = {} )
44
+ def initialize( name, contract, lazy: false, public: false, private: false )
43
45
  @name = name.to_sym
44
46
  @contract = contract
45
- @traits = Array( traits ).flatten.freeze
46
- @trait_set = Set.new( @traits.map{ |t| :"#{t}?" } )
47
- @lazy = options.fetch( :lazy, false )
48
- @public = options.fetch( :public, false )
49
- @private = options.fetch( :private, false )
47
+ @lazy = lazy
48
+ @public = public
49
+ @private = private
50
50
  end
51
51
 
52
- def respond_to?( name, include_all = false )
53
- super || trait_set.include?( name )
54
- end
55
-
56
- private
57
- # @return [Set] the set of traits associated with the attribute pre-processed
58
- # to include the trait names with a '?' suffix.
59
- attr_reader :trait_set
60
-
61
- def method_missing( name, *args )
62
- if is_trait_method?( name )
63
- trait_set.include? name
64
- else
65
- super
66
- end
67
- end
68
-
69
- def is_trait_method?( name )
70
- name[-1] == '?'
71
- end
72
52
  end
73
- end
53
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/attribute'
1
+ require "scorpion/attribute"
2
2
 
3
3
  module Scorpion
4
4
  class AttributeSet
@@ -13,7 +13,7 @@ module Scorpion
13
13
  end
14
14
 
15
15
  def each( &block )
16
- attributes.each do |k,v|
16
+ attributes.each_value do |v|
17
17
  yield v
18
18
  end
19
19
  end
@@ -36,9 +36,8 @@ module Scorpion
36
36
  end
37
37
 
38
38
  # Defines the food that {Scorpion::Object} will feed on. A food is defined by
39
- # invoking a method with the desired name passing the contract and traits
40
- # desired. AttributeSet uses method_missing to dynamically define
41
- # attributes.
39
+ # invoking a method with the desired name passing the contract desired.
40
+ # AttributeSet uses method_missing to dynamically define attributes.
42
41
  #
43
42
  # If the block takes an argument, AttributeSet will yield to the block
44
43
  # passing itself. If no argument is provided, yield will use the
@@ -71,16 +70,13 @@ module Scorpion
71
70
  end
72
71
 
73
72
  # Define a single attribute with the given name that expects food that will
74
- # satisfy the contract and traits.
73
+ # satisfy the contract.
75
74
  # @param [String] name of the attribute.
76
75
  # @param [Class,Module,Symbol] contract that describes the desired behavior
77
76
  # of the injected object.
78
- # @param [Array<Symbol>] traits that must match on instances of the {#contract}
79
77
  # @return [Attribute] the attribute that was created.
80
- def define_attribute( name, contract, *traits )
81
- options = traits.pop if traits.last.is_a? Hash
82
- options ||= {}
83
- attributes[name.to_sym] = Attribute.new name, contract, traits, options
78
+ def define_attribute( name, contract, **options )
79
+ attributes[name.to_sym] = Attribute.new name, contract, options
84
80
  end
85
81
 
86
82
 
@@ -90,7 +86,7 @@ module Scorpion
90
86
 
91
87
  private
92
88
 
93
- def method_missing( name, *args )
89
+ def method_missing( name, *args ) # rubocop:disable Style/MethodMissing
94
90
  return super unless @defining_attributes
95
91
 
96
92
  if args.length >= 1
@@ -100,5 +96,7 @@ module Scorpion
100
96
  end
101
97
  end
102
98
 
99
+
100
+
103
101
  end
104
- end
102
+ end
@@ -39,7 +39,7 @@ module Scorpion
39
39
  scorpions.each do |hunter|
40
40
  begin
41
41
  return hunter.execute( hunt, true )
42
- rescue UnsuccessfulHunt
42
+ rescue UnsuccessfulHunt # rubocop:disable Lint/HandleExceptions
43
43
  end
44
44
  end
45
45
 
@@ -47,12 +47,12 @@ module Scorpion
47
47
  scorpions.each do |hunter|
48
48
  begin
49
49
  return hunter.execute( hunt )
50
- rescue UnsuccessfulHunt
50
+ rescue UnsuccessfulHunt # rubocop:disable Lint/HandleExceptions
51
51
  end
52
52
  end
53
53
 
54
- unsuccessful_hunt hunt.contract, hunt.traits
54
+ unsuccessful_hunt hunt.contract
55
55
  end
56
56
 
57
57
  end
58
- end
58
+ end
@@ -2,11 +2,11 @@ module Scorpion
2
2
  # Dependency that can be injected into a {Scorpion::Object} by a {Scorpion}.
3
3
  class Dependency
4
4
 
5
- require 'scorpion/dependency/captured_dependency'
6
- require 'scorpion/dependency/class_dependency'
7
- require 'scorpion/dependency/module_dependency'
8
- require 'scorpion/dependency/builder_dependency'
9
- require 'scorpion/dependency/argument_dependency'
5
+ require "scorpion/dependency/captured_dependency"
6
+ require "scorpion/dependency/class_dependency"
7
+ require "scorpion/dependency/module_dependency"
8
+ require "scorpion/dependency/builder_dependency"
9
+ require "scorpion/dependency/argument_dependency"
10
10
 
11
11
  # ============================================================================
12
12
  # @!group Attributes
@@ -14,23 +14,18 @@ module Scorpion
14
14
 
15
15
  # @!attribute
16
16
  # @return [Class,Module,Symbol] contract describing the desired behavior of the dependency.
17
- attr_reader :contract
18
-
19
- # @!attribute
20
- # @return [Array<Symbol>] the traits available on the dependency.
21
- attr_reader :traits
17
+ attr_reader :contract
22
18
 
23
19
  #
24
20
  # @!endgroup Attributes
25
21
 
26
- def initialize( contract, traits = nil )
22
+ def initialize( contract )
27
23
  @contract = contract
28
- @traits = Set.new( Array( traits ) )
29
24
  end
30
25
 
31
- # @return [Boolean] if the dependency satisfies the required contract and traits.
32
- def satisfies?( contract, traits = nil )
33
- satisfies_contract?( contract ) && satisfies_traits?( traits )
26
+ # @return [Boolean] if the dependency satisfies the required contract.
27
+ def satisfies?( contract )
28
+ satisfies_contract?( contract )
34
29
  end
35
30
 
36
31
  # Fetch an instance of the dependency.
@@ -52,21 +47,16 @@ module Scorpion
52
47
 
53
48
  def ==( other )
54
49
  return unless other
55
- self.class == other.class &&
56
- contract == other.contract &&
57
- traits == other.traits
50
+ self.class == other.class && contract == other.contract
58
51
  end
59
52
  alias_method :eql?, :==
60
53
 
61
54
  def hash
62
- self.class.hash ^
63
- contract.hash ^
64
- traits.hash
55
+ self.class.hash ^ contract.hash
65
56
  end
66
57
 
67
58
  def inspect
68
59
  result = "<#{ contract.inspect }"
69
- result << " traits=#{ traits.to_a.inspect }" if traits.present?
70
60
  result << ">"
71
61
  result
72
62
  end
@@ -82,60 +72,34 @@ module Scorpion
82
72
  end
83
73
  end
84
74
 
85
- # @return [Boolean] true if the pray satisfies the given contract.
86
- def satisfies_traits?( traits )
87
- return true if traits.blank?
88
-
89
- Array( traits ).all? do |trait|
90
- case trait
91
- when Symbol then self.traits.include? trait
92
- when Module then self.contract <= trait
93
- else fail ArgumentError, "Unsupported trait"
94
- end
95
- end
96
- end
97
-
98
75
  class << self
99
76
 
100
- # Define dependency based on the desired contract and traits.
77
+ # Define dependency based on the desired contract.
101
78
  # @return [Dependency] the defined dependency.
102
- def define( contract, traits = nil, &builder )
103
- options, traits = extract_options!( traits )
104
-
79
+ def define( contract, options = {}, &builder )
105
80
  if options.key?( :return )
106
- Scorpion::Dependency::BuilderDependency.new( contract, traits ) do
81
+ Scorpion::Dependency::BuilderDependency.new( contract ) do
107
82
  options[:return]
108
83
  end
109
- elsif with = options[:with]
110
- Scorpion::Dependency::BuilderDependency.new( contract, traits, with )
84
+ elsif with = options[ :with ]
85
+ Scorpion::Dependency::BuilderDependency.new( contract, with )
111
86
  elsif block_given?
112
- Scorpion::Dependency::BuilderDependency.new( contract, traits, builder )
87
+ Scorpion::Dependency::BuilderDependency.new( contract, builder )
113
88
 
114
89
  # Allow a Class/Module to define a #create method that will resolve
115
90
  # and return an instance of itself. Do not automatically inherit the
116
91
  # #create method so only consider it if the owner of the method is the
117
92
  # contract itself.
118
93
  elsif contract.respond_to?( :create ) && contract.singleton_methods( false ).include?( :create )
119
- Scorpion::Dependency::BuilderDependency.new( contract, traits ) do |hunt,*args,**dependencies,&block|
120
- contract.create hunt, *args, **dependencies, &block
94
+ Scorpion::Dependency::BuilderDependency.new( contract ) do |hunt, *args, &block|
95
+ contract.create hunt, *args, &block
121
96
  end
122
97
  else
123
- dependency_class( contract ).new( contract, traits, &builder )
98
+ dependency_class( contract ).new( contract, &builder )
124
99
  end
125
100
  end
126
101
 
127
102
  private
128
- def extract_options!( traits )
129
- case traits
130
- when Hash then return [ traits, nil ]
131
- when Array then
132
- if traits.last.is_a? Hash
133
- return [ traits.pop, traits ]
134
- end
135
- end
136
-
137
- [ {}, traits]
138
- end
139
103
 
140
104
  def dependency_class( contract, &builder )
141
105
  return Scorpion::Dependency::ClassDependency if contract.is_a? Class
@@ -146,4 +110,4 @@ module Scorpion
146
110
  end
147
111
 
148
112
  end
149
- end
113
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/dependency'
1
+ require "scorpion/dependency"
2
2
 
3
3
  module Scorpion
4
4
  class Dependency
@@ -16,10 +16,10 @@ module Scorpion
16
16
  argument
17
17
  end
18
18
 
19
- def satisfies?( contract, traits = nil )
20
- contract === argument && traits.blank?
19
+ def satisfies?( contract )
20
+ contract === argument
21
21
  end
22
22
 
23
23
  end
24
24
  end
25
- end
25
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/dependency'
1
+ require "scorpion/dependency"
2
2
 
3
3
  module Scorpion
4
4
  class Dependency
@@ -17,16 +17,16 @@ module Scorpion
17
17
  #
18
18
  # @!endgroup Attributes
19
19
 
20
- def initialize( contract, traits = nil, builder = nil, &block )
20
+ def initialize( contract, builder = nil, &block )
21
21
  @builder = block_given? ? block : builder
22
- super contract, traits
22
+ super contract
23
23
  end
24
24
 
25
25
  # @see Scorpion::Dependency#fetch
26
26
  def fetch( hunt )
27
- builder.call( hunt, *hunt.arguments, **hunt.dependencies, &hunt.block )
27
+ builder.call( hunt, *hunt.arguments, &hunt.block )
28
28
  end
29
29
 
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/dependency'
1
+ require "scorpion/dependency"
2
2
 
3
3
  module Scorpion
4
4
  class Dependency
@@ -20,7 +20,7 @@ module Scorpion
20
20
  private :specific_dependency
21
21
 
22
22
 
23
- delegate [:contract,:traits,:satisfies?] => :specific_dependency
23
+ delegate [ :contract, :satisfies? ] => :specific_dependency
24
24
 
25
25
  #
26
26
  # @!endgroup Attributes
@@ -41,11 +41,9 @@ module Scorpion
41
41
 
42
42
  # @see Dependency#replicate
43
43
  def replicate
44
- dup.tap do |replica|
45
- replica.release
46
- end
44
+ dup.tap(&:release)
47
45
  end
48
46
 
49
47
  end
50
48
  end
51
- end
49
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/dependency'
1
+ require "scorpion/dependency"
2
2
 
3
3
  module Scorpion
4
4
  class Dependency
@@ -6,23 +6,9 @@ module Scorpion
6
6
  class ClassDependency < Scorpion::Dependency
7
7
 
8
8
  def fetch( hunt )
9
- resolved = resolve_dependencies( hunt )
10
- hunt.scorpion.spawn hunt, hunt.contract, *hunt.arguments, **resolved, &hunt.block
9
+ hunt.scorpion.spawn hunt, hunt.contract, *hunt.arguments, &hunt.block
11
10
  end
12
11
 
13
- private
14
-
15
- def resolve_dependencies( hunt )
16
- dependencies = hunt.dependencies
17
- return dependencies unless hunt.contract.respond_to? :initializer_injections
18
-
19
- hunt.contract.initializer_injections.each_with_object(dependencies.dup) do |attr,deps|
20
- next if attr.lazy?
21
-
22
- deps[attr.name] ||= hunt.fetch_by_traits( attr.contract, attr.traits )
23
- end
24
- end
25
-
26
12
  end
27
13
  end
28
- end
14
+ end
@@ -1,4 +1,4 @@
1
- require 'scorpion/dependency'
1
+ require "scorpion/dependency"
2
2
 
3
3
  module Scorpion
4
4
  class Dependency
@@ -1,3 +1,5 @@
1
+ require "forwardable"
2
+
1
3
  module Scorpion
2
4
  # {#chart} available {Dependency} and {#find} them based on desired
3
5
  # {Scorpion::Attribute attributes}.
@@ -33,13 +35,12 @@ module Scorpion
33
35
  reset
34
36
  end
35
37
 
36
- # Find {Dependency} that matches the requested `contract` and `traits`.
38
+ # Find {Dependency} that matches the requested `contract`.
37
39
  # @param [Class,Module,Symbol] contract describing the desired behavior of the dependency.
38
- # @param [Array<Symbol>] traits found on the {Dependency}.
39
40
  # @return [Dependency] the dependency matching the attribute.
40
- def find( contract, traits = nil )
41
- dependency_set.find{ |p| p.satisfies?( contract, traits ) } ||
42
- shared_dependency_set.find{ |p| p.satisfies?( contract, traits ) }
41
+ def find( contract )
42
+ dependency_set.find { |p| p.satisfies?( contract ) } ||
43
+ shared_dependency_set.find { |p| p.satisfies?( contract ) }
43
44
  end
44
45
 
45
46
  # Chart the {Dependency} that this hunting map can {#find}.
@@ -75,24 +76,23 @@ module Scorpion
75
76
  self
76
77
  end
77
78
 
78
- # Define {Dependency} that can be found on this map by `contract` and `traits`.
79
+ # Define {Dependency} that can be found on this map by `contract`.
79
80
  #
80
81
  # If a block is given, it will be used build the actual instances of the
81
82
  # dependency for the {Scorpion}.
82
83
  #
83
84
  # @param [Class,Module,Symbol] contract describing the desired behavior of the dependency.
84
- # @param [Array<Symbol>] traits found on the {Dependency}.
85
85
  # @return [Dependency] the dependency to be hunted for.
86
- def hunt_for( contract, traits = nil, &builder )
87
- active_dependency_set.unshift define_dependency( contract, traits, &builder )
86
+ def hunt_for( contract, **options, &builder )
87
+ active_dependency_set.unshift define_dependency( contract, options, &builder )
88
88
  end
89
89
 
90
90
  # Captures a single dependency and returns the same instance fore each request
91
91
  # for the resource.
92
92
  # @see #hunt_for
93
93
  # @return [Dependency] the dependency to be hunted for.
94
- def capture( contract, traits = nil, &builder )
95
- active_dependency_set.unshift Dependency::CapturedDependency.new( define_dependency( contract, traits, &builder ) )
94
+ def capture( contract, **options, &builder )
95
+ active_dependency_set.unshift Dependency::CapturedDependency.new( define_dependency( contract, options, &builder ) ) # rubocop:disable Metrics/LineLength
96
96
  end
97
97
  alias_method :singleton, :capture
98
98
 
@@ -127,8 +127,8 @@ module Scorpion
127
127
 
128
128
  # Remove all dependency mappings.
129
129
  def reset
130
- @dependency_set.each &:release if @dependency_set
131
- @shared_dependency_set.each &:release if @shared_dependency_set
130
+ @dependency_set&.each &:release
131
+ @shared_dependency_set&.each &:release
132
132
 
133
133
  @dependency_set = @active_dependency_set = []
134
134
  @shared_dependency_set = []
@@ -136,8 +136,8 @@ module Scorpion
136
136
 
137
137
  private
138
138
 
139
- def define_dependency( contract, traits, &builder )
140
- Dependency.define contract, traits, &builder
139
+ def define_dependency( contract, options, &builder )
140
+ Dependency.define contract, options, &builder
141
141
  end
142
142
  end
143
- end
143
+ end