cuprum 0.10.0 → 0.11.0.rc.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.
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/rspec'
4
+
5
+ module Cuprum::RSpec
6
+ module Matchers # rubocop:disable Style/Documentation
7
+ # Asserts that the command defines a :process method.
8
+ #
9
+ # @return [RSpec::Matchers::BuiltIn::RespondTo] the generated matcher.
10
+ def be_callable
11
+ respond_to(:process, true)
12
+ end
13
+ end
14
+ end
data/lib/cuprum/steps.rb CHANGED
@@ -63,6 +63,9 @@ module Cuprum
63
63
  module Steps
64
64
  include Cuprum::ResultHelpers
65
65
 
66
+ UNDEFINED = Object.new.freeze
67
+ private_constant :UNDEFINED
68
+
66
69
  class << self
67
70
  # @!visibility private
68
71
  def execute_method(receiver, method_name, *args, **kwargs, &block)
@@ -110,109 +113,62 @@ module Cuprum
110
113
  # rubocop:enable Metrics/MethodLength
111
114
  end
112
115
 
113
- # @overload step()
114
- # Executes the block and returns the value, or halts on a failure.
115
- #
116
- # @yield Called with no parameters.
117
- #
118
- # @return [Object] the #value of the result, or the returned object.
119
- #
120
- # The #step method is used to evaluate a sequence of processes, and to
121
- # fail fast and halt processing if any of the steps returns a failing
122
- # result. Each invocation of #step should be wrapped in a #steps block,
123
- # or used inside the #process method of a Command.
124
- #
125
- # If the object returned by the block is a Cuprum result or compatible
126
- # object (such as a called operation), the value is converted to a Cuprum
127
- # result via the #to_cuprum_result method. Otherwise, the object is
128
- # returned directly from #step.
129
- #
130
- # If the returned object is a passing result, the #value of the result is
131
- # returned by #step.
132
- #
133
- # If the returned object is a failing result, then #step will throw
134
- # :cuprum_failed_result and the failing result. This is caught by the
135
- # #steps block, and halts execution of any subsequent steps.
136
- #
137
- # @example Calling a Step
138
- # # The #do_something method returns the string 'some value'.
139
- # step { do_something() } #=> 'some value'
140
- #
141
- # value = step { do_something() }
142
- # value #=> 'some value'
116
+ # Executes the block and returns the value, or halts on a failure.
143
117
  #
144
- # @example Calling a Step with a Passing Result
145
- # # The #do_something_else method returns a Cuprum result with a value
146
- # # of 'another value'.
147
- # step { do_something_else() } #=> 'another value'
148
- #
149
- # # The result is passing, so the value is extracted and returned.
150
- # value = step { do_something_else() }
151
- # value #=> 'another value'
152
- #
153
- # @example Calling a Step with a Failing Result
154
- # # The #do_something_wrong method returns a failing Cuprum result.
155
- # step { do_something_wrong() } # Throws the :cuprum_failed_step symbol.
156
- #
157
- # @overload step(method_name, *arguments, **keywords)
158
- # Calls the method and returns the value, or halts on a failure.
159
- #
160
- # @param method_name [String, Symbol] The name of the method to call. Must
161
- # be the name of a method on the current object.
162
- # @param arguments [Array] Positional arguments to pass to the method.
163
- # @param keywords [Hash] Keyword arguments to pass to the method.
164
- #
165
- # @yield A block to pass to the method.
118
+ # @yield Called with no parameters.
166
119
  #
167
- # @return [Object] the #value of the result, or the returned object.
120
+ # @return [Object] the #value of the result, or the returned object.
168
121
  #
169
- # The #step method is used to evaluate a sequence of processes, and to
170
- # fail fast and halt processing if any of the steps returns a failing
171
- # result. Each invocation of #step should be wrapped in a #steps block,
172
- # or used inside the #process method of a Command.
122
+ # The #step method is used to evaluate a sequence of processes, and to
123
+ # fail fast and halt processing if any of the steps returns a failing
124
+ # result. Each invocation of #step should be wrapped in a #steps block,
125
+ # or used inside the #process method of a Command.
173
126
  #
174
- # If the object returned by the block is a Cuprum result or compatible
175
- # object (such as a called operation), the value is converted to a Cuprum
176
- # result via the #to_cuprum_result method. Otherwise, the object is
177
- # returned directly from #step.
127
+ # If the object returned by the block is a Cuprum result or compatible
128
+ # object (such as a called operation), the value is converted to a Cuprum
129
+ # result via the #to_cuprum_result method. Otherwise, the object is
130
+ # returned directly from #step.
178
131
  #
179
- # If the returned object is a passing result, the #value of the result is
180
- # returned by #step.
132
+ # If the returned object is a passing result, the #value of the result is
133
+ # returned by #step.
181
134
  #
182
- # If the returned object is a failing result, then #step will throw
183
- # :cuprum_failed_result and the failing result. This is caught by the
184
- # #steps block, and halts execution of any subsequent steps.
135
+ # If the returned object is a failing result, then #step will throw
136
+ # :cuprum_failed_result and the failing result. This is caught by the
137
+ # #steps block, and halts execution of any subsequent steps.
185
138
  #
186
- # @example Calling a Step
187
- # # The #zero method returns the integer 0.
188
- # step :zero #=> 0
139
+ # @example Calling a Step
140
+ # # The #do_something method returns the string 'some value'.
141
+ # step { do_something() } #=> 'some value'
189
142
  #
190
- # value = step :zero
191
- # value #=> 0
143
+ # value = step { do_something() }
144
+ # value #=> 'some value'
192
145
  #
193
- # @example Calling a Step with a Passing Result
194
- # # The #add method adds the numbers and returns a Cuprum result with a
195
- # # value equal to the sum.
196
- # step :add, 2, 2
197
- # #=> 4
146
+ # @example Calling a Step with a Passing Result
147
+ # # The #do_something_else method returns a Cuprum result with a value
148
+ # # of 'another value'.
149
+ # step { do_something_else() } #=> 'another value'
198
150
  #
199
- # # The result is passing, so the value is extracted and returned.
200
- # value = step :add, 2, 2
201
- # value #=> 4
151
+ # # The result is passing, so the value is extracted and returned.
152
+ # value = step { do_something_else() }
153
+ # value #=> 'another value'
202
154
  #
203
- # @example Calling a Step with a Failing Result
204
- # # The #divide method returns a failing Cuprum result when the second
205
- # # argument is zero.
206
- # step :divide, 1, 0
207
- # # Throws the :cuprum_failed_step symbol, which should be caught by the
208
- # # enclosing #steps block.
209
- def step(method_name = nil, *args, **kwargs, &block)
155
+ # @example Calling a Step with a Failing Result
156
+ # # The #do_something_wrong method returns a failing Cuprum result.
157
+ # step { do_something_wrong() } # Throws the :cuprum_failed_step symbol.
158
+ def step(method_name = UNDEFINED, *args, **kwargs, &block) # rubocop:disable Metrics/MethodLength
210
159
  result =
211
- if !block_given? || method_name || !args.empty? || !kwargs.empty?
160
+ if method_name != UNDEFINED || !args.empty? || !kwargs.empty?
161
+ SleepingKingStudios::Tools::CoreTools.deprecate(
162
+ "#{self.class}#step(method_name)",
163
+ message: 'Use the block form: step { method_name(*args, **kwargs) }'
164
+ )
165
+
212
166
  Cuprum::Steps.validate_method_name(method_name)
213
167
 
214
168
  Cuprum::Steps
215
169
  .execute_method(self, method_name, *args, **kwargs, &block)
170
+ elsif !block_given?
171
+ raise ArgumentError, 'expected a block'
216
172
  else
217
173
  block.call
218
174
  end
@@ -264,8 +220,10 @@ module Cuprum
264
220
  # result.class #=> Cuprum::Result
265
221
  # result.success? #=> false
266
222
  # result.error #=> 'second step'
267
- def steps
268
- result = catch(:cuprum_failed_step) { yield }
223
+ def steps(&block)
224
+ raise ArgumentError, 'no block given' unless block_given?
225
+
226
+ result = catch(:cuprum_failed_step) { block.call }
269
227
 
270
228
  return result if result.respond_to?(:to_cuprum_result)
271
229
 
data/lib/cuprum/utils.rb CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cuprum'
2
4
 
3
5
  module Cuprum
4
6
  # Namespace for utility modules.
5
7
  module Utils; end
6
- end # module
8
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cuprum/utils'
2
4
 
3
5
  module Cuprum::Utils
@@ -28,14 +30,14 @@ module Cuprum::Utils
28
30
  # expect(spy).to receive(:call)
29
31
  #
30
32
  # CustomCommand.new.call
31
- # end # spy_on
33
+ # end
32
34
  module InstanceSpy
33
35
  # Minimal class that implements a #call method to mirror method calls to
34
36
  # instances of an instrumented command class.
35
37
  class Spy
36
38
  # Empty method that accepts any arguments and an optional block.
37
- def call *_args, &block; end
38
- end # class
39
+ def call(*_args, &block); end
40
+ end
39
41
 
40
42
  class << self
41
43
  # Retires all spies. Subsequent calls to the #call method on command
@@ -44,7 +46,7 @@ module Cuprum::Utils
44
46
  Thread.current[:cuprum_instance_spies] = nil
45
47
 
46
48
  nil
47
- end # method clear_spies
49
+ end
48
50
 
49
51
  # Finds or creates a spy object for the given module or class. Each time
50
52
  # that the #call method is called for an object of the given type, the
@@ -68,41 +70,39 @@ module Cuprum::Utils
68
70
  # @yield [Cuprum::Utils::InstanceSpy::Spy] The instance spy.
69
71
  #
70
72
  # @return [nil] nil.
71
- def spy_on command_class
73
+ def spy_on(command_class)
72
74
  guard_spy_class!(command_class)
73
75
 
74
76
  instrument_call!
75
77
 
76
78
  if block_given?
77
- begin
78
- instance_spy = assign_spy(command_class)
79
+ instance_spy = assign_spy(command_class)
79
80
 
80
- yield instance_spy
81
- end # begin-ensure
81
+ yield instance_spy
82
82
  else
83
83
  assign_spy(command_class)
84
- end # if-else
85
- end # method spy_on
84
+ end
85
+ end
86
86
 
87
87
  private
88
88
 
89
- def assign_spy command_class
89
+ def assign_spy(command_class)
90
90
  existing_spy = spies[command_class]
91
91
 
92
92
  return existing_spy if existing_spy
93
93
 
94
94
  spies[command_class] = build_spy
95
- end # method assign_spy
95
+ end
96
96
 
97
97
  def build_spy
98
98
  Cuprum::Utils::InstanceSpy::Spy.new
99
- end # method build_spy
99
+ end
100
100
 
101
- def call_spies_for command, *args, &block
101
+ def call_spies_for(command, *args, &block)
102
102
  spies_for(command).each { |spy| spy.call(*args, &block) }
103
- end # method call_spies_for
103
+ end
104
104
 
105
- def guard_spy_class! command_class
105
+ def guard_spy_class!(command_class)
106
106
  return if command_class.is_a?(Module) && !command_class.is_a?(Class)
107
107
 
108
108
  return if command_class.is_a?(Class) &&
@@ -111,25 +111,25 @@ module Cuprum::Utils
111
111
  raise ArgumentError,
112
112
  'must be a class inheriting from Cuprum::Command',
113
113
  caller(1..-1)
114
- end # method guard_spy_class!
114
+ end
115
115
 
116
116
  def instrument_call!
117
117
  return if Cuprum::Command < Cuprum::Utils::InstanceSpy
118
118
 
119
119
  Cuprum::Command.prepend(Cuprum::Utils::InstanceSpy)
120
- end # method instrument_call!
120
+ end
121
121
 
122
122
  def spies
123
123
  Thread.current[:cuprum_instance_spies] ||= {}
124
- end # method spies
124
+ end
125
125
 
126
- def spies_for command
126
+ def spies_for(command)
127
127
  spies.select { |mod, _| command.is_a?(mod) }.map { |_, spy| spy }
128
- end # method spies_for
129
- end # eigenclass
128
+ end
129
+ end
130
130
 
131
- # (see Cuprum::Command#call)
132
- def call *args, **kwargs, &block
131
+ # (see Cuprum::Processing#call)
132
+ def call(*args, **kwargs, &block)
133
133
  if kwargs.empty?
134
134
  Cuprum::Utils::InstanceSpy.send(:call_spies_for, self, *args, &block)
135
135
  else
@@ -140,6 +140,6 @@ module Cuprum::Utils
140
140
  end
141
141
 
142
142
  super
143
- end # method call
144
- end # module
145
- end # module
143
+ end
144
+ end
145
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cuprum
2
4
  # @api private
3
5
  #
@@ -8,13 +10,13 @@ module Cuprum
8
10
  # Major version.
9
11
  MAJOR = 0
10
12
  # Minor version.
11
- MINOR = 10
13
+ MINOR = 11
12
14
  # Patch version.
13
15
  PATCH = 0
14
16
  # Prerelease version.
15
- PRERELEASE = nil
17
+ PRERELEASE = :rc
16
18
  # Build metadata.
17
- BUILD = nil
19
+ BUILD = 0
18
20
 
19
21
  class << self
20
22
  # Generates the gem version string from the Version constants.
@@ -28,17 +30,17 @@ module Cuprum
28
30
  str = "#{MAJOR}.#{MINOR}.#{PATCH}"
29
31
 
30
32
  prerelease = value_of(:PRERELEASE)
31
- str << ".#{prerelease}" if prerelease
33
+ str = "#{str}.#{prerelease}" if prerelease
32
34
 
33
35
  build = value_of(:BUILD)
34
- str << ".#{build}" if build
36
+ str = "#{str}.#{build}" if build
35
37
 
36
38
  str
37
- end # class method to_version
39
+ end
38
40
 
39
41
  private
40
42
 
41
- def value_of constant
43
+ def value_of(constant)
42
44
  return nil unless const_defined?(constant)
43
45
 
44
46
  value = const_get(constant)
@@ -46,9 +48,10 @@ module Cuprum
46
48
  return nil if value.respond_to?(:empty?) && value.empty?
47
49
 
48
50
  value
49
- end # method value_of
50
- end # eigenclass
51
- end # module
51
+ end
52
+ end
53
+ end
52
54
 
55
+ # The current version of the gem.
53
56
  VERSION = Version.to_gem_version
54
- end # module
57
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuprum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0.rc.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob "Merlin" Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-22 00:00:00.000000000 Z
11
+ date: 2021-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sleeping_king_studios-tools
@@ -16,70 +16,70 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.8'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.8'
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.6'
33
+ version: '3.10'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.6'
40
+ version: '3.10'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec-sleeping_king_studios
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.3'
47
+ version: '2.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.3'
54
+ version: '2.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.49.1
61
+ version: 1.10.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.49.1
68
+ version: 1.10.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.15'
75
+ version: '2.1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.15'
82
+ version: '2.1'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -94,9 +94,11 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.15'
97
- description: An opinionated implementation of the Command pattern for Ruby applications.
98
- Cuprum wraps your business logic in a consistent, object-oriented interface and
99
- features status and error management, composability and control flow management.
97
+ description: |-
98
+ An opinionated implementation of the Command pattern for Ruby applications.
99
+ Cuprum wraps your business logic in a consistent, object-oriented interface
100
+ and features status and error management, composability and control flow
101
+ management.
100
102
  email:
101
103
  - merlin@sleepingkingstudios.com
102
104
  executables: []
@@ -113,7 +115,6 @@ files:
113
115
  - lib/cuprum/built_in/identity_operation.rb
114
116
  - lib/cuprum/built_in/null_command.rb
115
117
  - lib/cuprum/built_in/null_operation.rb
116
- - lib/cuprum/chaining.rb
117
118
  - lib/cuprum/command.rb
118
119
  - lib/cuprum/command_factory.rb
119
120
  - lib/cuprum/currying.rb
@@ -122,6 +123,13 @@ files:
122
123
  - lib/cuprum/errors.rb
123
124
  - lib/cuprum/errors/command_not_implemented.rb
124
125
  - lib/cuprum/errors/operation_not_called.rb
126
+ - lib/cuprum/errors/uncaught_exception.rb
127
+ - lib/cuprum/exception_handling.rb
128
+ - lib/cuprum/matcher.rb
129
+ - lib/cuprum/matcher_list.rb
130
+ - lib/cuprum/matching.rb
131
+ - lib/cuprum/matching/match_clause.rb
132
+ - lib/cuprum/middleware.rb
125
133
  - lib/cuprum/operation.rb
126
134
  - lib/cuprum/processing.rb
127
135
  - lib/cuprum/result.rb
@@ -129,6 +137,7 @@ files:
129
137
  - lib/cuprum/rspec.rb
130
138
  - lib/cuprum/rspec/be_a_result.rb
131
139
  - lib/cuprum/rspec/be_a_result_matcher.rb
140
+ - lib/cuprum/rspec/be_callable.rb
132
141
  - lib/cuprum/steps.rb
133
142
  - lib/cuprum/utils.rb
134
143
  - lib/cuprum/utils/instance_spy.rb
@@ -136,7 +145,9 @@ files:
136
145
  homepage: http://sleepingkingstudios.com
137
146
  licenses:
138
147
  - MIT
139
- metadata: {}
148
+ metadata:
149
+ bug_tracker_uri: https://github.com/sleepingkingstudios/cuprum/issues
150
+ source_code_uri: https://github.com/sleepingkingstudios/cuprum
140
151
  post_install_message:
141
152
  rdoc_options: []
142
153
  require_paths:
@@ -145,14 +156,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
156
  requirements:
146
157
  - - ">="
147
158
  - !ruby/object:Gem::Version
148
- version: '0'
159
+ version: 2.5.0
149
160
  required_rubygems_version: !ruby/object:Gem::Requirement
150
161
  requirements:
151
- - - ">="
162
+ - - ">"
152
163
  - !ruby/object:Gem::Version
153
- version: '0'
164
+ version: 1.3.1
154
165
  requirements: []
155
- rubygems_version: 3.1.2
166
+ rubygems_version: 3.1.4
156
167
  signing_key:
157
168
  specification_version: 4
158
169
  summary: An opinionated implementation of the Command pattern.