smart_core 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|