mock_proxy 0.2.3 → 0.3.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/lib/mock_proxy.rb +63 -34
- data/lib/mock_proxy/version.rb +1 -1
- metadata +1 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4be99a98663982f26b85d5b18b0f4b8aeb60a889
         | 
| 4 | 
            +
              data.tar.gz: 56eabef1a63825f91c4375960677ed0dc3a0c37c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e355f02c7587ab7b2e194db9cb3d170e5baf970bdc620a86501902344440c75d3aa1c0fbd2eac1eacf9074b9fcca90037bf2cb78b2c1ba2f5f1157bcd018d1c6
         | 
| 7 | 
            +
              data.tar.gz: 38e6f423b030d606c29e3fc1e524027223032bfd3bb2dff2196a2a9ff33b79e3c8d978b758c37e697bf2e0b8cf6bff682ee9ff0e2b353fb42e58656ded28c1b7
         | 
    
        data/lib/mock_proxy.rb
    CHANGED
    
    | @@ -9,15 +9,15 @@ require 'active_support/core_ext' | |
| 9 9 | 
             
            # That would have be 5-6 lines of stubbing. If this sounds like stub_chain, you're on the right track. It was removed in
         | 
| 10 10 | 
             
            # RSpec 3 (or 2?). It's similar to that but it does things differently
         | 
| 11 11 | 
             
            # First, it doesn't require you to use it in a stub
         | 
| 12 | 
            -
            # Second, it's use of  | 
| 12 | 
            +
            # Second, it's use of callbacks means you can define anything, a stub or a mock (expectation) or a spy or whatever you want
         | 
| 13 13 | 
             
            #
         | 
| 14 14 | 
             
            # To use MockProxy, initialize it with a hash. Each key is a method call. Each call either returns a new proxy or calls
         | 
| 15 | 
            -
            # the  | 
| 16 | 
            -
            # a new proxy with the value as the hash. MockProxy will warn if you don't use hashes or  | 
| 15 | 
            +
            # the callback. If the value is a callback, it calls it immediately with the args and block. If the value is a hash, it returns
         | 
| 16 | 
            +
            # a new proxy with the value as the hash. MockProxy will warn if you don't use hashes or callbacks and will also warn if
         | 
| 17 17 | 
             
            # you did not define all the method calls (it won't automatically return itself for methods not defined in the hash)
         | 
| 18 18 | 
             
            #
         | 
| 19 19 | 
             
            # Example use:
         | 
| 20 | 
            -
            #   let(:model_proxy) { MockProxy.new(receive_email:  | 
| 20 | 
            +
            #   let(:model_proxy) { MockProxy.new(receive_email: callback {}, generate_email: { validate!: { send: callback { |to| email } } }) }
         | 
| 21 21 | 
             
            #   before { allow(Model).to receive(:new).and_return model_proxy }
         | 
| 22 22 | 
             
            #   # ...
         | 
| 23 23 | 
             
            #   describe 'Model' do
         | 
| @@ -34,13 +34,13 @@ require 'active_support/core_ext' | |
| 34 34 | 
             
            #
         | 
| 35 35 | 
             
            # Example:
         | 
| 36 36 | 
             
            #   let(:model_proxy) do
         | 
| 37 | 
            -
            #     callback =  | 
| 38 | 
            -
            #       MockProxy.merge(generator_proxy, decorate:  | 
| 37 | 
            +
            #     callback = callback do |type|
         | 
| 38 | 
            +
            #       MockProxy.merge(generator_proxy, decorate: callback { |*args| method_call(type, *args) })
         | 
| 39 39 | 
             
            #       generator_proxy
         | 
| 40 40 | 
             
            #     end
         | 
| 41 41 | 
             
            #     MockProxy.new(generate_email: callback)
         | 
| 42 42 | 
             
            #   end
         | 
| 43 | 
            -
            #   let(:generator_proxy) { MockProxy.new(validate!: { send:  | 
| 43 | 
            +
            #   let(:generator_proxy) { MockProxy.new(validate!: { send: callback { |to| email } }) }
         | 
| 44 44 | 
             
            #
         | 
| 45 45 | 
             
            #
         | 
| 46 46 | 
             
            # @author Geoff Lee
         | 
| @@ -51,7 +51,7 @@ class MockProxy | |
| 51 51 | 
             
              #
         | 
| 52 52 | 
             
              # NOTE: We freeze the hash so you cannot modify it
         | 
| 53 53 | 
             
              #
         | 
| 54 | 
            -
              # Use case: Retrieve  | 
| 54 | 
            +
              # Use case: Retrieve callback to mock
         | 
| 55 55 | 
             
              #
         | 
| 56 56 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 57 57 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| @@ -79,11 +79,11 @@ class MockProxy | |
| 79 79 | 
             
                proxy
         | 
| 80 80 | 
             
              end
         | 
| 81 81 |  | 
| 82 | 
            -
              # Replaces the  | 
| 82 | 
            +
              # Replaces the callback at the specified key path, but only if there was one there before.
         | 
| 83 83 | 
             
              # Without creating new paths comes validation, including checking that this replaces an
         | 
| 84 | 
            -
              # existing  | 
| 84 | 
            +
              # existing callback, sort of like mkdir (without the -p option)
         | 
| 85 85 | 
             
              #
         | 
| 86 | 
            -
              # Use case: Replace existing stub with a new  | 
| 86 | 
            +
              # Use case: Replace existing stub with a new callback without creating new method chains
         | 
| 87 87 | 
             
              #
         | 
| 88 88 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 89 89 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| @@ -94,7 +94,7 @@ class MockProxy | |
| 94 94 | 
             
                proxy
         | 
| 95 95 | 
             
              end
         | 
| 96 96 |  | 
| 97 | 
            -
              # Sets the  | 
| 97 | 
            +
              # Sets the callback at the specified key path, regardless if there was a callback there before.
         | 
| 98 98 | 
             
              # No validation comes with automatic path creation, meaning the key path will be defined
         | 
| 99 99 | 
             
              # it it hasn't already, sort of like mkdir -p
         | 
| 100 100 | 
             
              #
         | 
| @@ -124,7 +124,7 @@ class MockProxy | |
| 124 124 | 
             
                # Wrap existing callback, calling the provided block before it
         | 
| 125 125 | 
             
                # Multiple calls to .observe will create a pyramid of callbacks, calling the observers before
         | 
| 126 126 | 
             
                # eventually calling the existing callback
         | 
| 127 | 
            -
                new_callback =  | 
| 127 | 
            +
                new_callback = callback do |*args|
         | 
| 128 128 | 
             
                  block.call(*args)
         | 
| 129 129 | 
             
                  callback.call(*args)
         | 
| 130 130 | 
             
                end
         | 
| @@ -134,7 +134,7 @@ class MockProxy | |
| 134 134 |  | 
| 135 135 | 
             
              # Wraps the existing callback with your block
         | 
| 136 136 | 
             
              #
         | 
| 137 | 
            -
              # Use case: Get full control of the existing  | 
| 137 | 
            +
              # Use case: Get full control of the existing callback while running custom code
         | 
| 138 138 | 
             
              #
         | 
| 139 139 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 140 140 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| @@ -147,7 +147,7 @@ class MockProxy | |
| 147 147 | 
             
                # Wrap existing callback, calling the provided block before it
         | 
| 148 148 | 
             
                # Multiple calls to .observe will create a pyramid of callbacks, calling the observers before
         | 
| 149 149 | 
             
                # eventually calling the existing callback
         | 
| 150 | 
            -
                new_callback =  | 
| 150 | 
            +
                new_callback = callback do |*args|
         | 
| 151 151 | 
             
                  block.call(*args, &callback)
         | 
| 152 152 | 
             
                end
         | 
| 153 153 | 
             
                set_callback(proxy, key_path, new_callback)
         | 
| @@ -158,8 +158,8 @@ class MockProxy | |
| 158 158 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 159 159 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| 160 160 | 
             
              #        dot delimited key path or an array of method names as strings or symbols
         | 
| 161 | 
            -
              # @return [ | 
| 162 | 
            -
              # @raise [ArgumentError] if  | 
| 161 | 
            +
              # @return [AnyObject, !Hash] if callback found at key path
         | 
| 162 | 
            +
              # @raise [ArgumentError] if callback not found or hash found at key path
         | 
| 163 163 | 
             
              def self.get_callback(proxy, key_path)
         | 
| 164 164 | 
             
                key_paths = key_path.is_a?(Array) ? key_path.map(&:to_s) : key_path.split('.')
         | 
| 165 165 | 
             
                existing_callback_hash = proxy.instance_variable_get('@callback_hash')
         | 
| @@ -177,12 +177,12 @@ class MockProxy | |
| 177 177 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 178 178 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| 179 179 | 
             
              #        dot delimited key path or an array of method names as strings or symbols
         | 
| 180 | 
            -
              # @return [ | 
| 181 | 
            -
              # @raise [ArgumentError] if  | 
| 180 | 
            +
              # @return [AnyObject, !Hash] if callback found at key path
         | 
| 181 | 
            +
              # @raise [ArgumentError] if callback not found or hash found at key path
         | 
| 182 182 | 
             
              def self.get_and_validate_callback(proxy, key_path)
         | 
| 183 183 | 
             
                callback = get_callback(proxy, key_path)
         | 
| 184 | 
            -
                return callback if  | 
| 185 | 
            -
                fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no  | 
| 184 | 
            +
                return callback if valid_callback?(callback)
         | 
| 185 | 
            +
                fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no callback at exact key path). If you want to shorten the callback tree, use MockProxy.set_at. The callback tree looks like this: #{proxy.instance_variable_get('@callback_hash')}"
         | 
| 186 186 | 
             
              end
         | 
| 187 187 | 
             
              private_class_method :get_and_validate_callback
         | 
| 188 188 |  | 
| @@ -190,15 +190,15 @@ class MockProxy | |
| 190 190 | 
             
              # @param [MockProxy] proxy existing proxy
         | 
| 191 191 | 
             
              # @param [String, Symbol, #to_s, Array<String, Symbol, #to_s>] key_path the chain of methods or key path. Can be a
         | 
| 192 192 | 
             
              #        dot delimited key path or an array of method names as strings or symbols
         | 
| 193 | 
            -
              # @param [ | 
| 193 | 
            +
              # @param [AnyObject, !Hash] callback the new callback to replace the existing callback
         | 
| 194 194 | 
             
              # @param [Bool] validate true will throw error if nil at any part of key path, false to
         | 
| 195 195 | 
             
              #        create key path if missing (mkdir vs mkdir -p) (Defaults: true)
         | 
| 196 | 
            -
              # @return [MockProxy] if  | 
| 197 | 
            -
              # @raise [ArgumentError] if  | 
| 198 | 
            -
              def self.set_callback(proxy, key_path,  | 
| 199 | 
            -
                fail ArgumentError, ' | 
| 200 | 
            -
                fail ArgumentError, ' | 
| 201 | 
            -
                # Validate by checking if  | 
| 196 | 
            +
              # @return [MockProxy] if callback existed at key path
         | 
| 197 | 
            +
              # @raise [ArgumentError] if callback not found or hash found at key path
         | 
| 198 | 
            +
              def self.set_callback(proxy, key_path, callback, validate = true)
         | 
| 199 | 
            +
                fail ArgumentError, 'callback must be provided' unless callback
         | 
| 200 | 
            +
                fail ArgumentError, 'callback must have a non-hash value' unless valid_callback?(callback)
         | 
| 201 | 
            +
                # Validate by checking if callback exists at key path
         | 
| 202 202 | 
             
                get_and_validate_callback(proxy, key_path) if validate
         | 
| 203 203 | 
             
                # Set callback at key path, validating if set
         | 
| 204 204 | 
             
                key_paths = key_path.is_a?(Array) ? key_path.map(&:to_s) : key_path.to_s.split('.')
         | 
| @@ -208,11 +208,11 @@ class MockProxy | |
| 208 208 | 
             
                  # Last key
         | 
| 209 209 | 
             
                  if key_paths.last == key
         | 
| 210 210 | 
             
                    # Type check value, if validate
         | 
| 211 | 
            -
                    if validate && !callback_hash[key] | 
| 212 | 
            -
                      fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no  | 
| 211 | 
            +
                    if validate && !valid_callback?(callback_hash[key])
         | 
| 212 | 
            +
                      fail ArgumentError, "The existing callback tree contains the full key path you provided but continues going (i.e. no callback at exact key path). If you want to shorten the callback tree, use MockProxy.set_at. The callback tree looks like this: #{copied_callback_hash}"
         | 
| 213 213 | 
             
                    else
         | 
| 214 | 
            -
                      # Assign new  | 
| 215 | 
            -
                      callback_hash[key] =  | 
| 214 | 
            +
                      # Assign new callback if pass validations
         | 
| 215 | 
            +
                      callback_hash[key] = callback
         | 
| 216 216 | 
             
                    end
         | 
| 217 217 | 
             
                  else
         | 
| 218 218 | 
             
                    # In-between keys
         | 
| @@ -230,18 +230,47 @@ class MockProxy | |
| 230 230 | 
             
              end
         | 
| 231 231 | 
             
              private_class_method :set_callback
         | 
| 232 232 |  | 
| 233 | 
            +
              # @private
         | 
| 234 | 
            +
              # Supporting not just callbacks but other values for callbacks. To make the code easier to
         | 
| 235 | 
            +
              # read and more reliable, hashes are not a supported callback value. To return one, use
         | 
| 236 | 
            +
              # a callback like you would normally
         | 
| 237 | 
            +
              #
         | 
| 238 | 
            +
              # @param [AnyObject, !Hash] callback
         | 
| 239 | 
            +
              # @return [Boolean] true if callback is valid, false if not
         | 
| 240 | 
            +
              def self.valid_callback?(callback)
         | 
| 241 | 
            +
                callback && !callback.is_a?(Hash)
         | 
| 242 | 
            +
              end
         | 
| 243 | 
            +
              private_class_method :valid_callback?
         | 
| 244 | 
            +
             | 
| 245 | 
            +
              # @private
         | 
| 246 | 
            +
              # Supporting not just callbacks but other values for callbacks. To make the code easier to
         | 
| 247 | 
            +
              # read and more reliable, hashes are not a supported callback value. To return one, use
         | 
| 248 | 
            +
              # a callback like you would normally
         | 
| 249 | 
            +
              #
         | 
| 250 | 
            +
              # @param [#to_s => AnyObject, !Hash] callback_tree
         | 
| 251 | 
            +
              # @return [Boolean] true if callback is valid, false if not
         | 
| 252 | 
            +
              def self.valid_callback_tree?(callback_tree)
         | 
| 253 | 
            +
                return false unless callback_tree.is_a?(Hash)
         | 
| 254 | 
            +
                callback_tree.all? do |key, value|
         | 
| 255 | 
            +
                  next false unless key.responds_to?(:to_s)
         | 
| 256 | 
            +
                  value.is_a?(Hash) ? valid_callback_tree?(value) : valid_callback?(value)
         | 
| 257 | 
            +
                end
         | 
| 258 | 
            +
              end
         | 
| 259 | 
            +
              private_class_method :valid_callback_tree?
         | 
| 260 | 
            +
             | 
| 233 261 | 
             
              # @param [Hash] callback_hash the tree of chained method calls
         | 
| 234 262 | 
             
              def initialize(callback_hash)
         | 
| 263 | 
            +
                valid_callback_tree?(callback_hash)
         | 
| 235 264 | 
             
                @callback_hash = callback_hash.deep_stringify_keys.freeze
         | 
| 236 265 | 
             
              end
         | 
| 237 266 |  | 
| 238 267 | 
             
              # @private
         | 
| 239 268 | 
             
              def method_missing(name, *args, &block)
         | 
| 240 269 | 
             
                current = @callback_hash[name.to_s]
         | 
| 241 | 
            -
                if  | 
| 270 | 
            +
                if MockProxy.valid_callback?(current)
         | 
| 242 271 | 
             
                  current.call(*args, &block)
         | 
| 243 272 | 
             
                else
         | 
| 244 | 
            -
                  if !current | 
| 273 | 
            +
                  if !current
         | 
| 245 274 | 
             
                    fail "Missing method #{name}. Please add this definition to your mock proxy"
         | 
| 246 275 | 
             
                  end
         | 
| 247 276 | 
             
                  MockProxy.new(current.freeze)
         | 
    
        data/lib/mock_proxy/version.rb
    CHANGED