hashie 3.6.0 → 4.0.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 +28 -0
- data/README.md +95 -7
- data/UPGRADING.md +78 -2
- data/hashie.gemspec +2 -1
- data/lib/hashie.rb +20 -19
- data/lib/hashie/dash.rb +2 -1
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/coercion.rb +23 -16
- data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
- data/lib/hashie/extensions/dash/property_translation.rb +5 -2
- data/lib/hashie/extensions/deep_fetch.rb +4 -2
- data/lib/hashie/extensions/deep_find.rb +12 -3
- data/lib/hashie/extensions/deep_locate.rb +22 -7
- data/lib/hashie/extensions/indifferent_access.rb +1 -3
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -1
- data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/method_access.rb +5 -2
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +9 -4
- data/lib/hashie/extensions/strict_key_access.rb +8 -4
- data/lib/hashie/hash.rb +16 -9
- data/lib/hashie/mash.rb +99 -43
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/dash_spec.rb +18 -8
- data/spec/hashie/extensions/coercion_spec.rb +17 -8
- data/spec/hashie/extensions/deep_find_spec.rb +12 -6
- data/spec/hashie/extensions/deep_locate_spec.rb +2 -1
- data/spec/hashie/extensions/deep_merge_spec.rb +6 -2
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +2 -1
- data/spec/hashie/extensions/mash/define_accessors_spec.rb +90 -0
- data/spec/hashie/extensions/method_access_spec.rb +8 -1
- data/spec/hashie/extensions/strict_key_access_spec.rb +9 -10
- data/spec/hashie/extensions/symbolize_keys_spec.rb +3 -1
- data/spec/hashie/hash_spec.rb +45 -6
- data/spec/hashie/mash_spec.rb +314 -8
- data/spec/hashie/trash_spec.rb +9 -3
- data/spec/integration/elasticsearch/integration_spec.rb +3 -2
- data/spec/integration/rails/app.rb +5 -12
- data/spec/integration/rails/integration_spec.rb +22 -1
- metadata +8 -4
    
        data/lib/hashie/mash.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ require 'hashie/hash' | |
| 2 2 | 
             
            require 'hashie/array'
         | 
| 3 3 | 
             
            require 'hashie/utils'
         | 
| 4 4 | 
             
            require 'hashie/logger'
         | 
| 5 | 
            +
            require 'hashie/extensions/key_conflict_warning'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Hashie
         | 
| 7 8 | 
             
              # Mash allows you to create pseudo-objects that have method-like
         | 
| @@ -16,8 +17,10 @@ module Hashie | |
| 16 17 | 
             
              # * No punctuation: Returns the value of the hash for that key, or nil if none exists.
         | 
| 17 18 | 
             
              # * Assignment (<tt>=</tt>): Sets the attribute of the given method name.
         | 
| 18 19 | 
             
              # * Existence (<tt>?</tt>): Returns true or false depending on whether that key has been set.
         | 
| 19 | 
            -
              # * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it | 
| 20 | 
            -
              #  | 
| 20 | 
            +
              # * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it
         | 
| 21 | 
            +
              #   as "touch" for mashes.
         | 
| 22 | 
            +
              # * Under Bang (<tt>_</tt>): Like Bang, but returns a new Mash rather than creating a key.
         | 
| 23 | 
            +
              #   Used to test existance in deep Mashes.
         | 
| 21 24 | 
             
              #
         | 
| 22 25 | 
             
              # == Basic Example
         | 
| 23 26 | 
             
              #
         | 
| @@ -60,41 +63,10 @@ module Hashie | |
| 60 63 | 
             
              class Mash < Hash
         | 
| 61 64 | 
             
                include Hashie::Extensions::PrettyInspect
         | 
| 62 65 | 
             
                include Hashie::Extensions::RubyVersionCheck
         | 
| 66 | 
            +
                extend Hashie::Extensions::KeyConflictWarning
         | 
| 63 67 |  | 
| 64 68 | 
             
                ALLOWED_SUFFIXES = %w[? ! = _].freeze
         | 
| 65 69 |  | 
| 66 | 
            -
                class CannotDisableMashWarnings < StandardError
         | 
| 67 | 
            -
                  def initialize(message = 'You cannot disable warnings on the base Mash class. Please subclass the Mash and disable it in the subclass.')
         | 
| 68 | 
            -
                    super(message)
         | 
| 69 | 
            -
                  end
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                # Disable the logging of warnings based on keys conflicting keys/methods
         | 
| 73 | 
            -
                #
         | 
| 74 | 
            -
                # @api semipublic
         | 
| 75 | 
            -
                # @return [void]
         | 
| 76 | 
            -
                def self.disable_warnings
         | 
| 77 | 
            -
                  raise CannotDisableMashWarnings if self == Hashie::Mash
         | 
| 78 | 
            -
                  @disable_warnings = true
         | 
| 79 | 
            -
                end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                # Checks whether this class disables warnings for conflicting keys/methods
         | 
| 82 | 
            -
                #
         | 
| 83 | 
            -
                # @api semipublic
         | 
| 84 | 
            -
                # @return [Boolean]
         | 
| 85 | 
            -
                def self.disable_warnings?
         | 
| 86 | 
            -
                  @disable_warnings ||= false
         | 
| 87 | 
            -
                end
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                # Inheritance hook that sets class configuration when inherited.
         | 
| 90 | 
            -
                #
         | 
| 91 | 
            -
                # @api semipublic
         | 
| 92 | 
            -
                # @return [void]
         | 
| 93 | 
            -
                def self.inherited(subclass)
         | 
| 94 | 
            -
                  super
         | 
| 95 | 
            -
                  subclass.disable_warnings if disable_warnings?
         | 
| 96 | 
            -
                end
         | 
| 97 | 
            -
             | 
| 98 70 | 
             
                def self.load(path, options = {})
         | 
| 99 71 | 
             
                  @_mashes ||= new
         | 
| 100 72 |  | 
| @@ -102,7 +74,7 @@ module Hashie | |
| 102 74 | 
             
                  raise ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path)
         | 
| 103 75 |  | 
| 104 76 | 
             
                  parser = options.fetch(:parser) { Hashie::Extensions::Parsers::YamlErbParser }
         | 
| 105 | 
            -
                  @_mashes[path] = new(parser.perform(path)).freeze
         | 
| 77 | 
            +
                  @_mashes[path] = new(parser.perform(path, options.except(:parser))).freeze
         | 
| 106 78 | 
             
                end
         | 
| 107 79 |  | 
| 108 80 | 
             
                def to_module(mash_method_name = :settings)
         | 
| @@ -114,6 +86,10 @@ module Hashie | |
| 114 86 | 
             
                  end
         | 
| 115 87 | 
             
                end
         | 
| 116 88 |  | 
| 89 | 
            +
                def with_accessors!
         | 
| 90 | 
            +
                  extend Hashie::Extensions::Mash::DefineAccessors
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 117 93 | 
             
                alias to_s inspect
         | 
| 118 94 |  | 
| 119 95 | 
             
                # If you pass in an existing hash, it will
         | 
| @@ -125,6 +101,19 @@ module Hashie | |
| 125 101 | 
             
                  default ? super(default) : super(&blk)
         | 
| 126 102 | 
             
                end
         | 
| 127 103 |  | 
| 104 | 
            +
                # Creates a new anonymous subclass with key conflict
         | 
| 105 | 
            +
                # warnings disabled. You may pass an array of method
         | 
| 106 | 
            +
                # symbols to restrict the disabled warnings to.
         | 
| 107 | 
            +
                # Hashie::Mash.quiet.new(hash) all warnings disabled.
         | 
| 108 | 
            +
                # Hashie::Mash.quiet(:zip).new(hash) only zip warning
         | 
| 109 | 
            +
                # is disabled.
         | 
| 110 | 
            +
                def self.quiet(*method_keys)
         | 
| 111 | 
            +
                  @memoized_classes ||= {}
         | 
| 112 | 
            +
                  @memoized_classes[method_keys] ||= Class.new(self) do
         | 
| 113 | 
            +
                    disable_warnings(*method_keys)
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 128 117 | 
             
                class << self; alias [] new; end
         | 
| 129 118 |  | 
| 130 119 | 
             
                alias regular_reader []
         | 
| @@ -183,6 +172,31 @@ module Hashie | |
| 183 172 | 
             
                  super(*keys.map { |key| convert_key(key) })
         | 
| 184 173 | 
             
                end
         | 
| 185 174 |  | 
| 175 | 
            +
                # Returns a new instance of the class it was called on, with nil values
         | 
| 176 | 
            +
                # removed.
         | 
| 177 | 
            +
                def compact
         | 
| 178 | 
            +
                  self.class.new(super)
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                # Returns a new instance of the class it was called on, using its keys as
         | 
| 182 | 
            +
                # values, and its values as keys. The new values and keys will always be
         | 
| 183 | 
            +
                # strings.
         | 
| 184 | 
            +
                def invert
         | 
| 185 | 
            +
                  self.class.new(super)
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                # Returns a new instance of the class it was called on, containing elements
         | 
| 189 | 
            +
                # for which the given block returns false.
         | 
| 190 | 
            +
                def reject(&blk)
         | 
| 191 | 
            +
                  self.class.new(super(&blk))
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                # Returns a new instance of the class it was called on, containing elements
         | 
| 195 | 
            +
                # for which the given block returns true.
         | 
| 196 | 
            +
                def select(&blk)
         | 
| 197 | 
            +
                  self.class.new(super(&blk))
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 186 200 | 
             
                alias regular_dup dup
         | 
| 187 201 | 
             
                # Duplicates the current mash as a new mash.
         | 
| 188 202 | 
             
                def dup
         | 
| @@ -202,14 +216,42 @@ module Hashie | |
| 202 216 | 
             
                def deep_merge(other_hash, &blk)
         | 
| 203 217 | 
             
                  dup.deep_update(other_hash, &blk)
         | 
| 204 218 | 
             
                end
         | 
| 205 | 
            -
                alias merge deep_merge
         | 
| 206 219 |  | 
| 207 220 | 
             
                # Recursively merges this mash with the passed
         | 
| 208 221 | 
             
                # in hash, merging each hash in the hierarchy.
         | 
| 209 222 | 
             
                def deep_update(other_hash, &blk)
         | 
| 223 | 
            +
                  _deep_update(other_hash, &blk)
         | 
| 224 | 
            +
                  self
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                with_minimum_ruby('2.6.0') do
         | 
| 228 | 
            +
                  # Performs a deep_update on a duplicate of the
         | 
| 229 | 
            +
                  # current mash.
         | 
| 230 | 
            +
                  def deep_merge(*other_hashes, &blk)
         | 
| 231 | 
            +
                    dup.deep_update(*other_hashes, &blk)
         | 
| 232 | 
            +
                  end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                  # Recursively merges this mash with the passed
         | 
| 235 | 
            +
                  # in hash, merging each hash in the hierarchy.
         | 
| 236 | 
            +
                  def deep_update(*other_hashes, &blk)
         | 
| 237 | 
            +
                    other_hashes.each do |other_hash|
         | 
| 238 | 
            +
                      _deep_update(other_hash, &blk)
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
                    self
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                # Alias these lexically so they get the correctly defined
         | 
| 245 | 
            +
                # #deep_merge and #deep_update based on ruby version.
         | 
| 246 | 
            +
                alias merge deep_merge
         | 
| 247 | 
            +
                alias deep_merge! deep_update
         | 
| 248 | 
            +
                alias update deep_update
         | 
| 249 | 
            +
                alias merge! update
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                def _deep_update(other_hash, &blk)
         | 
| 210 252 | 
             
                  other_hash.each_pair do |k, v|
         | 
| 211 253 | 
             
                    key = convert_key(k)
         | 
| 212 | 
            -
                    if  | 
| 254 | 
            +
                    if v.is_a?(::Hash) && key?(key) && regular_reader(key).is_a?(Mash)
         | 
| 213 255 | 
             
                      custom_reader(key).deep_update(v, &blk)
         | 
| 214 256 | 
             
                    else
         | 
| 215 257 | 
             
                      value = convert_value(v, true)
         | 
| @@ -217,11 +259,8 @@ module Hashie | |
| 217 259 | 
             
                      custom_writer(key, value, false)
         | 
| 218 260 | 
             
                    end
         | 
| 219 261 | 
             
                  end
         | 
| 220 | 
            -
                  self
         | 
| 221 262 | 
             
                end
         | 
| 222 | 
            -
                 | 
| 223 | 
            -
                alias update deep_update
         | 
| 224 | 
            -
                alias merge! update
         | 
| 263 | 
            +
                private :_deep_update
         | 
| 225 264 |  | 
| 226 265 | 
             
                # Assigns a value to a key
         | 
| 227 266 | 
             
                def assign_property(name, value)
         | 
| @@ -296,6 +335,23 @@ module Hashie | |
| 296 335 | 
             
                  end
         | 
| 297 336 | 
             
                end
         | 
| 298 337 |  | 
| 338 | 
            +
                with_minimum_ruby('2.4.0') do
         | 
| 339 | 
            +
                  def transform_values(&blk)
         | 
| 340 | 
            +
                    self.class.new(super(&blk))
         | 
| 341 | 
            +
                  end
         | 
| 342 | 
            +
                end
         | 
| 343 | 
            +
             | 
| 344 | 
            +
                with_minimum_ruby('2.5.0') do
         | 
| 345 | 
            +
                  def slice(*keys)
         | 
| 346 | 
            +
                    string_keys = keys.map { |key| convert_key(key) }
         | 
| 347 | 
            +
                    self.class.new(super(*string_keys))
         | 
| 348 | 
            +
                  end
         | 
| 349 | 
            +
             | 
| 350 | 
            +
                  def transform_keys(&blk)
         | 
| 351 | 
            +
                    self.class.new(super(&blk))
         | 
| 352 | 
            +
                  end
         | 
| 353 | 
            +
                end
         | 
| 354 | 
            +
             | 
| 299 355 | 
             
                protected
         | 
| 300 356 |  | 
| 301 357 | 
             
                def method_name_and_suffix(method_name)
         | 
| @@ -337,7 +393,7 @@ module Hashie | |
| 337 393 | 
             
                private
         | 
| 338 394 |  | 
| 339 395 | 
             
                def log_built_in_message(method_key)
         | 
| 340 | 
            -
                  return if self.class.disable_warnings?
         | 
| 396 | 
            +
                  return if self.class.disable_warnings?(method_key)
         | 
| 341 397 |  | 
| 342 398 | 
             
                  method_information = Hashie::Utils.method_information(method(method_key))
         | 
| 343 399 |  | 
| @@ -350,7 +406,7 @@ module Hashie | |
| 350 406 | 
             
                end
         | 
| 351 407 |  | 
| 352 408 | 
             
                def log_collision?(method_key)
         | 
| 353 | 
            -
                  respond_to?(method_key) && !self.class.disable_warnings? &&
         | 
| 409 | 
            +
                  respond_to?(method_key) && !self.class.disable_warnings?(method_key) &&
         | 
| 354 410 | 
             
                    !(regular_key?(method_key) || regular_key?(method_key.to_s))
         | 
| 355 411 | 
             
                end
         | 
| 356 412 | 
             
              end
         | 
    
        data/lib/hashie/railtie.rb
    CHANGED
    
    | @@ -7,6 +7,13 @@ begin | |
| 7 7 | 
             
                  initializer 'hashie.configure_logger', after: 'initialize_logger' do
         | 
| 8 8 | 
             
                    Hashie.logger = Rails.logger
         | 
| 9 9 | 
             
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  initializer 'hashie.patch_hash_except', after: 'load_active_support' do
         | 
| 12 | 
            +
                    if Rails::VERSION::MAJOR >= 6
         | 
| 13 | 
            +
                      require 'hashie/extensions/active_support/core_ext/hash'
         | 
| 14 | 
            +
                      Hashie::Mash.send(:include, Hashie::Extensions::ActiveSupport::CoreExt::Hash)
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 10 17 | 
             
                end
         | 
| 11 18 | 
             
              end
         | 
| 12 19 | 
             
            rescue LoadError => e
         | 
    
        data/lib/hashie/rash.rb
    CHANGED
    
    | @@ -117,7 +117,7 @@ module Hashie | |
| 117 117 | 
             
                    end
         | 
| 118 118 |  | 
| 119 119 | 
             
                  when Regexp
         | 
| 120 | 
            -
                    # Reverse operation: `rash[/regexp/]` returns all  | 
| 120 | 
            +
                    # Reverse operation: `rash[/regexp/]` returns all string keys matching the regexp
         | 
| 121 121 | 
             
                    @hash.each do |key, val|
         | 
| 122 122 | 
             
                      yield val if key.is_a?(String) && query =~ key
         | 
| 123 123 | 
             
                    end
         | 
    
        data/lib/hashie/version.rb
    CHANGED
    
    
    
        data/spec/hashie/dash_spec.rb
    CHANGED
    
    | @@ -129,12 +129,14 @@ describe DashTest do | |
| 129 129 | 
             
              context 'writing to properties' do
         | 
| 130 130 | 
             
                it 'fails writing a required property to nil' do
         | 
| 131 131 | 
             
                  expect { subject.first_name = nil }.to raise_error(*property_required_error('first_name'))
         | 
| 132 | 
            -
                  expect { required_message.first_name = nil } | 
| 132 | 
            +
                  expect { required_message.first_name = nil }
         | 
| 133 | 
            +
                    .to raise_error(*property_required_custom_error('first_name'))
         | 
| 133 134 | 
             
                end
         | 
| 134 135 |  | 
| 135 136 | 
             
                it 'fails writing a required property to nil using []=' do
         | 
| 136 137 | 
             
                  expect { subject[:first_name] = nil }.to raise_error(*property_required_error('first_name'))
         | 
| 137 | 
            -
                  expect { required_message[:first_name] = nil } | 
| 138 | 
            +
                  expect { required_message[:first_name] = nil }
         | 
| 139 | 
            +
                    .to raise_error(*property_required_custom_error('first_name'))
         | 
| 138 140 | 
             
                end
         | 
| 139 141 |  | 
| 140 142 | 
             
                it 'fails writing to a non-existent property using []=' do
         | 
| @@ -263,11 +265,13 @@ describe DashTest do | |
| 263 265 | 
             
                end
         | 
| 264 266 |  | 
| 265 267 | 
             
                it 'fails with non-existent properties' do
         | 
| 266 | 
            -
                  expect { subject.merge(middle_name: 'James') } | 
| 268 | 
            +
                  expect { subject.merge(middle_name: 'James') }
         | 
| 269 | 
            +
                    .to raise_error(*no_property_error('middle_name'))
         | 
| 267 270 | 
             
                end
         | 
| 268 271 |  | 
| 269 272 | 
             
                it 'errors out when attempting to set a required property to nil' do
         | 
| 270 | 
            -
                  expect { subject.merge(first_name: nil) } | 
| 273 | 
            +
                  expect { subject.merge(first_name: nil) }
         | 
| 274 | 
            +
                    .to raise_error(*property_required_error('first_name'))
         | 
| 271 275 | 
             
                end
         | 
| 272 276 |  | 
| 273 277 | 
             
                context 'given a block' do
         | 
| @@ -366,8 +370,12 @@ describe DashTest do | |
| 366 370 | 
             
                let(:params) { { first_name: 'Alice', email: 'alice@example.com' } }
         | 
| 367 371 |  | 
| 368 372 | 
             
                context 'when there is coercion' do
         | 
| 369 | 
            -
                  let(:params_before)  | 
| 370 | 
            -
             | 
| 373 | 
            +
                  let(:params_before) do
         | 
| 374 | 
            +
                    { city: 'nyc', person: { first_name: 'Bob', email: 'bob@example.com' } }
         | 
| 375 | 
            +
                  end
         | 
| 376 | 
            +
                  let(:params_after) do
         | 
| 377 | 
            +
                    { city: 'sfo', person: { first_name: 'Alice', email: 'alice@example.com' } }
         | 
| 378 | 
            +
                  end
         | 
| 371 379 |  | 
| 372 380 | 
             
                  subject { DashWithCoercion.new(params_before) }
         | 
| 373 381 |  | 
| @@ -505,7 +513,8 @@ end | |
| 505 513 |  | 
| 506 514 | 
             
            describe ConditionallyRequiredTest do
         | 
| 507 515 | 
             
              it 'does not allow a conditionally required property to be set to nil if required' do
         | 
| 508 | 
            -
                expect { ConditionallyRequiredTest.new(username: 'bob.smith', password: nil) } | 
| 516 | 
            +
                expect { ConditionallyRequiredTest.new(username: 'bob.smith', password: nil) }
         | 
| 517 | 
            +
                  .to raise_error(ArgumentError, "The property 'password' must be set, too.")
         | 
| 509 518 | 
             
              end
         | 
| 510 519 |  | 
| 511 520 | 
             
              it 'allows a conditionally required property to be set to nil if not required' do
         | 
| @@ -513,7 +522,8 @@ describe ConditionallyRequiredTest do | |
| 513 522 | 
             
              end
         | 
| 514 523 |  | 
| 515 524 | 
             
              it 'allows a conditionally required property to be set if required' do
         | 
| 516 | 
            -
                expect { ConditionallyRequiredTest.new(username: 'bob.smith', password: '$ecure!') } | 
| 525 | 
            +
                expect { ConditionallyRequiredTest.new(username: 'bob.smith', password: '$ecure!') }
         | 
| 526 | 
            +
                  .not_to raise_error
         | 
| 517 527 | 
             
              end
         | 
| 518 528 | 
             
            end
         | 
| 519 529 |  | 
| @@ -283,7 +283,8 @@ describe Hashie::Extensions::Coercion do | |
| 283 283 |  | 
| 284 284 | 
             
                  it 'raises errors for non-coercable types' do
         | 
| 285 285 | 
             
                    subject.coerce_key :foo, NotInitializable
         | 
| 286 | 
            -
                    expect { instance[:foo] = 'true' } | 
| 286 | 
            +
                    expect { instance[:foo] = 'true' }
         | 
| 287 | 
            +
                      .to raise_error(Hashie::CoercionError, /NotInitializable is not a coercable type/)
         | 
| 287 288 | 
             
                  end
         | 
| 288 289 |  | 
| 289 290 | 
             
                  it 'can coerce false' do
         | 
| @@ -458,8 +459,12 @@ describe Hashie::Extensions::Coercion do | |
| 458 459 | 
             
                      coerce_key :categories, Array[CategoryHash]
         | 
| 459 460 | 
             
                    end
         | 
| 460 461 |  | 
| 461 | 
            -
                    let(:category)  | 
| 462 | 
            -
             | 
| 462 | 
            +
                    let(:category) do
         | 
| 463 | 
            +
                      CategoryHash.new(type: 'rubygem', products: [Hashie::Mash.new(name: 'Hashie')])
         | 
| 464 | 
            +
                    end
         | 
| 465 | 
            +
                    let(:product) do
         | 
| 466 | 
            +
                      ProductHash.new(name: 'Hashie', categories: [Hashie::Mash.new(type: 'rubygem')])
         | 
| 467 | 
            +
                    end
         | 
| 463 468 |  | 
| 464 469 | 
             
                    it 'coerces CategoryHash[:products] correctly' do
         | 
| 465 470 | 
             
                      expected = [ProductHash]
         | 
| @@ -559,22 +564,26 @@ describe Hashie::Extensions::Coercion do | |
| 559 564 |  | 
| 560 565 | 
             
                  it 'raises a CoercionError when coercion is not possible' do
         | 
| 561 566 | 
             
                    type =
         | 
| 562 | 
            -
                      if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= | 
| 567 | 
            +
                      if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
         | 
| 568 | 
            +
                         Hashie::Extensions::RubyVersion.new('2.4.0')
         | 
| 563 569 | 
             
                        Integer
         | 
| 564 570 | 
             
                      else
         | 
| 565 | 
            -
                        Fixnum | 
| 571 | 
            +
                        Fixnum
         | 
| 566 572 | 
             
                      end
         | 
| 567 573 |  | 
| 568 574 | 
             
                    subject.coerce_value type, Symbol
         | 
| 569 | 
            -
                    expect { instance[:hi] = 1 }.to raise_error( | 
| 575 | 
            +
                    expect { instance[:hi] = 1 }.to raise_error(
         | 
| 576 | 
            +
                      Hashie::CoercionError, /Cannot coerce property :hi from #{type} to Symbol/
         | 
| 577 | 
            +
                    )
         | 
| 570 578 | 
             
                  end
         | 
| 571 579 |  | 
| 572 580 | 
             
                  it 'coerces Integer to String' do
         | 
| 573 581 | 
             
                    type =
         | 
| 574 | 
            -
                      if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= | 
| 582 | 
            +
                      if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
         | 
| 583 | 
            +
                         Hashie::Extensions::RubyVersion.new('2.4.0')
         | 
| 575 584 | 
             
                        Integer
         | 
| 576 585 | 
             
                      else
         | 
| 577 | 
            -
                        Fixnum | 
| 586 | 
            +
                        Fixnum
         | 
| 578 587 | 
             
                      end
         | 
| 579 588 |  | 
| 580 589 | 
             
                    subject.coerce_value type, String
         | 
| @@ -36,7 +36,8 @@ describe Hashie::Extensions::DeepFind do | |
| 36 36 |  | 
| 37 37 | 
             
              describe '#deep_find_all' do
         | 
| 38 38 | 
             
                it 'detects all values from a nested hash' do
         | 
| 39 | 
            -
                  expect(instance.deep_find_all(:title)) | 
| 39 | 
            +
                  expect(instance.deep_find_all(:title))
         | 
| 40 | 
            +
                    .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 40 41 | 
             
                end
         | 
| 41 42 |  | 
| 42 43 | 
             
                it 'returns nil if it does not find any matches' do
         | 
| @@ -64,7 +65,8 @@ describe Hashie::Extensions::DeepFind do | |
| 64 65 | 
             
                  end
         | 
| 65 66 |  | 
| 66 67 | 
             
                  it 'detects all values from a nested hash' do
         | 
| 67 | 
            -
                    expect(instance.deep_find_all(:title)) | 
| 68 | 
            +
                    expect(instance.deep_find_all(:title))
         | 
| 69 | 
            +
                      .to eq([{ type: :string }, 'Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 68 70 | 
             
                  end
         | 
| 69 71 | 
             
                end
         | 
| 70 72 | 
             
              end
         | 
| @@ -91,8 +93,10 @@ describe Hashie::Extensions::DeepFind do | |
| 91 93 |  | 
| 92 94 | 
             
                describe '#deep_find_all' do
         | 
| 93 95 | 
             
                  it 'indifferently detects all values from a nested hash' do
         | 
| 94 | 
            -
                    expect(instance.deep_find_all(:title)) | 
| 95 | 
            -
             | 
| 96 | 
            +
                    expect(instance.deep_find_all(:title))
         | 
| 97 | 
            +
                      .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 98 | 
            +
                    expect(instance.deep_find_all('title'))
         | 
| 99 | 
            +
                      .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 96 100 | 
             
                  end
         | 
| 97 101 |  | 
| 98 102 | 
             
                  it 'indifferently returns nil if it does not find any matches' do
         | 
| @@ -125,8 +129,10 @@ describe Hashie::Extensions::DeepFind do | |
| 125 129 |  | 
| 126 130 | 
             
                describe '#deep_find_all' do
         | 
| 127 131 | 
             
                  it 'indifferently detects all values from a nested hash' do
         | 
| 128 | 
            -
                    expect(instance.deep_find_all(:title)) | 
| 129 | 
            -
             | 
| 132 | 
            +
                    expect(instance.deep_find_all(:title))
         | 
| 133 | 
            +
                      .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 134 | 
            +
                    expect(instance.deep_find_all('title'))
         | 
| 135 | 
            +
                      .to eq(['Call of the Wild', 'Moby Dick', 'Main Library'])
         | 
| 130 136 | 
             
                  end
         | 
| 131 137 |  | 
| 132 138 | 
             
                  it 'indifferently returns nil if it does not find any matches' do
         | 
| @@ -56,7 +56,8 @@ describe Hashie::Extensions::DeepLocate do | |
| 56 56 | 
             
              describe '.deep_locate' do
         | 
| 57 57 | 
             
                context 'if called with a non-callable comparator' do
         | 
| 58 58 | 
             
                  it 'creates a key comparator on-th-fly' do
         | 
| 59 | 
            -
                    expect(described_class.deep_locate(:lsr10, hash)) | 
| 59 | 
            +
                    expect(described_class.deep_locate(:lsr10, hash))
         | 
| 60 | 
            +
                      .to eq([hash[:query][:bool][:must_not][0][:range]])
         | 
| 60 61 | 
             
                  end
         | 
| 61 62 | 
             
                end
         | 
| 62 63 |  | 
| @@ -13,9 +13,13 @@ describe Hashie::Extensions::DeepMerge do | |
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              context 'without &block' do
         | 
| 16 | 
            -
                let(:h1)  | 
| 16 | 
            +
                let(:h1) do
         | 
| 17 | 
            +
                  subject.new.merge(a: 'a', a1: 42, b: 'b', c: { c1: 'c1', c2: { a: 'b' }, c3: { d1: 'd1' } })
         | 
| 18 | 
            +
                end
         | 
| 17 19 | 
             
                let(:h2) { { a: 1, a1: 1, c: { c1: 2, c2: 'c2', c3: { d2: 'd2' } }, e: { e1: 1 } } }
         | 
| 18 | 
            -
                let(:expected_hash)  | 
| 20 | 
            +
                let(:expected_hash) do
         | 
| 21 | 
            +
                  { a: 1, a1: 1, b: 'b', c: { c1: 2, c2: 'c2', c3: { d1: 'd1', d2: 'd2' } }, e: { e1: 1 } }
         | 
| 22 | 
            +
                end
         | 
| 19 23 |  | 
| 20 24 | 
             
                it 'deep merges two hashes' do
         | 
| 21 25 | 
             
                  expect(h1.deep_merge(h2)).to eq expected_hash
         |