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
@@ -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