cuprum 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +44 -1494
- data/lib/cuprum/built_in/identity_command.rb +4 -0
- data/lib/cuprum/built_in/identity_operation.rb +4 -4
- data/lib/cuprum/built_in/null_command.rb +5 -1
- data/lib/cuprum/command.rb +27 -16
- data/lib/cuprum/command_factory.rb +4 -4
- data/lib/cuprum/currying/curried_command.rb +1 -1
- data/lib/cuprum/error.rb +42 -0
- data/lib/cuprum/errors/command_not_implemented.rb +2 -3
- data/lib/cuprum/errors/multiple_errors.rb +39 -0
- data/lib/cuprum/errors/operation_not_called.rb +2 -3
- data/lib/cuprum/errors/uncaught_exception.rb +2 -2
- data/lib/cuprum/errors.rb +6 -1
- data/lib/cuprum/exception_handling.rb +4 -2
- data/lib/cuprum/map_command.rb +227 -0
- data/lib/cuprum/matcher.rb +2 -0
- data/lib/cuprum/matcher_list.rb +2 -2
- data/lib/cuprum/matching.rb +3 -1
- data/lib/cuprum/middleware.rb +20 -13
- data/lib/cuprum/operation.rb +8 -10
- data/lib/cuprum/processing.rb +22 -11
- data/lib/cuprum/result_list.rb +187 -0
- data/lib/cuprum/rspec/be_a_result_matcher.rb +6 -6
- data/lib/cuprum/steps.rb +4 -1
- data/lib/cuprum/utils/instance_spy.rb +22 -24
- data/lib/cuprum/version.rb +3 -3
- data/lib/cuprum.rb +3 -2
- metadata +20 -17
    
        data/lib/cuprum/operation.rb
    CHANGED
    
    | @@ -37,8 +37,9 @@ module Cuprum | |
| 37 37 | 
             
              #
         | 
| 38 38 | 
             
              # @see Cuprum::Command
         | 
| 39 39 | 
             
              class Operation < Cuprum::Command
         | 
| 40 | 
            -
                # Module-based implementation of the Operation methods. | 
| 41 | 
            -
                # | 
| 40 | 
            +
                # Module-based implementation of the Operation methods.
         | 
| 41 | 
            +
                #
         | 
| 42 | 
            +
                # Use this to convert an already-defined command into an operation.
         | 
| 42 43 | 
             
                #
         | 
| 43 44 | 
             
                # @example
         | 
| 44 45 | 
             
                #   class CustomOperation < CustomCommand
         | 
| @@ -50,9 +51,7 @@ module Cuprum | |
| 50 51 | 
             
                  attr_reader :result
         | 
| 51 52 |  | 
| 52 53 | 
             
                  # @overload call(*arguments, **keywords, &block)
         | 
| 53 | 
            -
                  #    | 
| 54 | 
            -
                  #   method if no block was passed to the constructor, and returns the
         | 
| 55 | 
            -
                  #   operation object.
         | 
| 54 | 
            +
                  #   Calls the command implementation and stores the result.
         | 
| 56 55 | 
             
                  #
         | 
| 57 56 | 
             
                  #   @param arguments [Array] Arguments to be passed to the implementation.
         | 
| 58 57 | 
             
                  #
         | 
| @@ -63,7 +62,7 @@ module Cuprum | |
| 63 62 | 
             
                  #   @yield If a block argument is given, it will be passed to the
         | 
| 64 63 | 
             
                  #     implementation.
         | 
| 65 64 | 
             
                  #
         | 
| 66 | 
            -
                  # | 
| 65 | 
            +
                  #   @see Cuprum::Command#call
         | 
| 67 66 | 
             
                  def call(*args, **kwargs, &block)
         | 
| 68 67 | 
             
                    reset! if called? # Clear reference to most recent result.
         | 
| 69 68 |  | 
| @@ -116,10 +115,9 @@ module Cuprum | |
| 116 115 | 
             
                    called? ? result.success? : false
         | 
| 117 116 | 
             
                  end
         | 
| 118 117 |  | 
| 119 | 
            -
                  #  | 
| 120 | 
            -
                  #  | 
| 121 | 
            -
                  #
         | 
| 122 | 
            -
                  # @return [Cuprum::Result] the most recent result or failing result.
         | 
| 118 | 
            +
                  # @return [Cuprum::Result] the most recent result if the operation was
         | 
| 119 | 
            +
                  #   previously called; otherwise, returns a failing result with a
         | 
| 120 | 
            +
                  #   Cuprum::Errors::OperationNotCalled error.
         | 
| 123 121 | 
             
                  def to_cuprum_result
         | 
| 124 122 | 
             
                    return result if result
         | 
| 125 123 |  | 
    
        data/lib/cuprum/processing.rb
    CHANGED
    
    | @@ -60,18 +60,23 @@ module Cuprum | |
| 60 60 | 
             
              module Processing
         | 
| 61 61 | 
             
                include Cuprum::ResultHelpers
         | 
| 62 62 |  | 
| 63 | 
            -
                # Returns  | 
| 64 | 
            -
                # | 
| 65 | 
            -
                #  | 
| 63 | 
            +
                # Returns an indication of the number of arguments accepted by #call.
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                # If the method takes a fixed number N of arguments, returns N. If the
         | 
| 66 | 
            +
                # method takes a variable number of arguments, returns -N-1, where N is the
         | 
| 67 | 
            +
                # number of required arguments. Keyword arguments will be considered as a
         | 
| 68 | 
            +
                # single additional argument, that argument being mandatory if any keyword
         | 
| 69 | 
            +
                # argument is mandatory.
         | 
| 66 70 | 
             
                #
         | 
| 67 71 | 
             
                # @return [Integer] The number of arguments.
         | 
| 72 | 
            +
                #
         | 
| 73 | 
            +
                # @see Method#arity.
         | 
| 68 74 | 
             
                def arity
         | 
| 69 75 | 
             
                  method(:process).arity
         | 
| 70 76 | 
             
                end
         | 
| 71 77 |  | 
| 72 78 | 
             
                # @overload call(*arguments, **keywords, &block)
         | 
| 73 | 
            -
                #   Executes the command  | 
| 74 | 
            -
                #   compatible object.
         | 
| 79 | 
            +
                #   Executes the command and returns a Cuprum::Result or compatible object.
         | 
| 75 80 | 
             
                #
         | 
| 76 81 | 
             
                #   Each time #call is invoked, the object performs the following steps:
         | 
| 77 82 | 
             
                #
         | 
| @@ -107,11 +112,16 @@ module Cuprum | |
| 107 112 |  | 
| 108 113 | 
             
                # @!visibility public
         | 
| 109 114 | 
             
                # @overload process(*arguments, **keywords, &block)
         | 
| 110 | 
            -
                #   The implementation of the command | 
| 111 | 
            -
                # | 
| 115 | 
            +
                #   The implementation of the command.
         | 
| 116 | 
            +
                #
         | 
| 117 | 
            +
                #   Whereas the #call method provides the public interface for calling a
         | 
| 118 | 
            +
                #   command, the #process method defines the actual implementation. This
         | 
| 119 | 
            +
                #   method should not be called directly.
         | 
| 120 | 
            +
                #
         | 
| 121 | 
            +
                #   When the command is called via #call, the parameters are passed to
         | 
| 122 | 
            +
                #   #process. If #process returns a result, that result will be returned by
         | 
| 112 123 | 
             
                #   #call; otherwise, the value returned by #process will be wrapped in a
         | 
| 113 | 
            -
                #   successful Cuprum::Result object. | 
| 114 | 
            -
                #   directly.
         | 
| 124 | 
            +
                #   successful Cuprum::Result object.
         | 
| 115 125 | 
             
                #
         | 
| 116 126 | 
             
                #   @param arguments [Array] The arguments, if any, passed from #call.
         | 
| 117 127 | 
             
                #
         | 
| @@ -119,9 +129,10 @@ module Cuprum | |
| 119 129 | 
             
                #
         | 
| 120 130 | 
             
                #   @yield The block, if any, passed from #call.
         | 
| 121 131 | 
             
                #
         | 
| 122 | 
            -
                #   @return [Object]  | 
| 132 | 
            +
                #   @return [Cuprum::Result, Object] a result object, or the value of the
         | 
| 133 | 
            +
                #     result object to be returned by #call.
         | 
| 123 134 | 
             
                #
         | 
| 124 | 
            -
                # | 
| 135 | 
            +
                #   @note This is a private method.
         | 
| 125 136 | 
             
                def process(*_args)
         | 
| 126 137 | 
             
                  error = Cuprum::Errors::CommandNotImplemented.new(command: self)
         | 
| 127 138 |  | 
| @@ -0,0 +1,187 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'forwardable'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'cuprum'
         | 
| 6 | 
            +
            require 'cuprum/errors/multiple_errors'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Cuprum
         | 
| 9 | 
            +
              # Collection object that encapsulates a set of Cuprum results.
         | 
| 10 | 
            +
              #
         | 
| 11 | 
            +
              # Each Cuprum::ResultList wraps an Array of Cuprum::Result objects, and itself
         | 
| 12 | 
            +
              # implements the same methods as a Result: #status, #value, #error, and the
         | 
| 13 | 
            +
              # #success? and #failure? predicates. As such, a Command's #process method can
         | 
| 14 | 
            +
              # return a ResultList instead of a Result. This is useful for commands that
         | 
| 15 | 
            +
              # operate on a collection of items, such as a MapCommand or a controller
         | 
| 16 | 
            +
              # endpoint that performs a bulk operation.
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              # @see Cuprum::Result.
         | 
| 19 | 
            +
              class ResultList
         | 
| 20 | 
            +
                extend  Forwardable
         | 
| 21 | 
            +
                include Enumerable
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                UNDEFINED = Object.new.freeze
         | 
| 24 | 
            +
                private_constant :UNDEFINED
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # @!method each
         | 
| 27 | 
            +
                #   Iterates over the results.
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                #   @overload each()
         | 
| 30 | 
            +
                #     @return [Enumerator] an enumerator over the results.
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                #   @overload each(&block)
         | 
| 33 | 
            +
                #     Yields each result to the block.
         | 
| 34 | 
            +
                #
         | 
| 35 | 
            +
                #     @yieldparam result [Cuprum::Result] the yielded result.
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # @param allow_partial [true, false] If true, allows for some failing
         | 
| 38 | 
            +
                #   results as long as there is at least one passing result. Defaults to
         | 
| 39 | 
            +
                #   false.
         | 
| 40 | 
            +
                # @param error [Cuprum::Error] If given, sets the error for the result list
         | 
| 41 | 
            +
                #   to the specified error object.
         | 
| 42 | 
            +
                # @param results [Array<Cuprum::Result>] The wrapped results.
         | 
| 43 | 
            +
                # @param status [:success, :failure] If given, sets the status of the result
         | 
| 44 | 
            +
                #   list to the specified value.
         | 
| 45 | 
            +
                # @param value [Object] The value of the result. Defaults to the mapped
         | 
| 46 | 
            +
                #   values of the results.
         | 
| 47 | 
            +
                def initialize(
         | 
| 48 | 
            +
                  *results,
         | 
| 49 | 
            +
                  allow_partial: false,
         | 
| 50 | 
            +
                  error: UNDEFINED,
         | 
| 51 | 
            +
                  status: UNDEFINED,
         | 
| 52 | 
            +
                  value: UNDEFINED
         | 
| 53 | 
            +
                )
         | 
| 54 | 
            +
                  @allow_partial = allow_partial
         | 
| 55 | 
            +
                  @results       = normalize_results(results)
         | 
| 56 | 
            +
                  @error         = error  == UNDEFINED ? build_error  : error
         | 
| 57 | 
            +
                  @status        = status == UNDEFINED ? build_status : status
         | 
| 58 | 
            +
                  @value         = value  == UNDEFINED ? values : value
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # @return [Array<Cuprum::Result>] the wrapped results.
         | 
| 62 | 
            +
                attr_reader :results
         | 
| 63 | 
            +
                alias_method :to_a, :results
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                # Returns the error for the result list.
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # If the result list was initialized with an error, returns that error.
         | 
| 68 | 
            +
                #
         | 
| 69 | 
            +
                # If any of the results have errors, aggregates the result errors into a
         | 
| 70 | 
            +
                # Cuprum::MultipleErrors object.
         | 
| 71 | 
            +
                #
         | 
| 72 | 
            +
                # If none of the results have errors, returns nil.
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                # @return [Cuprum::Errors::MultipleErrors, Cuprum::Error, nil] the error for
         | 
| 75 | 
            +
                #   the result list.
         | 
| 76 | 
            +
                attr_reader :error
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # Determines the status of the combined results.
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                # If the result list was initialize with a status, returns that status.
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                # If there are no failing results, i.e. the results array is empty or all of
         | 
| 83 | 
            +
                # the results are passing, returns :success.
         | 
| 84 | 
            +
                #
         | 
| 85 | 
            +
                # If there is at least one failing result, it instead returns :failure.
         | 
| 86 | 
            +
                #
         | 
| 87 | 
            +
                # If the :allow_partial flag is set to true, returns :success if the results
         | 
| 88 | 
            +
                # array is empty or there is at least one passing result. If there is at
         | 
| 89 | 
            +
                # least one failing result and no passing results, it instead returns
         | 
| 90 | 
            +
                # :failure.
         | 
| 91 | 
            +
                #
         | 
| 92 | 
            +
                # @return [:success, :failure] the status of the combined results.
         | 
| 93 | 
            +
                attr_reader :status
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                # @return [Object] The value of the result. Defaults to the mapped values of
         | 
| 96 | 
            +
                #   the results.
         | 
| 97 | 
            +
                attr_reader :value
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                def_delegators :@results, :each
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                # @return [true, false] true if the other object is a ResultList with
         | 
| 102 | 
            +
                #   matching results and options; otherwise false.
         | 
| 103 | 
            +
                def ==(other)
         | 
| 104 | 
            +
                  other.is_a?(ResultList) &&
         | 
| 105 | 
            +
                    results        == other.results &&
         | 
| 106 | 
            +
                    allow_partial? == other.allow_partial?
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                # @return [true, false] if true, allows for some failing results as long as
         | 
| 110 | 
            +
                #   there is at least one passing result. Defaults to false.
         | 
| 111 | 
            +
                #
         | 
| 112 | 
            +
                # @see #status
         | 
| 113 | 
            +
                # @see #to_cuprum_result
         | 
| 114 | 
            +
                def allow_partial?
         | 
| 115 | 
            +
                  @allow_partial
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                # @return [Array<Cuprum::Error, nil>] the error, if any, for each result.
         | 
| 119 | 
            +
                def errors
         | 
| 120 | 
            +
                  @errors ||= results.map(&:error)
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                # @return [Boolean] true if the result status is :failure, otherwise false.
         | 
| 124 | 
            +
                def failure?
         | 
| 125 | 
            +
                  status == :failure
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                # @return [Array<Symbol>] the status for each result.
         | 
| 129 | 
            +
                def statuses
         | 
| 130 | 
            +
                  @statuses ||= results.map(&:status)
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                # @return [Boolean] true if the result status is :success, otherwise false.
         | 
| 134 | 
            +
                def success?
         | 
| 135 | 
            +
                  status == :success
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                # Converts the result list to a Cuprum::Result.
         | 
| 139 | 
            +
                #
         | 
| 140 | 
            +
                # @return [Cuprum::Result] the converted result.
         | 
| 141 | 
            +
                #
         | 
| 142 | 
            +
                # @see #error
         | 
| 143 | 
            +
                # @see #status
         | 
| 144 | 
            +
                # @see #value
         | 
| 145 | 
            +
                def to_cuprum_result
         | 
| 146 | 
            +
                  Cuprum::Result.new(error: error, status: status, value: value)
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                # @return [Array<Object, nil>] the value, if any, for each result.
         | 
| 150 | 
            +
                def values
         | 
| 151 | 
            +
                  @values ||= results.map(&:value)
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                private
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                def build_error
         | 
| 157 | 
            +
                  return if errors.compact.empty?
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  Cuprum::Errors::MultipleErrors.new(errors: errors)
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                def build_status
         | 
| 163 | 
            +
                  passing_result? ? :success : :failure
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                def normalize_results(results)
         | 
| 167 | 
            +
                  results.map do |obj|
         | 
| 168 | 
            +
                    next obj if obj.is_a?(Cuprum::ResultList)
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                    next obj.to_cuprum_result if obj.respond_to?(:to_cuprum_result)
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                    raise ArgumentError,
         | 
| 173 | 
            +
                      "invalid result: #{obj.inspect} does not respond to #to_cuprum_result"
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                def passing_result?
         | 
| 178 | 
            +
                  return true if results.empty?
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  if allow_partial?
         | 
| 181 | 
            +
                    results.any?(&:success?)
         | 
| 182 | 
            +
                  else
         | 
| 183 | 
            +
                    results.all?(&:success?)
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
              end
         | 
| 187 | 
            +
            end
         | 
| @@ -142,7 +142,7 @@ module Cuprum::RSpec | |
| 142 142 | 
             
                  return '' if error_matches?
         | 
| 143 143 |  | 
| 144 144 | 
             
                  "\n   expected error: #{inspect_expected(expected_error)}" \
         | 
| 145 | 
            -
             | 
| 145 | 
            +
                    "\n     actual error: #{result.error.inspect}"
         | 
| 146 146 | 
             
                end
         | 
| 147 147 |  | 
| 148 148 | 
             
                def error_matches?
         | 
| @@ -179,7 +179,7 @@ module Cuprum::RSpec | |
| 179 179 |  | 
| 180 180 | 
             
                def negated_matcher_warning
         | 
| 181 181 | 
             
                  "Using `expect().not_to be_a_result#{properties_warning}` risks false" \
         | 
| 182 | 
            -
             | 
| 182 | 
            +
                    ' positives, since any other result will match.'
         | 
| 183 183 | 
             
                end
         | 
| 184 184 |  | 
| 185 185 | 
             
                # rubocop:disable Metrics/AbcSize
         | 
| @@ -219,7 +219,7 @@ module Cuprum::RSpec | |
| 219 219 | 
             
                  ary << 'error'  unless error_matches?
         | 
| 220 220 |  | 
| 221 221 | 
             
                  ", but the #{tools.array_tools.humanize_list(ary)}" \
         | 
| 222 | 
            -
             | 
| 222 | 
            +
                    " #{tools.integer_tools.pluralize(ary.size, 'does', 'do')} not match:"
         | 
| 223 223 | 
             
                end
         | 
| 224 224 |  | 
| 225 225 | 
             
                def properties_warning
         | 
| @@ -234,7 +234,7 @@ module Cuprum::RSpec | |
| 234 234 |  | 
| 235 235 | 
             
                  return message if ary.size == 1
         | 
| 236 236 |  | 
| 237 | 
            -
                  message + ary[1 | 
| 237 | 
            +
                  message + ary[1..].map { |str| ".and_#{str}()" }.join
         | 
| 238 238 | 
             
                end
         | 
| 239 239 |  | 
| 240 240 | 
             
                def result
         | 
| @@ -251,7 +251,7 @@ module Cuprum::RSpec | |
| 251 251 | 
             
                  return '' if status_matches?
         | 
| 252 252 |  | 
| 253 253 | 
             
                  "\n  expected status: #{expected_status.inspect}" \
         | 
| 254 | 
            -
             | 
| 254 | 
            +
                    "\n    actual status: #{result.status.inspect}"
         | 
| 255 255 | 
             
                end
         | 
| 256 256 |  | 
| 257 257 | 
             
                def status_matches?
         | 
| @@ -270,7 +270,7 @@ module Cuprum::RSpec | |
| 270 270 | 
             
                  return '' if value_matches?
         | 
| 271 271 |  | 
| 272 272 | 
             
                  "\n   expected value: #{inspect_expected(expected_value)}" \
         | 
| 273 | 
            -
             | 
| 273 | 
            +
                    "\n     actual value: #{result.value.inspect}"
         | 
| 274 274 | 
             
                end
         | 
| 275 275 |  | 
| 276 276 | 
             
                def value_matches?
         | 
    
        data/lib/cuprum/steps.rb
    CHANGED
    
    | @@ -128,7 +128,8 @@ module Cuprum | |
| 128 128 | 
             
                #
         | 
| 129 129 | 
             
                # @yield Called with no parameters.
         | 
| 130 130 | 
             
                #
         | 
| 131 | 
            -
                # @yieldreturn  | 
| 131 | 
            +
                # @yieldreturn [Cuprum::Result, Object] a Cuprum result, or an object to be
         | 
| 132 | 
            +
                #   wrapped in a result.
         | 
| 132 133 | 
             
                #
         | 
| 133 134 | 
             
                # @return [Cuprum::Result] the result or object returned by the block,
         | 
| 134 135 | 
             
                #   wrapped in a Cuprum result.
         | 
| @@ -163,6 +164,8 @@ module Cuprum | |
| 163 164 | 
             
                #   result.class    #=> Cuprum::Result
         | 
| 164 165 | 
             
                #   result.success? #=> false
         | 
| 165 166 | 
             
                #   result.error    #=> 'second step'
         | 
| 167 | 
            +
                #
         | 
| 168 | 
            +
                # @raise [ArgumentError] if a block is not given.
         | 
| 166 169 | 
             
                def steps(&block)
         | 
| 167 170 | 
             
                  raise ArgumentError, 'no block given' unless block_given?
         | 
| 168 171 |  | 
| @@ -3,54 +3,52 @@ | |
| 3 3 | 
             
            require 'cuprum/utils'
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Cuprum::Utils
         | 
| 6 | 
            -
              #  | 
| 7 | 
            -
              # | 
| 8 | 
            -
              #  | 
| 9 | 
            -
              #  | 
| 10 | 
            -
              # call a command instance.
         | 
| 6 | 
            +
              # Instruments calls to the #call method of any instance of a command class.
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # This can be used to unobtrusively test the functionality of code that calls
         | 
| 9 | 
            +
              # a command without providing a reference to the command instance, such
         | 
| 10 | 
            +
              # methods that create and call a command instance.
         | 
| 11 11 | 
             
              #
         | 
| 12 12 | 
             
              # @example Observing calls to instances of a command.
         | 
| 13 13 | 
             
              #   spy = Cuprum::Utils::InstanceSpy.spy_on(CustomCommand)
         | 
| 14 14 | 
             
              #
         | 
| 15 | 
            -
              #    | 
| 15 | 
            +
              #   allow(spy).to receive(:call)
         | 
| 16 16 | 
             
              #
         | 
| 17 17 | 
             
              #   CustomCommand.new.call(1, 2, 3, :four => '4')
         | 
| 18 18 | 
             
              #
         | 
| 19 | 
            -
              #  | 
| 20 | 
            -
              #   spy = Cuprum::Utils::InstanceSpy.spy_on(ChainedCommand)
         | 
| 21 | 
            -
              #
         | 
| 22 | 
            -
              #   expect(spy).to receive(:call)
         | 
| 23 | 
            -
              #
         | 
| 24 | 
            -
              #   Cuprum::Command.new {}.
         | 
| 25 | 
            -
              #     chain { |result| ChainedCommand.new.call(result) }.
         | 
| 26 | 
            -
              #     call
         | 
| 19 | 
            +
              #   expect(spy).to have_received(:call).with(1, 2, 3, :four => '4')
         | 
| 27 20 | 
             
              #
         | 
| 28 21 | 
             
              # @example Block syntax
         | 
| 29 22 | 
             
              #   Cuprum::Utils::InstanceSpy.spy_on(CustomCommand) do |spy|
         | 
| 30 | 
            -
              #      | 
| 23 | 
            +
              #     allow(spy).to receive(:call)
         | 
| 31 24 | 
             
              #
         | 
| 32 25 | 
             
              #     CustomCommand.new.call
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              #     expect(spy).to have_received(:call)
         | 
| 33 28 | 
             
              #   end
         | 
| 34 29 | 
             
              module InstanceSpy
         | 
| 35 | 
            -
                # Minimal class  | 
| 36 | 
            -
                # instances of an instrumented command class.
         | 
| 30 | 
            +
                # Minimal class double implementing the #call method.
         | 
| 37 31 | 
             
                class Spy
         | 
| 38 | 
            -
                  # Empty method that accepts any  | 
| 39 | 
            -
                  def call(*_args, &block); end
         | 
| 32 | 
            +
                  # Empty method that accepts any parameters and an optional block.
         | 
| 33 | 
            +
                  def call(*_args, **_kwargs, &block); end
         | 
| 40 34 | 
             
                end
         | 
| 41 35 |  | 
| 42 36 | 
             
                class << self
         | 
| 43 | 
            -
                  # Retires all spies. | 
| 44 | 
            -
                  # | 
| 37 | 
            +
                  # Retires all spies.
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # Subsequent calls to the #call method on command instances will not be
         | 
| 40 | 
            +
                  # mirrored to existing spy objects.
         | 
| 45 41 | 
             
                  def clear_spies
         | 
| 46 42 | 
             
                    Thread.current[:cuprum_instance_spies] = nil
         | 
| 47 43 |  | 
| 48 44 | 
             
                    nil
         | 
| 49 45 | 
             
                  end
         | 
| 50 46 |  | 
| 51 | 
            -
                  # Finds or creates a spy object for the given module or class. | 
| 52 | 
            -
                  # | 
| 53 | 
            -
                  #  | 
| 47 | 
            +
                  # Finds or creates a spy object for the given module or class.
         | 
| 48 | 
            +
                  #
         | 
| 49 | 
            +
                  # Each time that the #call method is called for an object of the given
         | 
| 50 | 
            +
                  # type, the spy's #call method will be invoked with the same arguments and
         | 
| 51 | 
            +
                  # block.
         | 
| 54 52 | 
             
                  #
         | 
| 55 53 | 
             
                  # @param command_class [Class, Module] The type of command to spy on.
         | 
| 56 54 | 
             
                  #   Must be either a Module, or a Class that extends Cuprum::Command.
         | 
    
        data/lib/cuprum/version.rb
    CHANGED
    
    | @@ -10,13 +10,13 @@ module Cuprum | |
| 10 10 | 
             
                # Major version.
         | 
| 11 11 | 
             
                MAJOR = 1
         | 
| 12 12 | 
             
                # Minor version.
         | 
| 13 | 
            -
                MINOR =  | 
| 13 | 
            +
                MINOR = 1
         | 
| 14 14 | 
             
                # Patch version.
         | 
| 15 15 | 
             
                PATCH = 0
         | 
| 16 16 | 
             
                # Prerelease version.
         | 
| 17 | 
            -
                PRERELEASE =  | 
| 17 | 
            +
                PRERELEASE = :rc
         | 
| 18 18 | 
             
                # Build metadata.
         | 
| 19 | 
            -
                BUILD =  | 
| 19 | 
            +
                BUILD = 0
         | 
| 20 20 |  | 
| 21 21 | 
             
                class << self
         | 
| 22 22 | 
             
                  # Generates the gem version string from the Version constants.
         | 
    
        data/lib/cuprum.rb
    CHANGED
    
    | @@ -1,14 +1,15 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            #  | 
| 4 | 
            -
            # citizen of your application.
         | 
| 3 | 
            +
            # Toolkit for implementing business logic as function objects.
         | 
| 5 4 | 
             
            module Cuprum
         | 
| 6 5 | 
             
              autoload :Command,    'cuprum/command'
         | 
| 7 6 | 
             
              autoload :Error,      'cuprum/error'
         | 
| 7 | 
            +
              autoload :MapCommand, 'cuprum/map_command'
         | 
| 8 8 | 
             
              autoload :Matcher,    'cuprum/matcher'
         | 
| 9 9 | 
             
              autoload :Middleware, 'cuprum/middleware'
         | 
| 10 10 | 
             
              autoload :Operation,  'cuprum/operation'
         | 
| 11 11 | 
             
              autoload :Result,     'cuprum/result'
         | 
| 12 | 
            +
              autoload :ResultList, 'cuprum/result_list'
         | 
| 12 13 | 
             
              autoload :Steps,      'cuprum/steps'
         | 
| 13 14 |  | 
| 14 15 | 
             
              class << self
         | 
    
        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: 1.0.0
         | 
| 4 | 
            +
              version: 1.1.0.rc.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Rob "Merlin" Smith
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2023-02-07 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: sleeping_king_studios-tools
         | 
| @@ -44,56 +44,56 @@ dependencies: | |
| 44 44 | 
             
                requirements:
         | 
| 45 45 | 
             
                - - "~>"
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: '2. | 
| 47 | 
            +
                    version: '2.7'
         | 
| 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. | 
| 54 | 
            +
                    version: '2.7'
         | 
| 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: 1. | 
| 61 | 
            +
                    version: '1.31'
         | 
| 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: 1. | 
| 68 | 
            +
                    version: '1.31'
         | 
| 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: '2. | 
| 75 | 
            +
                    version: '2.11'
         | 
| 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: '2. | 
| 82 | 
            +
                    version: '2.11'
         | 
| 83 83 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 84 84 | 
             
              name: simplecov
         | 
| 85 85 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 86 | 
             
                requirements:
         | 
| 87 87 | 
             
                - - "~>"
         | 
| 88 88 | 
             
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            -
                    version: '0. | 
| 89 | 
            +
                    version: '0.21'
         | 
| 90 90 | 
             
              type: :development
         | 
| 91 91 | 
             
              prerelease: false
         | 
| 92 92 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 93 | 
             
                requirements:
         | 
| 94 94 | 
             
                - - "~>"
         | 
| 95 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            -
                    version: '0. | 
| 96 | 
            +
                    version: '0.21'
         | 
| 97 97 | 
             
            description: |-
         | 
| 98 98 | 
             
              An opinionated implementation of the Command pattern for Ruby applications.
         | 
| 99 99 | 
             
              Cuprum wraps your business logic in a consistent, object-oriented interface
         | 
| @@ -123,9 +123,11 @@ files: | |
| 123 123 | 
             
            - lib/cuprum/error.rb
         | 
| 124 124 | 
             
            - lib/cuprum/errors.rb
         | 
| 125 125 | 
             
            - lib/cuprum/errors/command_not_implemented.rb
         | 
| 126 | 
            +
            - lib/cuprum/errors/multiple_errors.rb
         | 
| 126 127 | 
             
            - lib/cuprum/errors/operation_not_called.rb
         | 
| 127 128 | 
             
            - lib/cuprum/errors/uncaught_exception.rb
         | 
| 128 129 | 
             
            - lib/cuprum/exception_handling.rb
         | 
| 130 | 
            +
            - lib/cuprum/map_command.rb
         | 
| 129 131 | 
             
            - lib/cuprum/matcher.rb
         | 
| 130 132 | 
             
            - lib/cuprum/matcher_list.rb
         | 
| 131 133 | 
             
            - lib/cuprum/matching.rb
         | 
| @@ -135,6 +137,7 @@ files: | |
| 135 137 | 
             
            - lib/cuprum/processing.rb
         | 
| 136 138 | 
             
            - lib/cuprum/result.rb
         | 
| 137 139 | 
             
            - lib/cuprum/result_helpers.rb
         | 
| 140 | 
            +
            - lib/cuprum/result_list.rb
         | 
| 138 141 | 
             
            - lib/cuprum/rspec.rb
         | 
| 139 142 | 
             
            - lib/cuprum/rspec/be_a_result.rb
         | 
| 140 143 | 
             
            - lib/cuprum/rspec/be_a_result_matcher.rb
         | 
| @@ -150,7 +153,7 @@ metadata: | |
| 150 153 | 
             
              bug_tracker_uri: https://github.com/sleepingkingstudios/cuprum/issues
         | 
| 151 154 | 
             
              source_code_uri: https://github.com/sleepingkingstudios/cuprum
         | 
| 152 155 | 
             
              rubygems_mfa_required: 'true'
         | 
| 153 | 
            -
            post_install_message: | 
| 156 | 
            +
            post_install_message:
         | 
| 154 157 | 
             
            rdoc_options: []
         | 
| 155 158 | 
             
            require_paths:
         | 
| 156 159 | 
             
            - lib
         | 
| @@ -158,15 +161,15 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 158 161 | 
             
              requirements:
         | 
| 159 162 | 
             
              - - ">="
         | 
| 160 163 | 
             
                - !ruby/object:Gem::Version
         | 
| 161 | 
            -
                  version: 2. | 
| 164 | 
            +
                  version: 2.6.0
         | 
| 162 165 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 163 166 | 
             
              requirements:
         | 
| 164 | 
            -
              - - " | 
| 167 | 
            +
              - - ">"
         | 
| 165 168 | 
             
                - !ruby/object:Gem::Version
         | 
| 166 | 
            -
                  version:  | 
| 169 | 
            +
                  version: 1.3.1
         | 
| 167 170 | 
             
            requirements: []
         | 
| 168 | 
            -
            rubygems_version: 3.1 | 
| 169 | 
            -
            signing_key: | 
| 171 | 
            +
            rubygems_version: 3.4.1
         | 
| 172 | 
            +
            signing_key:
         | 
| 170 173 | 
             
            specification_version: 4
         | 
| 171 174 | 
             
            summary: An opinionated implementation of the Command pattern.
         | 
| 172 175 | 
             
            test_files: []
         |