cuprum 0.10.0 → 1.0.0.rc.1

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cuprum/command'
2
4
  require 'cuprum/errors/operation_not_called'
3
5
 
@@ -26,8 +28,8 @@ module Cuprum
26
28
  # @book = operation.value
27
29
  #
28
30
  # render :new
29
- # end # if-else
30
- # end # create
31
+ # end
32
+ # end
31
33
  #
32
34
  # Like a Command, an Operation can be defined directly by passing an
33
35
  # implementation block to the constructor or by creating a subclass that
@@ -41,7 +43,7 @@ module Cuprum
41
43
  # @example
42
44
  # class CustomOperation < CustomCommand
43
45
  # include Cuprum::Operation::Mixin
44
- # end # class
46
+ # end
45
47
  module Mixin
46
48
  # @return [Cuprum::Result] The result from the most recent call of the
47
49
  # operation.
@@ -62,32 +64,32 @@ module Cuprum
62
64
  # implementation.
63
65
  #
64
66
  # @see Cuprum::Command#call
65
- def call *args, **kwargs, &block
67
+ def call(*args, **kwargs, &block)
66
68
  reset! if called? # Clear reference to most recent result.
67
69
 
68
70
  @result = super
69
71
 
70
72
  self
71
- end # method call
73
+ end
72
74
 
73
75
  # @return [Boolean] true if the operation has been called and has a
74
76
  # reference to the most recent result; otherwise false.
75
77
  def called?
76
78
  !result.nil?
77
- end # method called?
79
+ end
78
80
 
79
81
  # @return [Object] the error (if any) from the most recent result, or nil
80
82
  # if the operation has not been called.
81
83
  def error
82
84
  called? ? result.error : nil
83
- end # method error
85
+ end
84
86
 
85
87
  # @return [Boolean] true if the most recent result had an error, or false
86
88
  # if the most recent result had no error or if the operation has not
87
89
  # been called.
88
90
  def failure?
89
91
  called? ? result.failure? : false
90
- end # method failure?
92
+ end
91
93
 
92
94
  # Clears the reference to the most recent call of the operation, if any.
93
95
  # This allows the result and any referenced data to be garbage collected.
@@ -99,7 +101,7 @@ module Cuprum
99
101
  # an error.
100
102
  def reset!
101
103
  @result = nil
102
- end # method reset
104
+ end
103
105
 
104
106
  # @return [Symbol, nil] the status of the most recent result, or nil if
105
107
  # the operation has not been called.
@@ -112,7 +114,7 @@ module Cuprum
112
114
  # been called.
113
115
  def success?
114
116
  called? ? result.success? : false
115
- end # method success?
117
+ end
116
118
 
117
119
  # Returns the most result if the operation was previously called.
118
120
  # Otherwise, returns a failing result.
@@ -130,8 +132,8 @@ module Cuprum
130
132
  # operation has not been called.
131
133
  def value
132
134
  called? ? result.value : nil
133
- end # method value
134
- end # module
135
+ end
136
+ end
135
137
  include Mixin
136
138
 
137
139
  # @!method call
@@ -156,9 +158,9 @@ module Cuprum
156
158
  # (see Cuprum::Operation::Mixin#success?)
157
159
 
158
160
  # @!method to_cuprum_result
159
- # (see Cuprum::Operation::Mixin#to_cuprum_result?)
161
+ # (see Cuprum::Operation::Mixin#to_cuprum_result)
160
162
 
161
163
  # @!method value
162
164
  # (see Cuprum::Operation::Mixin#value)
163
- end # class
164
- end # module
165
+ end
166
+ end
data/lib/cuprum/result.rb CHANGED
@@ -5,6 +5,7 @@ require 'cuprum'
5
5
  module Cuprum
6
6
  # Data object that encapsulates the result of calling a Cuprum command.
7
7
  class Result
8
+ # Enumerates the default permitted values for a Result#status.
8
9
  STATUSES = %i[success failure].freeze
9
10
 
10
11
  # @param value [Object] The value returned by calling the command.
@@ -28,8 +29,6 @@ module Cuprum
28
29
  # @return [Symbol] the status of the result, either :success or :failure.
29
30
  attr_reader :status
30
31
 
31
- # rubocop:disable Metrics/CyclomaticComplexity
32
-
33
32
  # Compares the other object to the result.
34
33
  #
35
34
  # @param other [#value, #success?] An object responding to, at minimum,
@@ -45,7 +44,6 @@ module Cuprum
45
44
 
46
45
  true
47
46
  end
48
- # rubocop:enable Metrics/CyclomaticComplexity
49
47
 
50
48
  # @return [Boolean] true if the result status is :failure, otherwise false.
51
49
  def failure?
@@ -2,16 +2,25 @@
2
2
 
3
3
  require 'cuprum/rspec/be_a_result_matcher'
4
4
 
5
- module RSpec
5
+ module Cuprum::RSpec
6
6
  module Matchers # rubocop:disable Style/Documentation
7
+ # Asserts that the object is a Cuprum::Result with status: :failure.
8
+ #
9
+ # @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
7
10
  def be_a_failing_result
8
11
  be_a_result.with_status(:failure)
9
12
  end
10
13
 
14
+ # Asserts that the object is a Cuprum::Result with status: :success.
15
+ #
16
+ # @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
11
17
  def be_a_passing_result
12
18
  be_a_result.with_status(:success).and_error(nil)
13
19
  end
14
20
 
21
+ # Asserts that the object is a Cuprum::Result.
22
+ #
23
+ # @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
15
24
  def be_a_result
16
25
  Cuprum::RSpec::BeAResultMatcher.new
17
26
  end
@@ -46,9 +46,9 @@ module Cuprum::RSpec
46
46
  message = "expected #{actual.inspect} to #{description}"
47
47
 
48
48
  if !actual_is_result?
49
- message + ', but the object is not a result'
49
+ "#{message}, but the object is not a result"
50
50
  elsif actual_is_uncalled_operation?
51
- message + ', but the object is an uncalled operation'
51
+ "#{message}, but the object is an uncalled operation"
52
52
  elsif !properties_match?
53
53
  message + properties_failure_message
54
54
  else
@@ -182,7 +182,6 @@ module Cuprum::RSpec
182
182
  ' positives, since any other result will match.'
183
183
  end
184
184
 
185
- # rubocop:disable Metrics/CyclomaticComplexity
186
185
  # rubocop:disable Metrics/AbcSize
187
186
  def properties_description
188
187
  msg = ''
@@ -200,7 +199,6 @@ module Cuprum::RSpec
200
199
 
201
200
  msg + " and status: #{expected_status.inspect}"
202
201
  end
203
- # rubocop:enable Metrics/CyclomaticComplexity
204
202
  # rubocop:enable Metrics/AbcSize
205
203
 
206
204
  def properties_failure_message
@@ -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,161 +63,60 @@ module Cuprum
63
63
  module Steps
64
64
  include Cuprum::ResultHelpers
65
65
 
66
- class << self
67
- # @!visibility private
68
- def execute_method(receiver, method_name, *args, **kwargs, &block)
69
- if block_given? && kwargs.empty?
70
- receiver.send(method_name, *args, &block)
71
- elsif block_given?
72
- receiver.send(method_name, *args, **kwargs, &block)
73
- elsif kwargs.empty?
74
- receiver.send(method_name, *args)
75
- else
76
- receiver.send(method_name, *args, **kwargs)
77
- end
78
- end
79
-
80
- # @!visibility private
81
- def extract_result_value(result)
82
- return result unless result.respond_to?(:to_cuprum_result)
83
-
84
- result = result.to_cuprum_result
85
-
86
- return result.value if result.success?
87
-
88
- throw :cuprum_failed_step, result
89
- end
90
-
91
- # rubocop:disable Metrics/MethodLength
92
- # @!visibility private
93
- def validate_method_name(method_name)
94
- if method_name.nil?
95
- raise ArgumentError,
96
- 'expected a block or a method name',
97
- caller(1..-1)
98
- end
99
-
100
- unless method_name.is_a?(String) || method_name.is_a?(Symbol)
101
- raise ArgumentError,
102
- 'expected method name to be a String or Symbol',
103
- caller(1..-1)
104
- end
105
-
106
- return unless method_name.empty?
107
-
108
- raise ArgumentError, "method name can't be blank", caller(1..-1)
109
- end
110
- # rubocop:enable Metrics/MethodLength
111
- end
112
-
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.
66
+ # Executes the block and returns the value, or halts on a failure.
129
67
  #
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'
143
- #
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.
68
+ # @yield Called with no parameters.
166
69
  #
167
- # @return [Object] the #value of the result, or the returned object.
70
+ # @return [Object] the #value of the result, or the returned object.
168
71
  #
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.
72
+ # The #step method is used to evaluate a sequence of processes, and to
73
+ # fail fast and halt processing if any of the steps returns a failing
74
+ # result. Each invocation of #step should be wrapped in a #steps block,
75
+ # or used inside the #process method of a Command.
173
76
  #
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.
77
+ # If the object returned by the block is a Cuprum result or compatible
78
+ # object (such as a called operation), the value is converted to a Cuprum
79
+ # result via the #to_cuprum_result method. Otherwise, the object is
80
+ # returned directly from #step.
178
81
  #
179
- # If the returned object is a passing result, the #value of the result is
180
- # returned by #step.
82
+ # If the returned object is a passing result, the #value of the result is
83
+ # returned by #step.
181
84
  #
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.
85
+ # If the returned object is a failing result, then #step will throw
86
+ # :cuprum_failed_result and the failing result. This is caught by the
87
+ # #steps block, and halts execution of any subsequent steps.
185
88
  #
186
- # @example Calling a Step
187
- # # The #zero method returns the integer 0.
188
- # step :zero #=> 0
89
+ # @example Calling a Step
90
+ # # The #do_something method returns the string 'some value'.
91
+ # step { do_something() } #=> 'some value'
189
92
  #
190
- # value = step :zero
191
- # value #=> 0
93
+ # value = step { do_something() }
94
+ # value #=> 'some value'
192
95
  #
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
96
+ # @example Calling a Step with a Passing Result
97
+ # # The #do_something_else method returns a Cuprum result with a value
98
+ # # of 'another value'.
99
+ # step { do_something_else() } #=> 'another value'
198
100
  #
199
- # # The result is passing, so the value is extracted and returned.
200
- # value = step :add, 2, 2
201
- # value #=> 4
101
+ # # The result is passing, so the value is extracted and returned.
102
+ # value = step { do_something_else() }
103
+ # value #=> 'another value'
202
104
  #
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)
210
- result =
211
- if !block_given? || method_name || !args.empty? || !kwargs.empty?
212
- Cuprum::Steps.validate_method_name(method_name)
105
+ # @example Calling a Step with a Failing Result
106
+ # # The #do_something_wrong method returns a failing Cuprum result.
107
+ # step { do_something_wrong() } # Throws the :cuprum_failed_step symbol.
108
+ def step
109
+ raise ArgumentError, 'expected a block' unless block_given?
110
+
111
+ result = yield
213
112
 
214
- Cuprum::Steps
215
- .execute_method(self, method_name, *args, **kwargs, &block)
216
- else
217
- block.call
218
- end
113
+ return result unless result.respond_to?(:to_cuprum_result)
219
114
 
220
- Cuprum::Steps.extract_result_value(result)
115
+ result = result.to_cuprum_result
116
+
117
+ return result.value if result.success?
118
+
119
+ throw :cuprum_failed_step, result
221
120
  end
222
121
 
223
122
  # Returns the first failing #step result, or the final result if none fail.
@@ -264,8 +163,10 @@ module Cuprum
264
163
  # result.class #=> Cuprum::Result
265
164
  # result.success? #=> false
266
165
  # result.error #=> 'second step'
267
- def steps
268
- result = catch(:cuprum_failed_step) { yield }
166
+ def steps(&block)
167
+ raise ArgumentError, 'no block given' unless block_given?
168
+
169
+ result = catch(:cuprum_failed_step) { block.call }
269
170
 
270
171
  return result if result.respond_to?(:to_cuprum_result)
271
172
 
@@ -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
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
  module Cuprum
2
4
  # @api private
3
5
  #
@@ -6,15 +8,15 @@ module Cuprum
6
8
  # @see http://semver.org/
7
9
  module Version
8
10
  # Major version.
9
- MAJOR = 0
11
+ MAJOR = 1
10
12
  # Minor version.
11
- MINOR = 10
13
+ MINOR = 0
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 = 1
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
data/lib/cuprum.rb CHANGED
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A lightweight, functional-lite toolkit for making business logic a first-class
2
4
  # citizen of your application.
3
5
  module Cuprum
4
- autoload :Command, 'cuprum/command'
5
- autoload :Operation, 'cuprum/operation'
6
- autoload :Result, 'cuprum/result'
7
- autoload :Steps, 'cuprum/steps'
6
+ autoload :Command, 'cuprum/command'
7
+ autoload :Error, 'cuprum/error'
8
+ autoload :Matcher, 'cuprum/matcher'
9
+ autoload :Middleware, 'cuprum/middleware'
10
+ autoload :Operation, 'cuprum/operation'
11
+ autoload :Result, 'cuprum/result'
12
+ autoload :Steps, 'cuprum/steps'
8
13
 
9
14
  class << self
10
15
  # @return [String] The current version of the gem.
11
16
  def version
12
17
  VERSION
13
- end # method version
14
- end # eigenclass
15
- end # module
18
+ end
19
+ end
20
+ end