smart_core 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/.rubocop.yml +2 -2
- data/.travis.yml +3 -3
- data/CHANGELOG.md +3 -0
- data/Gemfile +0 -3
- data/README.md +5 -33
- data/Rakefile +2 -0
- data/lib/smart_core/container/command_definer.rb +117 -0
- data/lib/smart_core/container/command_set.rb +82 -0
- data/lib/smart_core/container/commands/base.rb +12 -0
- data/lib/smart_core/container/commands/namespace.rb +53 -0
- data/lib/smart_core/container/commands/register.rb +63 -0
- data/lib/smart_core/container/commands.rb +9 -0
- data/lib/smart_core/container/definition_dsl.rb +66 -0
- data/lib/smart_core/container/dependency.rb +44 -0
- data/lib/smart_core/container/dependency_builder.rb +48 -0
- data/lib/smart_core/container/dependency_compatability/abstract.rb +59 -0
- data/lib/smart_core/container/dependency_compatability/command_set.rb +35 -0
- data/lib/smart_core/container/dependency_compatability/registry.rb +37 -0
- data/lib/smart_core/container/dependency_compatability.rb +9 -0
- data/lib/smart_core/container/dependency_resolver.rb +16 -0
- data/lib/smart_core/container/entity.rb +26 -0
- data/lib/smart_core/container/exceptions.rb +31 -0
- data/lib/smart_core/container/key_guard.rb +31 -0
- data/lib/smart_core/container/memoized_dependency.rb +28 -0
- data/lib/smart_core/container/mixin.rb +82 -0
- data/lib/smart_core/container/namespace.rb +51 -0
- data/lib/smart_core/container/registry.rb +227 -0
- data/lib/smart_core/container/registry_builder.rb +18 -0
- data/lib/smart_core/container.rb +123 -0
- data/lib/smart_core/exceptions.rb +23 -0
- data/lib/smart_core/initializer/attribute/builder.rb +99 -0
- data/lib/smart_core/initializer/attribute/value_finalizer/lambda.rb +32 -0
- data/lib/smart_core/initializer/attribute/value_finalizer/method.rb +32 -0
- data/lib/smart_core/initializer/attribute/value_finalizer.rb +24 -0
- data/lib/smart_core/initializer/attribute.rb +123 -0
- data/lib/smart_core/initializer/attribute_definer.rb +162 -0
- data/lib/smart_core/{operation → initializer}/attribute_set.rb +17 -17
- data/lib/smart_core/initializer/exceptions.rb +47 -0
- data/lib/smart_core/initializer/extension.rb +39 -0
- data/lib/smart_core/initializer/extension_definer.rb +62 -0
- data/lib/smart_core/initializer/extension_set.rb +75 -0
- data/lib/smart_core/{operation → initializer}/initialization_dsl.rb +82 -42
- data/lib/smart_core/initializer/instance_attribute_accessing.rb +49 -0
- data/lib/smart_core/initializer/instance_builder.rb +164 -0
- data/lib/smart_core/initializer/type.rb +49 -0
- data/lib/smart_core/initializer/type_set.rb +52 -0
- data/lib/smart_core/initializer.rb +89 -0
- data/lib/smart_core/injector.rb +6 -0
- data/lib/smart_core/operation/exceptions.rb +4 -20
- data/lib/smart_core/operation/instance_builder.rb +16 -124
- data/lib/smart_core/operation/state.rb +7 -0
- data/lib/smart_core/operation/step.rb +43 -0
- data/lib/smart_core/operation/step_set.rb +73 -0
- data/lib/smart_core/operation/success.rb +11 -0
- data/lib/smart_core/operation.rb +10 -12
- data/lib/smart_core/schema.rb +6 -0
- data/lib/smart_core/validator/commands.rb +2 -0
- data/lib/smart_core/validator/exceptions.rb +1 -1
- data/lib/smart_core/version.rb +1 -1
- data/lib/smart_core.rb +5 -0
- data/smart_core.gemspec +14 -14
- metadata +57 -15
- data/lib/smart_core/operation/attribute.rb +0 -66
- data/lib/smart_core/operation/attribute_definer.rb +0 -160
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.5.0
|
5
|
+
class SmartCore::Initializer::InstanceBuilder
|
6
|
+
class << self
|
7
|
+
# @param processed_object [Any]
|
8
|
+
# @param processed_klass [Class]
|
9
|
+
# @param parameters [Array<Any>]
|
10
|
+
# @param options [Hash<Symbol,Any>]
|
11
|
+
# @return [Any] Fully allocated processed_object
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.5.0
|
15
|
+
def call(processed_object, processed_klass, parameters, options)
|
16
|
+
new(processed_object, processed_klass, parameters, options).call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param processed_object [Any]
|
21
|
+
# @param processed_klass [Class]
|
22
|
+
# @param parameters [Array<Any>]
|
23
|
+
# @param options [Hash<Symbol,Any>]
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 0.5.0
|
28
|
+
def initialize(processed_object, processed_klass, parameters, options)
|
29
|
+
@processed_object = processed_object
|
30
|
+
@processed_klass = processed_klass
|
31
|
+
@parameters = parameters
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Any]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.5.0
|
39
|
+
def call
|
40
|
+
processed_object.tap do
|
41
|
+
prevent_parameters_incomparability
|
42
|
+
initialize_parameters
|
43
|
+
initialize_options
|
44
|
+
call_original_methods
|
45
|
+
invoke_additional_initialization_steps
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @return [Any]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
# @since 0.5.0
|
55
|
+
attr_reader :processed_object
|
56
|
+
|
57
|
+
# @return [Class]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
# @since 0.5.0
|
61
|
+
attr_reader :processed_klass
|
62
|
+
|
63
|
+
# @return [Array<Any>]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
# @since 0.5.0
|
67
|
+
attr_reader :parameters
|
68
|
+
|
69
|
+
# @return [Hash<Symbol,Any>]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
# @since 0.5.0
|
73
|
+
attr_reader :options
|
74
|
+
|
75
|
+
# An array of the required option attribute names (parameters without default values)
|
76
|
+
#
|
77
|
+
# @return [Array<Symbol>]
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
# @since 0.5.0
|
81
|
+
def required_options
|
82
|
+
processed_klass.__options__.each.reject(&:has_default_value?).map(&:name)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Integer]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
# @since 0.5.0
|
89
|
+
def required_attributes_count
|
90
|
+
processed_klass.__params__.size
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [void]
|
94
|
+
#
|
95
|
+
# @raise [SmartCore::Initializer::AttributeError]
|
96
|
+
# @raise [SmartCore::Initializer::ParameterError]
|
97
|
+
# @raise [SmartCore::Initializer::OptionError]
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
# @since 0.5.0
|
101
|
+
def prevent_parameters_incomparability
|
102
|
+
raise(
|
103
|
+
SmartCore::Initializer::ParameterError,
|
104
|
+
"Wrong number of parameters " \
|
105
|
+
"(given #{parameters.size}, expected #{required_attributes_count})"
|
106
|
+
) unless parameters.size == required_attributes_count
|
107
|
+
|
108
|
+
missing_options = required_options.reject { |option| options.key?(option) }
|
109
|
+
|
110
|
+
raise(
|
111
|
+
SmartCore::Initializer::OptionError,
|
112
|
+
"Missing options: :#{missing_options.join(', :')}"
|
113
|
+
) unless missing_options.empty?
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
# @since 0.5.0
|
120
|
+
def initialize_parameters
|
121
|
+
parameter_objects = processed_klass.__params__
|
122
|
+
parameter_pairs = Hash[parameter_objects.zip(parameters)]
|
123
|
+
|
124
|
+
parameter_pairs.each_pair do |parameter_object, parameter_value|
|
125
|
+
parameter_object.validate_value_type!(parameter_value)
|
126
|
+
final_parameter_value = parameter_object.finalize(parameter_value, processed_object)
|
127
|
+
processed_object.instance_variable_set("@#{parameter_object.name}", final_parameter_value)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [void]
|
132
|
+
#
|
133
|
+
# @api private
|
134
|
+
# @since 0.5.0
|
135
|
+
def initialize_options
|
136
|
+
processed_klass.__options__.each do |option|
|
137
|
+
option_name = option.name
|
138
|
+
option_value = options.fetch(option_name) { option.default_value }.tap do |value|
|
139
|
+
option.validate_value_type!(value)
|
140
|
+
end
|
141
|
+
final_option_value = option.finalize(option_value, processed_object)
|
142
|
+
|
143
|
+
processed_object.instance_variable_set("@#{option_name}", final_option_value)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# @return [void]
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
# @since 0.5.0
|
151
|
+
def invoke_additional_initialization_steps
|
152
|
+
processed_klass.__initialization_extensions__.each do |extension|
|
153
|
+
extension.call(processed_object)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [void]
|
158
|
+
#
|
159
|
+
# @api private
|
160
|
+
# @since 0.5.0
|
161
|
+
def call_original_methods
|
162
|
+
processed_object.send(:initialize, *parameters, **options)
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.5.0
|
5
|
+
class SmartCore::Initializer::Type
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.5.0
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @name [Symbol, String]
|
13
|
+
# @param checker [Proc]
|
14
|
+
# @return [void]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
# @since 0.5.0
|
18
|
+
def initialize(name, checker)
|
19
|
+
unless name.is_a?(String) || name.is_a?(Symbol)
|
20
|
+
raise(SmartCore::Initializer::ArgumentError, 'Type name should be a symbol or a string')
|
21
|
+
end
|
22
|
+
|
23
|
+
unless checker.is_a?(Proc)
|
24
|
+
raise(SmartCore::Initializer::ArgumentError, 'Checker should be a proc')
|
25
|
+
end
|
26
|
+
|
27
|
+
@name = name.to_sym
|
28
|
+
@checker = checker
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param value [Any]
|
32
|
+
# @return [Boolean]
|
33
|
+
#
|
34
|
+
# @raise [SmartCore::Initializer::TypeError]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
# @since 0.5.0
|
38
|
+
def comparable?(value)
|
39
|
+
checker.call(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @return [Proc]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
# @since 0.5.0
|
48
|
+
attr_reader :checker
|
49
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.5.0
|
5
|
+
class SmartCore::Initializer::TypeSet
|
6
|
+
# @return [void]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.5.0
|
10
|
+
def initialize
|
11
|
+
@types = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param name [String, Symbol]
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.5.0
|
19
|
+
def has_type?(name)
|
20
|
+
types.key?(name)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param name [String, Symbol]
|
24
|
+
# @param checker [Proc]
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
# @since 0.5.0
|
29
|
+
def register(name, checker)
|
30
|
+
type = SmartCore::Initializer::Type.new(name, checker)
|
31
|
+
types[type.name] = type
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param name [String, Symbol]
|
35
|
+
# @return [SmartCore::Initializer::Type]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.5.0
|
39
|
+
def resolve(name)
|
40
|
+
types.fetch(name.to_sym)
|
41
|
+
rescue KeyError
|
42
|
+
raise SmartCore::Initializer::UnregisteredTypeError, "type :#{name} is not registered!"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# @return [Hash<Symbol,SmartCore::Initializer::Type>]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
# @since 0.5.0
|
51
|
+
attr_reader :types
|
52
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.5.0
|
5
|
+
module SmartCore::Initializer
|
6
|
+
require_relative 'initializer/exceptions'
|
7
|
+
require_relative 'initializer/attribute'
|
8
|
+
require_relative 'initializer/attribute_set'
|
9
|
+
require_relative 'initializer/attribute_definer'
|
10
|
+
require_relative 'initializer/extension'
|
11
|
+
require_relative 'initializer/extension_set'
|
12
|
+
require_relative 'initializer/extension_definer'
|
13
|
+
require_relative 'initializer/instance_builder'
|
14
|
+
require_relative 'initializer/type'
|
15
|
+
require_relative 'initializer/type_set'
|
16
|
+
require_relative 'initializer/initialization_dsl'
|
17
|
+
require_relative 'initializer/instance_attribute_accessing'
|
18
|
+
|
19
|
+
@__type_set__ = SmartCore::Initializer::TypeSet.new
|
20
|
+
# TODO: convertable attributes and converters (in typeset manner)
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# @param child_klass [Class]
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
# @since 0.5.0
|
28
|
+
def included(child_klass)
|
29
|
+
child_klass.include(InitializationDSL)
|
30
|
+
child_klass.include(InstanceAttributeAccessing)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param name [String, Symbol]
|
34
|
+
# @param checker [Block]
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
# @since 0.5.0
|
39
|
+
def register_type(name, &checker)
|
40
|
+
types.register(name, checker)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param name [String, Symbol]
|
44
|
+
# @return [SmartCore::Initializer::Type]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
# @since 0.5.0
|
48
|
+
def get_type(name)
|
49
|
+
types.resolve(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [SmartCore::Initializer::TypeSet]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
# @since 0.5.0
|
56
|
+
def types
|
57
|
+
@__type_set__
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [void]
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
# @since 0.5.0
|
65
|
+
def initialize(*, **); end
|
66
|
+
|
67
|
+
# @since 0.5.0
|
68
|
+
register_type(:array) { |value| value.is_a?(Array) }
|
69
|
+
# @since 0.5.0
|
70
|
+
register_type(:hash) { |value| value.is_a?(Hash) }
|
71
|
+
# @since 0.5.0
|
72
|
+
register_type(:string) { |value| value.is_a?(String) }
|
73
|
+
# @since 0.5.0
|
74
|
+
register_type(:integer) { |value| value.is_a?(Integer) }
|
75
|
+
# @since 0.5.0
|
76
|
+
register_type(:float) { |value| value.is_a?(Float) }
|
77
|
+
# @since 0.5.0
|
78
|
+
register_type(:proc) { |value| value.is_a?(Proc) }
|
79
|
+
# @since 0.5.0
|
80
|
+
register_type(:numeric) { |value| value.is_a?(Numeric) }
|
81
|
+
# @since 0.5.0
|
82
|
+
register_type(:big_decimal) { |value| value.is_a?(BigDecimal) }
|
83
|
+
# @since 0.5.0
|
84
|
+
register_type(:class) { |value| value.is_a?(Class) }
|
85
|
+
# @since 0.5.0
|
86
|
+
register_type(:boolean) { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
|
87
|
+
# @since 0.5.0
|
88
|
+
register_type(:__any__) { true }
|
89
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
class SmartCore::Operation
|
4
4
|
# @api public
|
5
5
|
# @since 0.2.0
|
6
|
-
Error = Class.new(
|
6
|
+
Error = Class.new(SmartCore::Error)
|
7
7
|
|
8
8
|
# @api public
|
9
9
|
# @since 0.3.0
|
@@ -27,27 +27,11 @@ class SmartCore::Operation
|
|
27
27
|
|
28
28
|
# @api public
|
29
29
|
# @since 0.2.0
|
30
|
-
|
31
|
-
|
32
|
-
# @api public
|
33
|
-
# @since 0.2.0
|
34
|
-
ParameterError = Class.new(ArgumentError)
|
35
|
-
|
36
|
-
# @api public
|
37
|
-
# @since 0.2.0
|
38
|
-
ParamOverlapError = Class.new(ParameterError)
|
39
|
-
|
40
|
-
# @api public
|
41
|
-
# @since 0.2.0
|
42
|
-
OptionError = Class.new(ArgumentError)
|
43
|
-
|
44
|
-
# @api public
|
45
|
-
# @since 0.2.0
|
46
|
-
OptionOverlapError = Class.new(OptionError)
|
30
|
+
IncorrectAttributeNameError = Class.new(Error)
|
47
31
|
|
48
32
|
# @api public
|
49
|
-
# @since 0.
|
50
|
-
|
33
|
+
# @since 0.5.0
|
34
|
+
IncorrectStepNameError = Class.new(Error)
|
51
35
|
|
52
36
|
# @api public
|
53
37
|
# @since 0.2.0
|
@@ -1,49 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# @api private
|
4
|
-
# @since 0.
|
4
|
+
# @since 0.5.0
|
5
5
|
class SmartCore::Operation::InstanceBuilder
|
6
6
|
class << self
|
7
|
-
# @param
|
8
|
-
# @
|
9
|
-
# @param parameters [Array<Any>]
|
10
|
-
# @param options [Hash<Symbol,Any>]
|
11
|
-
# @return [SmartCore::Operation]
|
7
|
+
# @param operation [SmartCore::Operation]
|
8
|
+
# @return [void]
|
12
9
|
#
|
13
10
|
# @api private
|
14
|
-
# @since 0.
|
15
|
-
def call(
|
16
|
-
new(
|
11
|
+
# @since 0.5.0
|
12
|
+
def call(operation)
|
13
|
+
new(operation).call
|
17
14
|
end
|
18
15
|
end
|
19
16
|
|
20
|
-
# @param
|
21
|
-
# @param operation_klass [Class<SmartCore::Operation>]
|
22
|
-
# @param parameters [Array<Any>]
|
23
|
-
# @param options [Hash<Symbol,Any>]
|
17
|
+
# @param operation [SmartCore::Operation]
|
24
18
|
# @return [void]
|
25
19
|
#
|
26
20
|
# @api private
|
27
|
-
# @since 0.
|
28
|
-
def initialize(
|
29
|
-
@
|
30
|
-
@operation_klass = operation_klass
|
31
|
-
@parameters = parameters
|
32
|
-
@options = options
|
21
|
+
# @since 0.5.0
|
22
|
+
def initialize(operation)
|
23
|
+
@operation = operation
|
33
24
|
end
|
34
25
|
|
35
|
-
# @return [
|
26
|
+
# @return [void]
|
36
27
|
#
|
37
28
|
# @api private
|
38
|
-
# @since 0.
|
29
|
+
# @since 0.5.0
|
39
30
|
def call
|
40
|
-
|
41
|
-
prevent_parameters_incomparability
|
42
|
-
initialize_parameters
|
43
|
-
initialize_options
|
44
|
-
call_original_methods
|
45
|
-
make_operation_caller_yieldable
|
46
|
-
end
|
31
|
+
make_operation_caller_yieldable
|
47
32
|
end
|
48
33
|
|
49
34
|
private
|
@@ -51,108 +36,15 @@ class SmartCore::Operation::InstanceBuilder
|
|
51
36
|
# @return [SmartCore::Operation]
|
52
37
|
#
|
53
38
|
# @api private
|
54
|
-
# @since 0.
|
55
|
-
attr_reader :
|
56
|
-
|
57
|
-
# @return [Class<SmartCore::Operation>]
|
58
|
-
#
|
59
|
-
# @api private
|
60
|
-
# @since 0.2.0
|
61
|
-
attr_reader :operation_klass
|
62
|
-
|
63
|
-
# @return [Array<Any>]
|
64
|
-
#
|
65
|
-
# @api private
|
66
|
-
# @since 0.2.0
|
67
|
-
attr_reader :parameters
|
68
|
-
|
69
|
-
# @return [Hash<Symbol,Any>]
|
70
|
-
#
|
71
|
-
# @api private
|
72
|
-
# @since 0.2.0
|
73
|
-
attr_reader :options
|
74
|
-
|
75
|
-
# An array of the required option attribute names (parameters without default values)
|
76
|
-
#
|
77
|
-
# @return [Array<Symbol>]
|
78
|
-
#
|
79
|
-
# @api private
|
80
|
-
# @since 0.2.0
|
81
|
-
def required_options
|
82
|
-
operation_klass.__options__.each.reject(&:has_default_value?).map(&:name)
|
83
|
-
end
|
84
|
-
|
85
|
-
# @return [Integer]
|
86
|
-
#
|
87
|
-
# @api private
|
88
|
-
# @since 0.2.0
|
89
|
-
def required_attributes_count
|
90
|
-
operation_klass.__params__.size
|
91
|
-
end
|
92
|
-
|
93
|
-
# @return [void]
|
94
|
-
#
|
95
|
-
# @raise [SmartCore::Operation::AttributeError]
|
96
|
-
# @raise [SmartCore::Operation::ParameterError]
|
97
|
-
# @raise [SmartCore::Operation::OptionError]
|
98
|
-
#
|
99
|
-
# @api private
|
100
|
-
# @since 0.2.0
|
101
|
-
def prevent_parameters_incomparability
|
102
|
-
raise(
|
103
|
-
SmartCore::Operation::ParameterError,
|
104
|
-
"Wrong number of parameters " \
|
105
|
-
"(given #{parameters.size}, expected #{required_attributes_count})"
|
106
|
-
) unless parameters.size == required_attributes_count
|
107
|
-
|
108
|
-
missing_options = required_options.reject { |option| options.key?(option) }
|
109
|
-
|
110
|
-
raise(
|
111
|
-
SmartCore::Operation::OptionError,
|
112
|
-
"Missing options: :#{missing_options.join(', :')}"
|
113
|
-
) unless missing_options.empty?
|
114
|
-
end
|
115
|
-
|
116
|
-
# @return [void]
|
117
|
-
#
|
118
|
-
# @api private
|
119
|
-
# @since 0.2.0
|
120
|
-
def initialize_parameters
|
121
|
-
parameter_names = operation_klass.__params__.map(&:name)
|
122
|
-
parameter_pairs = Hash[parameter_names.zip(parameters)]
|
123
|
-
|
124
|
-
parameter_pairs.each_pair do |parameter_name, parameter_value|
|
125
|
-
operation_object.instance_variable_set("@#{parameter_name}", parameter_value)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# @return [void]
|
130
|
-
#
|
131
|
-
# @api private
|
132
|
-
# @since 0.2.0
|
133
|
-
def initialize_options
|
134
|
-
operation_klass.__options__.each do |option|
|
135
|
-
option_name = option.name
|
136
|
-
option_value = options.fetch(option_name) { option.default_value }
|
137
|
-
|
138
|
-
operation_object.instance_variable_set("@#{option_name}", option_value)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# @return [void]
|
143
|
-
#
|
144
|
-
# @api private
|
145
|
-
# @since 0.2.0
|
146
|
-
def call_original_methods
|
147
|
-
operation_object.send(:initialize, *parameters, **options)
|
148
|
-
end
|
39
|
+
# @since 0.5.0
|
40
|
+
attr_reader :operation
|
149
41
|
|
150
42
|
# @return [void]
|
151
43
|
#
|
152
44
|
# @api private
|
153
45
|
# @since 0.2.0
|
154
46
|
def make_operation_caller_yieldable
|
155
|
-
|
47
|
+
operation.singleton_class.prepend(Module.new do
|
156
48
|
def call
|
157
49
|
super.tap { |result| yield(result) if block_given? }
|
158
50
|
rescue SmartCore::Operation::FatalError => error
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.5.0
|
5
|
+
class SmartCore::Operation::Step
|
6
|
+
# @return [String, Symbol]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.5.0
|
10
|
+
attr_reader :method_name
|
11
|
+
|
12
|
+
# @return [Hash<Symbol,Any>]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.5.0
|
16
|
+
attr_reader :options
|
17
|
+
|
18
|
+
# @param method_name [String, Symbol]
|
19
|
+
# @param options [Hash<Symbol,Any>]
|
20
|
+
# @return [void]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.5.0
|
24
|
+
def initialize(method_name, **options)
|
25
|
+
unless method_name.is_a?(Symbol) || method_name.is_a?(String)
|
26
|
+
raise(
|
27
|
+
SmartCore::Operation::IncorrectStepNameError,
|
28
|
+
'Step name should be a symbol or a string'
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
@method_name = method_name.to_sym
|
33
|
+
@options = options # TODO: support for another operations
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [SmartCore::Operation::Step]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @since 0.5.0
|
40
|
+
def dup
|
41
|
+
self.class.new(method_name, **options)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.5.0
|
5
|
+
class SmartCore::Operation::StepSet
|
6
|
+
# @since 0.5.0
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# @return [Array<SmartCore:::Operation::Step>]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.5.0
|
13
|
+
attr_reader :steps
|
14
|
+
|
15
|
+
# @return [void]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.5.0
|
19
|
+
def initialize
|
20
|
+
@steps = []
|
21
|
+
@access_lock = Mutex.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param step [SmartCore::Operation::Step]
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
# @since 0.5.0
|
29
|
+
def add_step(step)
|
30
|
+
thread_safe { steps << step }
|
31
|
+
end
|
32
|
+
alias_method :<<, :add_step
|
33
|
+
|
34
|
+
# @param step_set [SmartCore::Operation::Step]
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @sinec 0.5.0
|
39
|
+
def concat(step_set)
|
40
|
+
thread_safe { steps.concat(step_set.dup.steps) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# @retun [SmartCore::Operation::StepSet]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
# @since 0.5.0
|
47
|
+
def dup
|
48
|
+
thread_safe do
|
49
|
+
self.class.new.tap do |duplicate|
|
50
|
+
steps.each { |step| duplicate.add_step(step.dup) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Enumerable]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
# @since 0.5.0
|
59
|
+
def each(&block)
|
60
|
+
thread_safe { block_given? ? steps.each(&block) : steps.each }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# @param block [Proc]
|
66
|
+
# @return [Any]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @since 0.5.0
|
70
|
+
def thread_safe(&block)
|
71
|
+
@access_lock.synchronize(&block)
|
72
|
+
end
|
73
|
+
end
|