cuprum 0.6.0 → 0.7.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,19 +2,19 @@ require 'cuprum/utils'
2
2
 
3
3
  module Cuprum::Utils
4
4
  # Utility module for instrumenting calls to the #call method of any instance
5
- # of a function class. This can be used to unobtrusively test the
6
- # functionality of code that calls a function without providing a reference to
7
- # the function instance, such as chained functions or methods that create and
8
- # call a function instance.
5
+ # of a command class. This can be used to unobtrusively test the
6
+ # functionality of code that calls a command without providing a reference to
7
+ # the command instance, such as chained commands or methods that create and
8
+ # call a command instance.
9
9
  #
10
- # @example Observing calls to instances of a function.
10
+ # @example Observing calls to instances of a command.
11
11
  # spy = Cuprum::Utils::InstanceSpy.spy_on(CustomCommand)
12
12
  #
13
13
  # expect(spy).to receive(:call).with(1, 2, 3, :four => '4')
14
14
  #
15
15
  # CustomCommand.new.call(1, 2, 3, :four => '4')
16
16
  #
17
- # @example Observing calls to a chained function.
17
+ # @example Observing calls to a chained command.
18
18
  # spy = Cuprum::Utils::InstanceSpy.spy_on(ChainedCommand)
19
19
  #
20
20
  # expect(spy).to receive(:call)
@@ -31,14 +31,14 @@ module Cuprum::Utils
31
31
  # end # spy_on
32
32
  module InstanceSpy
33
33
  # Minimal class that implements a #call method to mirror method calls to
34
- # instances of an instrumented function class.
34
+ # instances of an instrumented command class.
35
35
  class Spy
36
36
  # Empty method that accepts any arguments and an optional block.
37
37
  def call *_args, █ end
38
38
  end # class
39
39
 
40
40
  class << self
41
- # Retires all spies. Subsequent calls to the #call method on function
41
+ # Retires all spies. Subsequent calls to the #call method on command
42
42
  # instances will not be mirrored to existing spy objects.
43
43
  def clear_spies
44
44
  Thread.current[:cuprum_instance_spies] = nil
@@ -50,7 +50,7 @@ module Cuprum::Utils
50
50
  # that the #call method is called for an object of the given type, the
51
51
  # spy's #call method will be invoked with the same arguments and block.
52
52
  #
53
- # @param function_class [Class, Module] The type of function to spy on.
53
+ # @param command_class [Class, Module] The type of command to spy on.
54
54
  # Must be either a Module, or a Class that extends Cuprum::Command.
55
55
  #
56
56
  # @raise [ArgumentError] If the argument is neither a Module nor a Class
@@ -59,54 +59,54 @@ module Cuprum::Utils
59
59
  # @note Calling this method for the first time will prepend the
60
60
  # Cuprum::Utils::InstanceSpy module to Cuprum::Command.
61
61
  #
62
- # @overload spy_on(function_class)
62
+ # @overload spy_on(command_class)
63
63
  # @return [Cuprum::Utils::InstanceSpy::Spy] The instance spy.
64
64
  #
65
- # @overload spy_on(function_class, &block)
65
+ # @overload spy_on(command_class, &block)
66
66
  # Yields the instance spy to the block, and returns nil.
67
67
  #
68
68
  # @yield [Cuprum::Utils::InstanceSpy::Spy] The instance spy.
69
69
  #
70
70
  # @return [nil] nil.
71
- def spy_on function_class
72
- guard_spy_class!(function_class)
71
+ def spy_on command_class
72
+ guard_spy_class!(command_class)
73
73
 
74
74
  instrument_call!
75
75
 
76
76
  if block_given?
77
77
  begin
78
- instance_spy = assign_spy(function_class)
78
+ instance_spy = assign_spy(command_class)
79
79
 
80
80
  yield instance_spy
81
81
  end # begin-ensure
82
82
  else
83
- assign_spy(function_class)
83
+ assign_spy(command_class)
84
84
  end # if-else
85
85
  end # method spy_on
86
86
 
87
87
  private
88
88
 
89
- def assign_spy function_class
90
- existing_spy = spies[function_class]
89
+ def assign_spy command_class
90
+ existing_spy = spies[command_class]
91
91
 
92
92
  return existing_spy if existing_spy
93
93
 
94
- spies[function_class] = build_spy
94
+ spies[command_class] = build_spy
95
95
  end # method assign_spy
96
96
 
97
97
  def build_spy
98
98
  Cuprum::Utils::InstanceSpy::Spy.new
99
99
  end # method build_spy
100
100
 
101
- def call_spies_for function, *args, &block
102
- spies_for(function).each { |spy| spy.call(*args, &block) }
101
+ def call_spies_for command, *args, &block
102
+ spies_for(command).each { |spy| spy.call(*args, &block) }
103
103
  end # method call_spies_for
104
104
 
105
- def guard_spy_class! function_class
106
- return if function_class.is_a?(Module) && !function_class.is_a?(Class)
105
+ def guard_spy_class! command_class
106
+ return if command_class.is_a?(Module) && !command_class.is_a?(Class)
107
107
 
108
- return if function_class.is_a?(Class) &&
109
- function_class <= Cuprum::Command
108
+ return if command_class.is_a?(Class) &&
109
+ command_class <= Cuprum::Command
110
110
 
111
111
  raise ArgumentError,
112
112
  'must be a class inheriting from Cuprum::Command',
@@ -123,8 +123,8 @@ module Cuprum::Utils
123
123
  Thread.current[:cuprum_instance_spies] ||= {}
124
124
  end # method spies
125
125
 
126
- def spies_for function
127
- spies.select { |mod, _| function.is_a?(mod) }.map { |_, spy| spy }
126
+ def spies_for command
127
+ spies.select { |mod, _| command.is_a?(mod) }.map { |_, spy| spy }
128
128
  end # method spies_for
129
129
  end # eigenclass
130
130
 
@@ -0,0 +1,65 @@
1
+ require 'cuprum/utils'
2
+
3
+ module Cuprum::Utils
4
+ # Helper class for building a warning message when a command returns a result,
5
+ # but the command's current result already has errors, a set status, or is
6
+ # halted.
7
+ class ResultNotEmptyWarning
8
+ MESSAGE = '#process returned a result, but '.freeze
9
+ private_constant :MESSAGE
10
+
11
+ # @param result [Cuprum::Result] The result for which to generate the
12
+ # warning message.
13
+ def initialize result
14
+ @result = result
15
+ end # constructor
16
+
17
+ # @return [String] The warning message for the given result.
18
+ def message
19
+ # byebug
20
+ MESSAGE + humanize_list(warnings).freeze
21
+ end # method message
22
+
23
+ private
24
+
25
+ attr_reader :result
26
+
27
+ def errors_not_empty_warning
28
+ return nil if result.errors.empty?
29
+
30
+ "there were already errors #{@result.errors.inspect}".freeze
31
+ end # method errors_not_empty_warning
32
+
33
+ def halted_warning
34
+ return nil unless result.halted?
35
+
36
+ 'the command was halted'.freeze
37
+ end # method halted_warning
38
+
39
+ def humanize_list list, empty_value: ''
40
+ return empty_value if list.size.zero?
41
+
42
+ return list.first.to_s if list.size == 1
43
+
44
+ return "#{list.first} and #{list.last}" if list.size == 2
45
+
46
+ "#{list[0...-1].join ', '}, and #{list.last}"
47
+ end # method humanize_list
48
+
49
+ def status_set_warning
50
+ status = result.send(:status)
51
+
52
+ return nil if status.nil?
53
+
54
+ "the status was set to #{status.inspect}".freeze
55
+ end # method status_set_warning
56
+
57
+ def warnings
58
+ [
59
+ errors_not_empty_warning,
60
+ status_set_warning,
61
+ halted_warning
62
+ ].compact
63
+ end # method warnings
64
+ end # class
65
+ end # module
@@ -8,13 +8,13 @@ module Cuprum
8
8
  # Major version.
9
9
  MAJOR = 0
10
10
  # Minor version.
11
- MINOR = 6
11
+ MINOR = 7
12
12
  # Patch version.
13
13
  PATCH = 0
14
14
  # Prerelease version.
15
- PRERELEASE = nil
15
+ PRERELEASE = :rc
16
16
  # Build metadata.
17
- BUILD = nil
17
+ BUILD = 0
18
18
 
19
19
  class << self
20
20
  # Generates the gem version string from the Version constants.
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.6.0
4
+ version: 0.7.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: 2017-11-30 00:00:00.000000000 Z
11
+ date: 2018-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -94,7 +94,6 @@ files:
94
94
  - LICENSE
95
95
  - README.md
96
96
  - lib/cuprum.rb
97
- - lib/cuprum/basic_command.rb
98
97
  - lib/cuprum/built_in.rb
99
98
  - lib/cuprum/built_in/identity_command.rb
100
99
  - lib/cuprum/built_in/identity_operation.rb
@@ -104,9 +103,12 @@ files:
104
103
  - lib/cuprum/command.rb
105
104
  - lib/cuprum/not_implemented_error.rb
106
105
  - lib/cuprum/operation.rb
106
+ - lib/cuprum/processing.rb
107
107
  - lib/cuprum/result.rb
108
+ - lib/cuprum/result_helpers.rb
108
109
  - lib/cuprum/utils.rb
109
110
  - lib/cuprum/utils/instance_spy.rb
111
+ - lib/cuprum/utils/result_not_empty_warning.rb
110
112
  - lib/cuprum/version.rb
111
113
  homepage: http://sleepingkingstudios.com
112
114
  licenses:
@@ -123,9 +125,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
125
  version: '0'
124
126
  required_rubygems_version: !ruby/object:Gem::Requirement
125
127
  requirements:
126
- - - ">="
128
+ - - ">"
127
129
  - !ruby/object:Gem::Version
128
- version: '0'
130
+ version: 1.3.1
129
131
  requirements: []
130
132
  rubyforge_project:
131
133
  rubygems_version: 2.6.13
@@ -1,212 +0,0 @@
1
- require 'cuprum/not_implemented_error'
2
-
3
- module Cuprum
4
- # Functional object that encapsulates a business logic operation with a
5
- # standardized interface and returns a result object.
6
- class BasicCommand
7
- # Returns a new instance of Cuprum::BasicCommand.
8
- #
9
- # @yield [*arguments, **keywords, &block] If a block is given, the
10
- # #call method will wrap the block and set the result #value to the return
11
- # value of the block. This overrides the implementation in #process, if
12
- # any.
13
- def initialize &implementation
14
- define_singleton_method :process, &implementation if implementation
15
- end # method initialize
16
-
17
- # @overload call(*arguments, **keywords, &block)
18
- # Executes the logic encoded in the constructor block, or the #process
19
- # method if no block was passed to the constructor, and returns a
20
- # Cuprum::Result object with the return value of the block or #process,
21
- # the success or failure status, and any errors generated.
22
- #
23
- # @param arguments [Array] Arguments to be passed to the implementation.
24
- #
25
- # @param keywords [Hash] Keywords to be passed to the implementation.
26
- #
27
- # @return [Cuprum::Result] The result object for the command.
28
- #
29
- # @yield If a block argument is given, it will be passed to the
30
- # implementation.
31
- #
32
- # @raise [Cuprum::NotImplementedError] Unless a block was passed to the
33
- # constructor or the #process method was overriden by a Command
34
- # subclass.
35
- def call *args, &block
36
- wrap_result { |result| merge_results(result, process(*args, &block)) }
37
- end # method call
38
-
39
- private
40
-
41
- # @!visibility public
42
- #
43
- # Generates an empty errors object. When the function is called, the result
44
- # will have its #errors property initialized to the value returned by
45
- # #build_errors. By default, this is an array. If you want to use a custom
46
- # errors object type, override this method in a subclass.
47
- #
48
- # @return [Array] An empty errors object.
49
- def build_errors
50
- []
51
- end # method build_errors
52
-
53
- def convert_value_to_result value
54
- return nil unless value_is_result?(value)
55
-
56
- if value.respond_to?(:result) && value_is_result?(value.result)
57
- return value.result
58
- end # if
59
-
60
- value
61
- end # method convert_value_to_result
62
-
63
- # @!visibility public
64
- #
65
- # Provides a reference to the current result's errors object. Messages or
66
- # error objects added to this will be included in the #errors method of the
67
- # returned result object.
68
- #
69
- # @return [Array, Object] The errors object.
70
- #
71
- # @see Cuprum::Result#errors.
72
- #
73
- # @note This is a private method, and only available when executing the
74
- # function implementation as defined in the constructor block or the
75
- # #process method.
76
- def errors
77
- @result&.errors
78
- end # method errors
79
-
80
- # @!visibility public
81
- #
82
- # Marks the current result as failed. Calling #failure? on the returned
83
- # result object will evaluate to true, whether or not the result has any
84
- # errors.
85
- #
86
- # @see Cuprum::Result#failure!.
87
- #
88
- # @note This is a private method, and only available when executing the
89
- # function implementation as defined in the constructor block or the
90
- # #process method.
91
- def failure!
92
- @result&.failure!
93
- end # method failure!
94
-
95
- # @!visibility public
96
- #
97
- # Marks the current result as halted.
98
- #
99
- # @see Cuprum::Result#halt!.
100
- #
101
- # @note This is a private method, and only available when executing the
102
- # function implementation as defined in the constructor block or the
103
- # #process method.
104
- def halt!
105
- @result&.halt!
106
- end # method halt!
107
-
108
- # :nocov:
109
- def humanize_list list, empty_value: ''
110
- return empty_value if list.size.zero?
111
-
112
- return list.first.to_s if list.size == 1
113
-
114
- return "#{list.first} and #{list.last}" if list.size == 2
115
-
116
- "#{list[0...-1].join ', '}, and #{list.last}"
117
- end # method humanize_list
118
- # :nocov:
119
-
120
- def merge_results result, other
121
- if value_is_result?(other)
122
- Cuprum.warn(result_not_empty_warning) unless result.empty?
123
-
124
- convert_value_to_result(other)
125
- else
126
- result.value = other
127
-
128
- result
129
- end # if-else
130
- end # method merge_results
131
-
132
- # @!visibility public
133
- # @overload process(*arguments, **keywords, &block)
134
- # The implementation of the function, to be executed when the #call method
135
- # is called. Can add errors to or set the status of the result, and the
136
- # value of the result will be set to the value returned by #process. Do
137
- # not call this method directly.
138
- #
139
- # @param arguments [Array] The arguments, if any, passed from #call.
140
- #
141
- # @param keywords [Hash] The keywords, if any, passed from #call.
142
- #
143
- # @yield The block, if any, passed from #call.
144
- #
145
- # @return [Object] the value of the result object to be returned by #call.
146
- #
147
- # @raise [Cuprum::NotImplementedError] Unless a block was passed to the
148
- # constructor or the #process method was overriden by a Command
149
- # subclass.
150
- #
151
- # @note This is a private method.
152
- def process *_args
153
- raise Cuprum::NotImplementedError, nil, caller(1..-1)
154
- end # method process
155
-
156
- def result_not_empty_warning # rubocop:disable Metrics/MethodLength
157
- warnings = []
158
-
159
- unless @result.errors.empty?
160
- warnings << "there were already errors #{@result.errors.inspect}"
161
- end # unless
162
-
163
- status = @result.send(:status)
164
- unless status.nil?
165
- warnings << "the status was set to #{status.inspect}"
166
- end # unless
167
-
168
- if @result.halted?
169
- warnings << 'the function was halted'
170
- end # if
171
-
172
- message = '#process returned a result, but '
173
- message <<
174
- humanize_list(warnings, :empty_value => 'the result was not empty')
175
-
176
- message
177
- end # method result_not_empty_warning
178
-
179
- # @!visibility public
180
- #
181
- # Marks the current result as passing. Calling #success? on the returned
182
- # result object will evaluate to true, whether or not the result has any
183
- # errors.
184
- #
185
- # @see Cuprum::Result#success!.
186
- #
187
- # @note This is a private method, and only available when executing the
188
- # function implementation as defined in the constructor block or the
189
- # #process method.
190
- def success!
191
- @result&.success!
192
- end # method success!
193
-
194
- def value_is_result? value
195
- value.respond_to?(:value) && value.respond_to?(:success?)
196
- end # method value
197
-
198
- def wrap_result
199
- result = Cuprum::Result.new(:errors => build_errors)
200
-
201
- begin
202
- @result = result
203
-
204
- result = yield result
205
- ensure
206
- @result = nil
207
- end # begin-ensure
208
-
209
- result
210
- end # method wrap_result
211
- end # class
212
- end # module