convenient_service 0.21.0 → 0.22.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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/convenient_service/dependencies/built_in.rb +20 -16
  3. data/lib/convenient_service/service/configs/standard.rb +1 -0
  4. data/lib/convenient_service/service/plugins/can_have_steps/concern.rb +8 -0
  5. data/lib/convenient_service/service/plugins/can_have_steps/entities/step/concern/instance_methods.rb +25 -11
  6. data/lib/convenient_service/service/plugins/can_have_steps/entities/step/exceptions.rb +17 -0
  7. data/lib/convenient_service/service/plugins/can_have_steps/entities/step/plugins/can_be_method_step/commands/calculate_method_result.rb +7 -10
  8. data/lib/convenient_service/service/plugins/can_have_steps/entities/step/plugins/can_be_service_step/commands/calculate_service_result.rb +4 -7
  9. data/lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data/concern.rb +109 -0
  10. data/lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data/exceptions.rb +66 -0
  11. data/lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data.rb +9 -0
  12. data/lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins.rb +1 -0
  13. data/lib/convenient_service/support/arguments/null_arguments/exceptions.rb +31 -0
  14. data/lib/convenient_service/support/arguments/null_arguments.rb +23 -2
  15. data/lib/convenient_service/support/arguments.rb +26 -3
  16. data/lib/convenient_service/support/block.rb +17 -0
  17. data/lib/convenient_service/support/cache/entities/caches/array.rb +5 -1
  18. data/lib/convenient_service/support/cache/entities/caches/hash.rb +5 -1
  19. data/lib/convenient_service/support/not_passed.rb +1 -9
  20. data/lib/convenient_service/support/undefined.rb +1 -9
  21. data/lib/convenient_service/support/unique_value.rb +8 -0
  22. data/lib/convenient_service/support.rb +1 -1
  23. data/lib/convenient_service/utils/method/loose_call.rb +340 -0
  24. data/lib/convenient_service/utils/method.rb +5 -0
  25. data/lib/convenient_service/version.rb +1 -1
  26. metadata +8 -17
  27. data/lib/convenient_service/support/method_parameters.rb +0 -126
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc0b70a8a73f6bffd654e90e8ad332f0132b7ea83255ad56860c6e3ac454492c
4
- data.tar.gz: e9be9fdaf668c6fdd510b27af3a04b9fa01582891478c95cab72320236926939
3
+ metadata.gz: 1c8f0f45805d314b21afa5fdafc59cb20a5bdfb3d1bd2805b4cdab85953229c9
4
+ data.tar.gz: b92a6f6ea00c8ea45d328d667d6612dfe4f9d884ee227fbb66eb83907518a06b
5
5
  SHA512:
6
- metadata.gz: 372f4e96c265835df11321a7e30e2a8aaf5544ab6fea1d9b89084e4f1687a6399dbb72bea80b730fab31c5bc44722e0647260e717f518201c36a5e575f2cf074
7
- data.tar.gz: 84852e20f09454a0181fc1438205f4ef446aba65d86c3c391838f4b340eb31546fe7e2bdd226da8bfc94c9d2ef80bf5e23c884d00282ef966c5384840f79e207
6
+ metadata.gz: 1154d803aeca510b922a468eb816a5d26d8c2ac12d089b744f491969f2b1d6ace8f2b98ba183585aca5a28d2c31b5cab993970fedea6ddffa9fd9ef1a77a1acc
7
+ data.tar.gz: 71a5f43b90cf24bad64bdf6de40dc4087f36e505c7781e1c563cdf42b411056b32d94b96ce44496d3b6bfa2f8b290c5b5392a56420881f58ff60e20963372c1a
@@ -15,14 +15,19 @@
15
15
  # - https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Lint/RedundantRequireStatement
16
16
  ##
17
17
 
18
+ ##
19
+ # NOTE: Dependencies must be kept in sync with `convenient_service.gemspec`.
20
+ ##
21
+
18
22
  ##
19
23
  # @internal
20
- # - https://ruby-doc.org/stdlib-2.7.0/libdoc/pathname/rdoc/Pathname.html
21
- # - https://github.com/ruby/pathname
24
+ # - https://ruby-doc.org/stdlib-2.7.0/libdoc/rubygems/rdoc/Gem/Version.html
25
+ # - https://github.com/rubygems/rubygems
26
+ # - https://github.com/rubygems/rubygems/blob/master/lib/rubygems/version.rb
22
27
  #
23
28
  # @!visibility private
24
29
  #
25
- require "pathname"
30
+ require "rubygems"
26
31
 
27
32
  ##
28
33
  # @internal
@@ -44,13 +49,21 @@ require "logger"
44
49
 
45
50
  ##
46
51
  # @internal
47
- # - https://ruby-doc.org/stdlib-2.7.0/libdoc/rubygems/rdoc/Gem/Version.html
48
- # - https://github.com/rubygems/rubygems
49
- # - https://github.com/rubygems/rubygems/blob/master/lib/rubygems/version.rb
52
+ # - https://ruby-doc.org/stdlib-2.7.0/libdoc/pathname/rdoc/Pathname.html
53
+ # - https://github.com/ruby/pathname
50
54
  #
51
55
  # @!visibility private
52
56
  #
53
- require "rubygems"
57
+ require "pathname"
58
+
59
+ ##
60
+ # @internal
61
+ # - https://ruby-doc.org/stdlib-2.7.0/libdoc/set/rdoc/Set.html
62
+ # - https://github.com/ruby/set
63
+ #
64
+ # @!visibility private
65
+ #
66
+ require "set"
54
67
 
55
68
  ##
56
69
  # @internal
@@ -71,12 +84,3 @@ require "singleton"
71
84
  # rubocop:disable Lint/RedundantRequireStatement
72
85
  require "thread"
73
86
  # rubocop:enable Lint/RedundantRequireStatement
74
-
75
- ##
76
- # @internal
77
- # - https://ruby-doc.org/stdlib-2.7.0/libdoc/set/rdoc/Set.html
78
- # - https://github.com/ruby/set
79
- #
80
- # @!visibility private
81
- #
82
- require "set"
@@ -219,6 +219,7 @@ module ConvenientService
219
219
  use ConvenientService::Plugins::Result::CanHaveStep::Concern if options.enabled?(:essential)
220
220
  use ConvenientService::Plugins::Result::CanBeCalled::Concern if options.enabled?(:essential)
221
221
  use ConvenientService::Plugins::Result::CanBeStrict::Concern if options.enabled?(:essential)
222
+ use ConvenientService::Plugins::Result::CanHaveModifiedData::Concern if options.enabled?(:essential)
222
223
  use ConvenientService::Plugins::Result::HasNegatedResult::Concern if options.enabled?(:essential)
223
224
  use ConvenientService::Plugins::Result::HasPatternMatchingSupport::Concern if options.enabled?(:essential)
224
225
  use ConvenientService::Plugins::Result::CanBeFromFallback::Concern if options.enabled?(:fallbacks)
@@ -13,6 +13,14 @@ module ConvenientService
13
13
  include Support::Concern
14
14
 
15
15
  class_methods do
16
+ ##
17
+ # @api public
18
+ # @return [ConvenientService::Support::UniqueValue]
19
+ #
20
+ def block
21
+ Support::BLOCK
22
+ end
23
+
16
24
  ##
17
25
  # @api public
18
26
  #
@@ -177,14 +177,11 @@ module ConvenientService
177
177
  ##
178
178
  # @api public
179
179
  #
180
- # @return [Hash{Symbol => Object}]
180
+ # @return [ConvenientService::Support::Arguments]
181
181
  # @raise [ConvenientService::Service::Plugins::CanHaveSteps::Entities::Step::Exceptions::StepHasNoOrganizer]
182
182
  #
183
- # @internal
184
- # TODO: Refactor to `input_arguments` to support args and block via `step`?
185
- #
186
- def input_values
187
- @input_values ||= calculate_input_values
183
+ def input_arguments
184
+ @input_arguments ||= calculate_input_arguments
188
185
  end
189
186
 
190
187
  ##
@@ -329,14 +326,31 @@ module ConvenientService
329
326
  private
330
327
 
331
328
  ##
332
- # @return [Hash{Symbol => Object}]
329
+ # @return [ConvenientService::Support::Arguments]
333
330
  # @raise [ConvenientService::Service::Plugins::CanHaveSteps::Entities::Step::Exceptions::StepHasNoOrganizer]
334
331
  #
335
332
  # @internal
336
- # TODO: Commands instead of private methods.
337
- #
338
- def calculate_input_values
339
- inputs.reduce({}) { |values, input| values.merge(input.key.to_sym => input.value) }
333
+ # TODO: Refactor `inputs` array to `inputs` collection.
334
+ #
335
+ def calculate_input_arguments
336
+ arguments = Support::Arguments.new
337
+
338
+ inputs.each do |input|
339
+ key = input.key.value
340
+
341
+ case key
342
+ when ::Symbol
343
+ arguments.kwargs[key] = input.value
344
+ when ::Integer
345
+ arguments.args[key] = input.value
346
+ when Support::BLOCK
347
+ arguments.block = input.value
348
+ else
349
+ ::ConvenientService.raise Exceptions::UnsupportedKeyType.new(key: key, step: self)
350
+ end
351
+ end
352
+
353
+ arguments
340
354
  end
341
355
 
342
356
  ##
@@ -42,6 +42,23 @@ module ConvenientService
42
42
  initialize(message)
43
43
  end
44
44
  end
45
+
46
+ class UnsupportedKeyType < ::ConvenientService::Exception
47
+ ##
48
+ # @param key [Symbol]
49
+ # @param step [ConvenientService::Service::Plugins::CanHaveSteps::Entities::Step]
50
+ # @return [void]
51
+ #
52
+ def initialize_with_kwargs(key:, step:)
53
+ message = <<~TEXT
54
+ Input key `#{key.inspect}` of step `#{step.printable_action}` has unsupported type `#{key.class}`.
55
+
56
+ Maybe there is a typo in `in` definition?
57
+ TEXT
58
+
59
+ initialize(message)
60
+ end
61
+ end
45
62
  end
46
63
  end
47
64
  end
@@ -46,14 +46,11 @@ module ConvenientService
46
46
  # @param method [Method]
47
47
  # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
48
48
  #
49
+ # @internal
50
+ # TODO: Extract loose arguments from own method, but call regular method. This way middlewares can be applied to method steps.
51
+ #
49
52
  def call_method(method)
50
- params = Support::MethodParameters.new(method.parameters)
51
-
52
- return method.call(**input_values) if params.has_rest_kwargs?
53
-
54
- return method.call(**input_values.slice(*params.named_kwargs_keys)) if params.named_kwargs_keys.any?
55
-
56
- method.call
53
+ Utils::Method.loose_call(method, *input_arguments.args, **input_arguments.kwargs, &input_arguments.block)
57
54
  end
58
55
 
59
56
  ##
@@ -81,10 +78,10 @@ module ConvenientService
81
78
  end
82
79
 
83
80
  ##
84
- # @return [Hash{Symbol => Object}]
81
+ # @return [ConvenientService::Support::Arguments]
85
82
  #
86
- def input_values
87
- @input_values ||= step.input_values
83
+ def input_arguments
84
+ @input_arguments ||= step.input_arguments
88
85
  end
89
86
  end
90
87
  end
@@ -33,13 +33,10 @@ module ConvenientService
33
33
  # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
34
34
  # @raise [ConvenientService::Service::Plugins::CanHaveSteps::Entities::Step::Plugins::CanBeMethodStep::Exceptions::StepIsNotServiceStep]
35
35
  #
36
- # @internal
37
- # IMPORTANT: `service.result(**input_values)` is the reason, why services should have only kwargs as arguments.
38
- #
39
36
  def call
40
37
  ::ConvenientService.raise Exceptions::StepIsNotServiceStep.new(step: step) unless step.service_step?
41
38
 
42
- service.result(**input_values)
39
+ service.result(*input_arguments.args, **input_arguments.kwargs, &input_arguments.block)
43
40
  end
44
41
 
45
42
  private
@@ -52,10 +49,10 @@ module ConvenientService
52
49
  end
53
50
 
54
51
  ##
55
- # @return [Hash{Symbol => Object}]
52
+ # @return [ConvenientService::Support::Arguments]
56
53
  #
57
- def input_values
58
- @input_values ||= step.input_values
54
+ def input_arguments
55
+ @input_arguments ||= step.input_arguments
59
56
  end
60
57
  end
61
58
  end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ module ConvenientService
9
+ module Service
10
+ module Plugins
11
+ module HasJSendResult
12
+ module Entities
13
+ class Result
14
+ module Plugins
15
+ module CanHaveModifiedData
16
+ module Concern
17
+ include Support::Concern
18
+
19
+ instance_methods do
20
+ ##
21
+ # @api public
22
+ #
23
+ # @param keys [Array<Symbol>]
24
+ # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
25
+ #
26
+ def with_only_keys(*keys)
27
+ return self if status.unsafe_not_success?
28
+ return self if keys.empty?
29
+
30
+ data_with_only_keys =
31
+ keys.each_with_object({}) do |key, data_with_only_keys|
32
+ if unsafe_data.__has_attribute__?(key)
33
+ data_with_only_keys[key] = unsafe_data[key]
34
+ else
35
+ ::ConvenientService.raise Exceptions::NotExistingAttributeForOnly.new(key: key)
36
+ end
37
+ end
38
+
39
+ copy(overrides: {kwargs: {data: data_with_only_keys}})
40
+ end
41
+
42
+ ##
43
+ # @api public
44
+ #
45
+ # @param keys [Array<Symbol>]
46
+ # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
47
+ #
48
+ def with_except_keys(*keys)
49
+ return self if status.unsafe_not_success?
50
+ return self if keys.empty?
51
+
52
+ data_with_except_keys =
53
+ keys.each_with_object(unsafe_data.to_h.dup) do |key, data_with_except_keys|
54
+ if unsafe_data.__has_attribute__?(key)
55
+ data_with_except_keys.delete(key)
56
+ else
57
+ ::ConvenientService.raise Exceptions::NotExistingAttributeForExcept.new(key: key)
58
+ end
59
+ end
60
+
61
+ copy(overrides: {kwargs: {data: data_with_except_keys}})
62
+ end
63
+
64
+ ##
65
+ # @api public
66
+ #
67
+ # @param renamings [Hash{Symbol => Symbol}]
68
+ # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
69
+ #
70
+ def with_renamed_keys(**renamings)
71
+ return self if status.unsafe_not_success?
72
+ return self if renamings.empty?
73
+
74
+ data_with_renamed_keys =
75
+ renamings.each_with_object(unsafe_data.to_h.dup) do |(key, renamed_key), data_with_renamed_keys|
76
+ if unsafe_data.__has_attribute__?(key)
77
+ data_with_renamed_keys[renamed_key] = data_with_renamed_keys.delete(key)
78
+ else
79
+ ::ConvenientService.raise Exceptions::NotExistingAttributeForRename.new(key: key, renamed_key: renamed_key)
80
+ end
81
+ end
82
+
83
+ copy(overrides: {kwargs: {data: data_with_renamed_keys}})
84
+ end
85
+
86
+ ##
87
+ # @api public
88
+ #
89
+ # @param values [Hash{Symbol => Object}]
90
+ # @return [ConvenientService::Service::Plugins::HasJSendResult::Entities::Result]
91
+ #
92
+ def with_extra_keys(**values)
93
+ return self if status.unsafe_not_success?
94
+ return self if values.empty?
95
+
96
+ data_with_extra_keys = unsafe_data.to_h.merge(values)
97
+
98
+ copy(overrides: {kwargs: {data: data_with_extra_keys}})
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ module ConvenientService
9
+ module Service
10
+ module Plugins
11
+ module HasJSendResult
12
+ module Entities
13
+ class Result
14
+ module Plugins
15
+ module CanHaveModifiedData
16
+ module Exceptions
17
+ class NotExistingAttributeForOnly < ::ConvenientService::Exception
18
+ ##
19
+ # @param key [Symbol]
20
+ # @return [void]
21
+ #
22
+ def initialize_with_kwargs(key:)
23
+ message = <<~TEXT
24
+ Data attribute by key `:#{key}` does NOT exist. That is why it can NOT be selected. Make sure the corresponding result has it.
25
+ TEXT
26
+
27
+ initialize(message)
28
+ end
29
+ end
30
+
31
+ class NotExistingAttributeForExcept < ::ConvenientService::Exception
32
+ ##
33
+ # @param key [Symbol]
34
+ # @return [void]
35
+ #
36
+ def initialize_with_kwargs(key:)
37
+ message = <<~TEXT
38
+ Data attribute by key `:#{key}` does NOT exist. That is why it can NOT be dropped. Make sure the corresponding result has it.
39
+ TEXT
40
+
41
+ initialize(message)
42
+ end
43
+ end
44
+
45
+ class NotExistingAttributeForRename < ::ConvenientService::Exception
46
+ ##
47
+ # @param key [Symbol]
48
+ # @return [void]
49
+ #
50
+ def initialize_with_kwargs(key:, renamed_key:)
51
+ message = <<~TEXT
52
+ Data attribute by key `:#{key}` does NOT exist. That is why it can NOT be renamed to `:#{renamed_key}`. Make sure the corresponding result has it.
53
+ TEXT
54
+
55
+ initialize(message)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ require_relative "can_have_modified_data/concern"
9
+ require_relative "can_have_modified_data/exceptions"
@@ -13,6 +13,7 @@ require_relative "plugins/can_have_fallbacks"
13
13
  require_relative "plugins/can_be_from_exception"
14
14
  require_relative "plugins/can_be_own_result"
15
15
  require_relative "plugins/can_be_stubbed_result"
16
+ require_relative "plugins/can_have_modified_data"
16
17
  require_relative "plugins/has_j_send_status_and_attributes"
17
18
  require_relative "plugins/has_inspect"
18
19
  require_relative "plugins/has_pattern_matching_support"
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ module ConvenientService
9
+ module Support
10
+ class Arguments
11
+ class NullArguments < Support::Arguments
12
+ module Exceptions
13
+ class BlockSetIsNotAllowed < ::ConvenientService::Exception
14
+ ##
15
+ # @return [void]
16
+ #
17
+ def initialize_without_arguments
18
+ message = <<~TEXT
19
+ Setting a block to null arguments is NOT allowed.
20
+
21
+ Consider to create a new arguments object and set block to it instead.
22
+ TEXT
23
+
24
+ initialize(message)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -5,6 +5,8 @@
5
5
  # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
6
  ##
7
7
 
8
+ require_relative "null_arguments/exceptions"
9
+
8
10
  module ConvenientService
9
11
  module Support
10
12
  class Arguments
@@ -16,17 +18,36 @@ module ConvenientService
16
18
  # @return [void]
17
19
  #
18
20
  def initialize
19
- @args = []
20
- @kwargs = {}
21
+ @args = [].freeze
22
+ @kwargs = {}.freeze
21
23
  @block = nil
22
24
  end
23
25
 
26
+ ##
27
+ # @param other_block [Proc, nil]
28
+ #
29
+ def block=(other_block)
30
+ ::ConvenientService.raise Exceptions::BlockSetIsNotAllowed.new
31
+ end
32
+
24
33
  ##
25
34
  # @return [Boolean]
26
35
  #
27
36
  def null_arguments?
28
37
  true
29
38
  end
39
+
40
+ ##
41
+ # @return [Boolean]
42
+ #
43
+ alias_method :nil_arguments?, :null_arguments?
44
+
45
+ ##
46
+ # @return [ConvenientService::Support::Arguments]
47
+ #
48
+ def to_arguments
49
+ ConvenientService::Support::Arguments.new
50
+ end
30
51
  end
31
52
  end
32
53
  end
@@ -13,22 +13,28 @@ module ConvenientService
13
13
  class Arguments
14
14
  ##
15
15
  # @!attribute [r] args
16
- # @return [Array]
16
+ # @return [Array<Object>]
17
17
  #
18
18
  attr_reader :args
19
19
 
20
20
  ##
21
21
  # @!attribute [r] kwargs
22
- # @return [Hash]
22
+ # @return [Hash{Symbol => Object}]
23
23
  #
24
24
  attr_reader :kwargs
25
25
 
26
26
  ##
27
27
  # @!attribute [r] block
28
- # @return [Proc]
28
+ # @return [Proc, nil]
29
29
  #
30
30
  attr_reader :block
31
31
 
32
+ ##
33
+ # @!attribute [w] block
34
+ # @return [Proc, nil]
35
+ #
36
+ attr_writer :block
37
+
32
38
  ##
33
39
  # @param args [Array<Object>]
34
40
  # @param kwargs [Hash{Symbol => Object}]
@@ -48,6 +54,11 @@ module ConvenientService
48
54
  def null_arguments
49
55
  @null_arguments ||= Support::Arguments::NullArguments.new
50
56
  end
57
+
58
+ ##
59
+ # @return [ConvenientService::Support::Arguments::NullArguments]
60
+ #
61
+ alias_method :nil_arguments, :null_arguments
51
62
  end
52
63
 
53
64
  ##
@@ -57,6 +68,11 @@ module ConvenientService
57
68
  false
58
69
  end
59
70
 
71
+ ##
72
+ # @return [Boolean]
73
+ #
74
+ alias_method :nil_arguments?, :null_arguments?
75
+
60
76
  ##
61
77
  # @return [Booleam]
62
78
  #
@@ -137,6 +153,13 @@ module ConvenientService
137
153
  end
138
154
  end
139
155
  end
156
+
157
+ ##
158
+ # @return [ConvenientService::Support::Arguments]
159
+ #
160
+ def to_arguments
161
+ self
162
+ end
140
163
  end
141
164
  end
142
165
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ module ConvenientService
9
+ module Support
10
+ class Block < Support::UniqueValue; end
11
+
12
+ ##
13
+ # @return [ConvenientService::Support::UniqueValue]
14
+ #
15
+ BLOCK = Support::Block.new("block")
16
+ end
17
+ end
@@ -142,7 +142,11 @@ module ConvenientService
142
142
  # @return [Object] Can be any type.
143
143
  #
144
144
  def default=(value)
145
- save_self_as_scope_in_parent!
145
+ if value.nil?
146
+ delete_self_as_scope_in_parent! if store.empty?
147
+ else
148
+ save_self_as_scope_in_parent!
149
+ end
146
150
 
147
151
  @default = value
148
152
  end
@@ -147,7 +147,11 @@ module ConvenientService
147
147
  # @return [Object] Can be any type.
148
148
  #
149
149
  def default=(value)
150
- save_self_as_scope_in_parent!
150
+ if value.nil?
151
+ delete_self_as_scope_in_parent! if store.empty?
152
+ else
153
+ save_self_as_scope_in_parent!
154
+ end
151
155
 
152
156
  store.default = value
153
157
 
@@ -7,15 +7,7 @@
7
7
 
8
8
  module ConvenientService
9
9
  module Support
10
- class NotPassed < Support::UniqueValue
11
- ##
12
- # @param value [Object] Can be any type.
13
- # @return [Boolean]
14
- #
15
- def [](value)
16
- equal?(value)
17
- end
18
- end
10
+ class NotPassed < Support::UniqueValue; end
19
11
 
20
12
  ##
21
13
  # @return [ConvenientService::Support::UniqueValue]
@@ -7,15 +7,7 @@
7
7
 
8
8
  module ConvenientService
9
9
  module Support
10
- class Undefined < Support::UniqueValue
11
- ##
12
- # @param value [Object] Can be any type.
13
- # @return [Boolean]
14
- #
15
- def [](value)
16
- equal?(value)
17
- end
18
- end
10
+ class Undefined < Support::UniqueValue; end
19
11
 
20
12
  ##
21
13
  # @return [ConvenientService::Support::UniqueValue]
@@ -22,6 +22,14 @@ module ConvenientService
22
22
  @label = label
23
23
  end
24
24
 
25
+ ##
26
+ # @param value [Object] Can be any type.
27
+ # @return [Boolean]
28
+ #
29
+ def [](value)
30
+ equal?(value)
31
+ end
32
+
25
33
  ##
26
34
  # @param other [Object] Can be any type.
27
35
  # @return [Boolean, nil]
@@ -11,6 +11,7 @@ require_relative "support/unique_value"
11
11
  require_relative "support/not_passed"
12
12
  require_relative "support/undefined"
13
13
  require_relative "support/never_reach_here"
14
+ require_relative "support/block"
14
15
 
15
16
  require_relative "support/concern"
16
17
 
@@ -25,7 +26,6 @@ require_relative "support/counter"
25
26
  require_relative "support/delegate"
26
27
  require_relative "support/dependency_container"
27
28
  require_relative "support/finite_loop"
28
- require_relative "support/method_parameters"
29
29
  require_relative "support/middleware"
30
30
  require_relative "support/raw_value"
31
31
  require_relative "support/safe_method"
@@ -0,0 +1,340 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
+ # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
+ ##
7
+
8
+ module ConvenientService
9
+ module Utils
10
+ module Method
11
+ class LooseCall < Support::Command
12
+ ##
13
+ # @example All possible parameters values in Ruby 2.7.
14
+ # class Example
15
+ # def m1(); end
16
+ # def m2(a); end
17
+ # def m3(a = 0); end
18
+ # def m4(a, b); end
19
+ # def m5(a, b = 1); end
20
+ # def m6(a = 0, b = 1); end
21
+ # def m7(*args); end
22
+ # def m8(a:); end
23
+ # def m9(a: 0); end
24
+ # def m10(a:, b:); end
25
+ # def m11(a:, b: 1); end
26
+ # def m12(a: 0, b: 1); end
27
+ # def m13(**kwargs); end
28
+ # def m14(&block); end
29
+ # end
30
+ #
31
+ # object = Example.new
32
+ #
33
+ # # def m1(); end
34
+ # p object.method(:m1).parameters
35
+ # # => []
36
+ #
37
+ # # def m2(a); end
38
+ # p object.method(:m2).parameters
39
+ # # => [[:req, :a]]
40
+ #
41
+ # # def m3(a = 0); end
42
+ # p object.method(:m3).parameters
43
+ # # => [[:opt, :a]]
44
+ #
45
+ # # def m4(a, b); end
46
+ # p object.method(:m4).parameters
47
+ # # => [[:req, :a], [:req, :b]]
48
+ #
49
+ # # def m5(a, b = 1); end
50
+ # p object.method(:m5).parameters
51
+ # # => [[:req, :a], [:opt, :b]]
52
+ #
53
+ # # def m6(a = 0, b = 1); end
54
+ # p object.method(:m6).parameters
55
+ # # => [[:opt, :a], [:opt, :b]]
56
+ #
57
+ # # def m7(*args); end
58
+ # p object.method(:m7).parameters
59
+ # # => [[:rest, :args]]
60
+ #
61
+ # # def m8(a:); end
62
+ # p object.method(:m8).parameters
63
+ # # => [[:keyreq, :a]]
64
+ #
65
+ # # def m9(a: 0); end
66
+ # p object.method(:m9).parameters
67
+ # # => [[:key, :a]]
68
+ #
69
+ # # def m10(a:, b:); end
70
+ # p object.method(:m10).parameters
71
+ # # => [[:keyreq, :a], [:keyreq, :b]]
72
+ #
73
+ # # def m11(a:, b: 1); end
74
+ # p object.method(:m11).parameters
75
+ # # => [[:keyreq, :a], [:key, :b]]
76
+ #
77
+ # # def m12(a: 0, b: 1); end
78
+ # p object.method(:m12).parameters
79
+ # # => [[:key, :a], [:key, :b]]
80
+ #
81
+ # # def m13(**kwargs); end
82
+ # p object.method(:m13).parameters
83
+ # # => [[:keyrest, :kwargs]]
84
+ #
85
+ # # def m14(&block); end
86
+ # p object.method(:m14).parameters
87
+ # # => [[:block, :block]]
88
+ #
89
+ # @example All possible parameters values in Ruby 4.0.
90
+ # class Example
91
+ # def m1(); end
92
+ # def m2(a); end
93
+ # def m3(a = 0); end
94
+ # def m4(a, b); end
95
+ # def m5(a, b = 1); end
96
+ # def m6(a = 0, b = 1); end
97
+ # def m7(*args); end
98
+ # def m8(a:); end
99
+ # def m9(a: 0); end
100
+ # def m10(a:, b:); end
101
+ # def m11(a:, b: 1); end
102
+ # def m12(a: 0, b: 1); end
103
+ # def m13(**kwargs); end
104
+ # def m14(&block); end
105
+ # end
106
+ #
107
+ # object = Example.new
108
+ #
109
+ # # def m1(); end
110
+ # p object.method(:m1).parameters
111
+ # # => []
112
+ #
113
+ # # def m2(a); end
114
+ # p object.method(:m2).parameters
115
+ # # => [[:req, :a]]
116
+ #
117
+ # # def m3(a = 0); end
118
+ # p object.method(:m3).parameters
119
+ # # => [[:opt, :a]]
120
+ #
121
+ # # def m4(a, b); end
122
+ # p object.method(:m4).parameters
123
+ # # => [[:req, :a], [:req, :b]]
124
+ #
125
+ # # def m5(a, b = 1); end
126
+ # p object.method(:m5).parameters
127
+ # # => [[:req, :a], [:opt, :b]]
128
+ #
129
+ # # def m6(a = 0, b = 1); end
130
+ # p object.method(:m6).parameters
131
+ # # => [[:opt, :a], [:opt, :b]]
132
+ #
133
+ # # def m7(*args); end
134
+ # p object.method(:m7).parameters
135
+ # # => [[:rest, :args]]
136
+ #
137
+ # # def m8(a:); end
138
+ # p object.method(:m8).parameters
139
+ # # => [[:keyreq, :a]]
140
+ #
141
+ # # def m9(a: 0); end
142
+ # p object.method(:m9).parameters
143
+ # # => [[:key, :a]]
144
+ #
145
+ # # def m10(a:, b:); end
146
+ # p object.method(:m10).parameters
147
+ # # => [[:keyreq, :a], [:keyreq, :b]]
148
+ #
149
+ # # def m11(a:, b: 1); end
150
+ # p object.method(:m11).parameters
151
+ # # => [[:keyreq, :a], [:key, :b]]
152
+ #
153
+ # # def m12(a: 0, b: 1); end
154
+ # p object.method(:m12).parameters
155
+ # # => [[:key, :a], [:key, :b]]
156
+ #
157
+ # # def m13(**kwargs); end
158
+ # p object.method(:m13).parameters
159
+ # # => [[:keyrest, :kwargs]]
160
+ #
161
+ # # def m14(&block); end
162
+ # p object.method(:m14).parameters
163
+ # # => [[:block, :block]]
164
+ #
165
+ class Signature
166
+ ##
167
+ # @!attribute [r] parameters
168
+ # @return [Array<Array<Symbol>>]
169
+ #
170
+ attr_reader :parameters
171
+
172
+ ##
173
+ # @param parameters [Array<Array<Symbol>>]
174
+ # @return [void]
175
+ #
176
+ def initialize(parameters)
177
+ @parameters = parameters
178
+ end
179
+
180
+ ##
181
+ # @return [Array<Symbol>]
182
+ #
183
+ def args
184
+ parsed_parameters[:args].to_a
185
+ end
186
+
187
+ ##
188
+ # @return [Hash{Symbol => Object}]
189
+ #
190
+ def kwargs
191
+ parsed_parameters[:kwargs].to_a
192
+ end
193
+
194
+ ##
195
+ # @return [Symbol]
196
+ #
197
+ def kwargs_names
198
+ @kwargs_names ||= kwargs.map { |_, name| name }
199
+ end
200
+
201
+ ##
202
+ # @return [Boolean]
203
+ #
204
+ def args_rest?
205
+ parsed_parameters.has_key?(:args_rest)
206
+ end
207
+
208
+ ##
209
+ # @return [Boolean]
210
+ #
211
+ def kwargs_rest?
212
+ parsed_parameters.has_key?(:kwargs_rest)
213
+ end
214
+
215
+ ##
216
+ # @return [Boolean]
217
+ #
218
+ def block?
219
+ parsed_parameters.has_key?(:block)
220
+ end
221
+
222
+ ##
223
+ # @param regular_args [Array<Object>]
224
+ # @return [Array<Object>]
225
+ #
226
+ def loose_args_from(regular_args)
227
+ args_rest? ? regular_args : regular_args.take(args.size)
228
+ end
229
+
230
+ ##
231
+ # @param regular_kwargs [Hash{Symbol => Object}]
232
+ # @return [Hash{Symbol => Object}]
233
+ #
234
+ def loose_kwargs_from(regular_kwargs)
235
+ kwargs_rest? ? regular_kwargs : regular_kwargs.slice(*kwargs_names)
236
+ end
237
+
238
+ ##
239
+ # @param regular_block [Proc, nil]
240
+ # @return [Proc, nil]
241
+ #
242
+ def loose_block_from(regular_block)
243
+ block? ? regular_block : nil
244
+ end
245
+
246
+ private
247
+
248
+ ##
249
+ # @return [Hash{Symbol => Object}]
250
+ #
251
+ def parsed_parameters
252
+ @parsed_parameters ||=
253
+ parameters.each_with_object({}) do |parameter, hash|
254
+ case parameter.first
255
+ when :req, :opt
256
+ (hash[:args] ||= []) << parameter
257
+ when :keyreq, :key
258
+ (hash[:kwargs] ||= []) << parameter
259
+ when :block
260
+ hash[:block] = parameter
261
+ when :rest
262
+ hash[:args_rest] = true
263
+ when :keyrest
264
+ hash[:kwargs_rest] = true
265
+ end
266
+ end
267
+ end
268
+ end
269
+
270
+ ##
271
+ # @!attribute [r] method
272
+ # @return [String, Symbol]
273
+ #
274
+ attr_reader :method
275
+
276
+ ##
277
+ # @!attribute [r] args
278
+ # @return [Array<Object>]
279
+ #
280
+ attr_reader :args
281
+
282
+ ##
283
+ # @!attribute [r] kwargs
284
+ # @return [Hash{Symbol => Object}]
285
+ #
286
+ attr_reader :kwargs
287
+
288
+ ##
289
+ # @!attribute [r] block
290
+ # @return [Proc, nil]
291
+ #
292
+ attr_reader :block
293
+
294
+ ##
295
+ # @param method [Symbol, String]
296
+ # @param args [Array<Object>]
297
+ # @param kwargs [Hash{Symbol => Object}]
298
+ # @param block [Proc, nil]
299
+ # @return [void]
300
+ #
301
+ def initialize(method, *args, **kwargs, &block)
302
+ @method = method
303
+ @args = args
304
+ @kwargs = kwargs
305
+ @block = block
306
+ end
307
+
308
+ ##
309
+ # @return [Object] Can be any type.
310
+ #
311
+ # @internal
312
+ # NOTE: Ruby 2.7 sometimes passes `kwargs` as `args`. Look for `ConvenientService::Dependencies.ruby.version > 3.0` in `spec/e2e/loose_method_steps_spec.rb` for examples.
313
+ #
314
+ def call
315
+ method.call(
316
+ *signature.loose_args_from(args),
317
+ **signature.loose_kwargs_from(kwargs),
318
+ &signature.loose_block_from(block)
319
+ )
320
+ end
321
+
322
+ private
323
+
324
+ ##
325
+ # @return [Signature]
326
+ #
327
+ def signature
328
+ @signature ||= Signature.new(parameters)
329
+ end
330
+
331
+ ##
332
+ # @return [Array<Array<Symbol>>]
333
+ #
334
+ def parameters
335
+ @parameters ||= method.parameters
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end
@@ -6,6 +6,7 @@
6
6
  ##
7
7
 
8
8
  require_relative "method/defined"
9
+ require_relative "method/loose_call"
9
10
  require_relative "method/name"
10
11
  require_relative "method/remove"
11
12
 
@@ -17,6 +18,10 @@ module ConvenientService
17
18
  Defined.call(...)
18
19
  end
19
20
 
21
+ def loose_call(...)
22
+ LooseCall.call(...)
23
+ end
24
+
20
25
  def remove(...)
21
26
  Remove.call(...)
22
27
  end
@@ -13,5 +13,5 @@ module ConvenientService
13
13
  # @since 1.0.0
14
14
  # @return [String]
15
15
  #
16
- VERSION = "0.21.0"
16
+ VERSION = "0.22.0"
17
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convenient_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marian Kostyk
@@ -23,20 +23,6 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0'
26
- - !ruby/object:Gem::Dependency
27
- name: set
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0'
40
26
  description: |
41
27
  Manage complex business logic in Ruby applications using Service Objects with Results and Steps.
42
28
 
@@ -618,6 +604,9 @@ files:
618
604
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_fallbacks.rb
619
605
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_fallbacks/concern.rb
620
606
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_fallbacks/exceptions.rb
607
+ - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data.rb
608
+ - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data/concern.rb
609
+ - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_modified_data/exceptions.rb
621
610
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_parent_result.rb
622
611
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_parent_result/concern.rb
623
612
  - lib/convenient_service/service/plugins/has_j_send_result/entities/result/plugins/can_have_parent_result/constants.rb
@@ -756,7 +745,9 @@ files:
756
745
  - lib/convenient_service/support/arguments.rb
757
746
  - lib/convenient_service/support/arguments/exceptions.rb
758
747
  - lib/convenient_service/support/arguments/null_arguments.rb
748
+ - lib/convenient_service/support/arguments/null_arguments/exceptions.rb
759
749
  - lib/convenient_service/support/backtrace_cleaner.rb
750
+ - lib/convenient_service/support/block.rb
760
751
  - lib/convenient_service/support/cache.rb
761
752
  - lib/convenient_service/support/cache/constants.rb
762
753
  - lib/convenient_service/support/cache/entities.rb
@@ -794,7 +785,6 @@ files:
794
785
  - lib/convenient_service/support/dependency_container/export.rb
795
786
  - lib/convenient_service/support/dependency_container/import.rb
796
787
  - lib/convenient_service/support/finite_loop.rb
797
- - lib/convenient_service/support/method_parameters.rb
798
788
  - lib/convenient_service/support/middleware.rb
799
789
  - lib/convenient_service/support/middleware/stack_builder.rb
800
790
  - lib/convenient_service/support/middleware/stack_builder/constants.rb
@@ -845,6 +835,7 @@ files:
845
835
  - lib/convenient_service/utils/kernel/silence_warnings.rb
846
836
  - lib/convenient_service/utils/method.rb
847
837
  - lib/convenient_service/utils/method/defined.rb
838
+ - lib/convenient_service/utils/method/loose_call.rb
848
839
  - lib/convenient_service/utils/method/name.rb
849
840
  - lib/convenient_service/utils/method/name/append.rb
850
841
  - lib/convenient_service/utils/method/remove.rb
@@ -901,7 +892,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
901
892
  - !ruby/object:Gem::Version
902
893
  version: '0'
903
894
  requirements: []
904
- rubygems_version: 3.6.9
895
+ rubygems_version: 4.0.3
905
896
  specification_version: 4
906
897
  summary: Ruby Service Objects with Steps and more.
907
898
  test_files: []
@@ -1,126 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ##
4
- # @author Marian Kostyk <mariankostyk13895@gmail.com>
5
- # @license LGPLv3 <https://www.gnu.org/licenses/lgpl-3.0.html>
6
- ##
7
-
8
- module ConvenientService
9
- module Support
10
- ##
11
- # Wrapps `Method#parameters` return value to provide a higher level interface.
12
- #
13
- # @note `Method#parameters` return value may look like the following.
14
- #
15
- # def foo(a, b = 1, *args, c:, d: 2, **kwargs, &block)
16
- # end
17
- #
18
- # method(:foo).parameters
19
- # # => [[:req, :a], [:opt, :b], [:rest, :args], [:keyreq, :c], [:key, :d], [:keyrest, :kwargs], [:block, :block]]
20
- #
21
- # @see https://ruby-doc.org/core-2.7.1/Method.html#method-i-parameters
22
- #
23
- class MethodParameters
24
- module Constants
25
- module Types
26
- REQUIRED_KEYWORD = :keyreq
27
- OPTIONAL_KEYWORD = :key
28
-
29
- REST_KEYWORDS = :keyrest
30
- end
31
- end
32
-
33
- ##
34
- # @!attribute [r] method_parameters
35
- # @return [Array]
36
- #
37
- attr_reader :method_parameters
38
-
39
- ##
40
- # @param method_parameters [Array]
41
- # @return [void]
42
- #
43
- def initialize(method_parameters)
44
- @method_parameters = method_parameters
45
- end
46
-
47
- ##
48
- # Returns `true` when method definition has `**kwargs`.
49
- # @return [Boolean]
50
- #
51
- # @example `rest_kwargs` means NOT named kwargs.
52
- #
53
- # def foo(a, b = 1, *args, c:, d: 2, **kwargs, &block)
54
- # end
55
- #
56
- # def bar(a, b = 1, *args, c:, d: 2, &block)
57
- # end
58
- #
59
- # ConvenientService::Support::MethodParameters.new(method(:foo).parameters).has_rest_kwargs?
60
- # # => true
61
- #
62
- # ConvenientService::Support::MethodParameters.new(method(:bar).parameters).has_rest_kwargs?
63
- # # => false
64
- #
65
- # @see https://ruby-doc.org/core-2.7.1/Method.html#method-i-parameters
66
- #
67
- def has_rest_kwargs?
68
- return @has_rest_kwargs if defined? @has_rest_kwargs
69
-
70
- @has_rest_kwargs = method_parameters.any? { |type, _name| type == Constants::Types::REST_KEYWORDS }
71
- end
72
-
73
- ##
74
- # @return [Array<Symbol>]
75
- #
76
- # @example `named_kwargs_keys` are `kwargs` with or without `defaults`.
77
- #
78
- # def foo(a, b = 1, *args, c:, d: 2, **kwargs, &block)
79
- # end
80
- #
81
- # ConvenientService::Support::MethodParameters.new(method(:foo).parameters).named_kwargs_keys
82
- # # => [:c, :d]
83
- #
84
- # @note `named_kwargs_keys` is an optimized way to get `required_kwargs_keys + optional_kwargs_keys`.
85
- # @see https://ruby-doc.org/core-2.7.1/Method.html#method-i-parameters
86
- #
87
- def named_kwargs_keys
88
- @named_kwargs_keys ||= method_parameters.select { |type, _name| type == Constants::Types::REQUIRED_KEYWORD || type == Constants::Types::OPTIONAL_KEYWORD }.map { |_type, name| name }
89
- end
90
-
91
- ##
92
- # @return [Array<Symbol>]
93
- #
94
- # @note `required_kwargs` are named `kwargs` without `defaults`.
95
- #
96
- # def foo(a, b = 1, *args, c:, d: 2, **kwargs, &block)
97
- # end
98
- #
99
- # ConvenientService::Support::MethodParameters.new(method(:foo).parameters).required_kwargs_keys
100
- # # => [:c]
101
- #
102
- # @see https://ruby-doc.org/core-2.7.1/Method.html#method-i-parameters
103
- #
104
- def required_kwargs_keys
105
- @required_kwargs_keys ||= method_parameters.select { |type, _name| type == Constants::Types::REQUIRED_KEYWORD }.map { |_type, name| name }
106
- end
107
-
108
- ##
109
- # @return [Array<Symbol>]
110
- #
111
- # @note `optional_kwargs` are named `kwargs` with `defaults`.
112
- #
113
- # def foo(a, b = 1, *args, c:, d: 2, **kwargs, &block)
114
- # end
115
- #
116
- # ConvenientService::Support::MethodParameters.new(method(:foo).parameters).optional_kwargs_keys
117
- # # => [:d]
118
- #
119
- # @see https://ruby-doc.org/core-2.7.1/Method.html#method-i-parameters
120
- #
121
- def optional_kwargs_keys
122
- @optional_kwargs_keys ||= method_parameters.select { |type, _name| type == Constants::Types::OPTIONAL_KEYWORD }.map { |_type, name| name }
123
- end
124
- end
125
- end
126
- end