hashie 2.1.2 → 4.1.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 +7 -0
- data/CHANGELOG.md +524 -59
- data/CONTRIBUTING.md +24 -7
- data/README.md +781 -90
- data/Rakefile +19 -2
- data/UPGRADING.md +245 -0
- data/hashie.gemspec +21 -13
- data/lib/hashie.rb +60 -21
- data/lib/hashie/array.rb +21 -0
- data/lib/hashie/clash.rb +24 -12
- data/lib/hashie/dash.rb +96 -33
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/array/pretty_inspect.rb +19 -0
- data/lib/hashie/extensions/coercion.rb +124 -18
- data/lib/hashie/extensions/dash/coercion.rb +25 -0
- data/lib/hashie/extensions/dash/indifferent_access.rb +56 -0
- data/lib/hashie/extensions/dash/property_translation.rb +191 -0
- data/lib/hashie/extensions/deep_fetch.rb +7 -5
- data/lib/hashie/extensions/deep_find.rb +69 -0
- data/lib/hashie/extensions/deep_locate.rb +113 -0
- data/lib/hashie/extensions/deep_merge.rb +35 -12
- data/lib/hashie/extensions/ignore_undeclared.rb +11 -5
- data/lib/hashie/extensions/indifferent_access.rb +28 -16
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/key_conversion.rb +0 -82
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +53 -0
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +18 -0
- data/lib/hashie/extensions/mash/symbolize_keys.rb +38 -0
- data/lib/hashie/extensions/method_access.rb +154 -11
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +48 -0
- data/lib/hashie/extensions/pretty_inspect.rb +19 -0
- data/lib/hashie/extensions/ruby_version.rb +60 -0
- data/lib/hashie/extensions/ruby_version_check.rb +21 -0
- data/lib/hashie/extensions/strict_key_access.rb +77 -0
- data/lib/hashie/extensions/stringify_keys.rb +71 -0
- data/lib/hashie/extensions/symbolize_keys.rb +71 -0
- data/lib/hashie/hash.rb +27 -8
- data/lib/hashie/logger.rb +18 -0
- data/lib/hashie/mash.rb +235 -57
- data/lib/hashie/railtie.rb +21 -0
- data/lib/hashie/rash.rb +40 -16
- data/lib/hashie/trash.rb +2 -88
- data/lib/hashie/utils.rb +44 -0
- data/lib/hashie/version.rb +1 -1
- metadata +42 -81
- data/.gitignore +0 -9
- data/.rspec +0 -2
- data/.rubocop.yml +0 -36
- data/.travis.yml +0 -15
- data/Gemfile +0 -11
- data/Guardfile +0 -5
- data/lib/hashie/hash_extensions.rb +0 -47
- data/spec/hashie/clash_spec.rb +0 -48
- data/spec/hashie/dash_spec.rb +0 -338
- data/spec/hashie/extensions/coercion_spec.rb +0 -156
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -70
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -22
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -23
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -152
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -103
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -121
- data/spec/hashie/hash_spec.rb +0 -66
- data/spec/hashie/mash_spec.rb +0 -467
- data/spec/hashie/rash_spec.rb +0 -44
- data/spec/hashie/trash_spec.rb +0 -193
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/spec.opts +0 -3
- data/spec/spec_helper.rb +0 -8
| @@ -2,28 +2,51 @@ module Hashie | |
| 2 2 | 
             
              module Extensions
         | 
| 3 3 | 
             
                module DeepMerge
         | 
| 4 4 | 
             
                  # Returns a new hash with +self+ and +other_hash+ merged recursively.
         | 
| 5 | 
            -
                  def deep_merge(other_hash)
         | 
| 6 | 
            -
                     | 
| 5 | 
            +
                  def deep_merge(other_hash, &block)
         | 
| 6 | 
            +
                    copy = _deep_dup(self)
         | 
| 7 | 
            +
                    copy.extend(Hashie::Extensions::DeepMerge) unless copy.respond_to?(:deep_merge!)
         | 
| 8 | 
            +
                    copy.deep_merge!(other_hash, &block)
         | 
| 7 9 | 
             
                  end
         | 
| 8 10 |  | 
| 9 11 | 
             
                  # Returns a new hash with +self+ and +other_hash+ merged recursively.
         | 
| 10 12 | 
             
                  # Modifies the receiver in place.
         | 
| 11 | 
            -
                  def deep_merge!(other_hash)
         | 
| 12 | 
            -
                     | 
| 13 | 
            +
                  def deep_merge!(other_hash, &block)
         | 
| 14 | 
            +
                    return self unless other_hash.is_a?(::Hash)
         | 
| 15 | 
            +
                    _recursive_merge(self, other_hash, &block)
         | 
| 13 16 | 
             
                    self
         | 
| 14 17 | 
             
                  end
         | 
| 15 18 |  | 
| 16 19 | 
             
                  private
         | 
| 17 20 |  | 
| 18 | 
            -
                  def  | 
| 19 | 
            -
                     | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
                       | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 21 | 
            +
                  def _deep_dup(hash)
         | 
| 22 | 
            +
                    copy = hash.dup
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    copy.each do |key, value|
         | 
| 25 | 
            +
                      copy[key] =
         | 
| 26 | 
            +
                        if value.is_a?(::Hash)
         | 
| 27 | 
            +
                          _deep_dup(value)
         | 
| 28 | 
            +
                        else
         | 
| 29 | 
            +
                          Hashie::Utils.safe_dup(value)
         | 
| 30 | 
            +
                        end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    copy
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def _recursive_merge(hash, other_hash, &block)
         | 
| 37 | 
            +
                    other_hash.each do |k, v|
         | 
| 38 | 
            +
                      hash[k] =
         | 
| 39 | 
            +
                        if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
         | 
| 40 | 
            +
                          _recursive_merge(hash[k], v, &block)
         | 
| 41 | 
            +
                        elsif v.is_a?(::Hash)
         | 
| 42 | 
            +
                          _recursive_merge({}, v, &block)
         | 
| 43 | 
            +
                        elsif hash.key?(k) && block_given?
         | 
| 44 | 
            +
                          yield(k, hash[k], v)
         | 
| 45 | 
            +
                        else
         | 
| 46 | 
            +
                          v.respond_to?(:deep_dup) ? v.deep_dup : v
         | 
| 47 | 
            +
                        end
         | 
| 26 48 | 
             
                    end
         | 
| 49 | 
            +
                    hash
         | 
| 27 50 | 
             
                  end
         | 
| 28 51 | 
             
                end
         | 
| 29 52 | 
             
              end
         | 
| @@ -5,7 +5,7 @@ module Hashie | |
| 5 5 | 
             
                # raising an error. This is useful when using a Trash to
         | 
| 6 6 | 
             
                # capture a subset of a larger hash.
         | 
| 7 7 | 
             
                #
         | 
| 8 | 
            -
                # Note that attempting to retrieve an undeclared property
         | 
| 8 | 
            +
                # Note that attempting to retrieve or set an undeclared property
         | 
| 9 9 | 
             
                # will still raise a NoMethodError, even if a value for
         | 
| 10 10 | 
             
                # that property was provided at initialization.
         | 
| 11 11 | 
             
                #
         | 
| @@ -30,11 +30,17 @@ module Hashie | |
| 30 30 | 
             
                #   p.email      # => NoMethodError
         | 
| 31 31 | 
             
                module IgnoreUndeclared
         | 
| 32 32 | 
             
                  def initialize_attributes(attributes)
         | 
| 33 | 
            +
                    return unless attributes
         | 
| 34 | 
            +
                    klass = self.class
         | 
| 35 | 
            +
                    translations = klass.respond_to?(:translations) && klass.translations
         | 
| 33 36 | 
             
                    attributes.each_pair do |att, value|
         | 
| 34 | 
            -
                       | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 37 | 
            +
                      next unless klass.property?(att) || (translations && translations.include?(att))
         | 
| 38 | 
            +
                      self[att] = value
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def property_exists?(property)
         | 
| 43 | 
            +
                    self.class.property?(property)
         | 
| 38 44 | 
             
                  end
         | 
| 39 45 | 
             
                end
         | 
| 40 46 | 
             
              end
         | 
| @@ -24,16 +24,18 @@ module Hashie | |
| 24 24 | 
             
                #
         | 
| 25 25 | 
             
                module IndifferentAccess
         | 
| 26 26 | 
             
                  def self.included(base)
         | 
| 27 | 
            +
                    Hashie::Extensions::Dash::IndifferentAccess.maybe_extend(base)
         | 
| 28 | 
            +
             | 
| 27 29 | 
             
                    base.class_eval do
         | 
| 28 | 
            -
                      alias_method :regular_writer, :[]=
         | 
| 30 | 
            +
                      alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
         | 
| 29 31 | 
             
                      alias_method :[]=, :indifferent_writer
         | 
| 30 32 | 
             
                      alias_method :store, :indifferent_writer
         | 
| 31 | 
            -
                      %w | 
| 32 | 
            -
                        alias_method "regular_#{m}", m
         | 
| 33 | 
            +
                      %w[default update replace fetch delete key? values_at].each do |m|
         | 
| 34 | 
            +
                        alias_method "regular_#{m}", m unless method_defined?("regular_#{m}")
         | 
| 33 35 | 
             
                        alias_method m, "indifferent_#{m}"
         | 
| 34 36 | 
             
                      end
         | 
| 35 37 |  | 
| 36 | 
            -
                      %w | 
| 38 | 
            +
                      %w[include? member? has_key?].each do |key_alias|
         | 
| 37 39 | 
             
                        alias_method key_alias, :indifferent_key?
         | 
| 38 40 | 
             
                      end
         | 
| 39 41 |  | 
| @@ -71,17 +73,17 @@ module Hashie | |
| 71 73 | 
             
                  # their proper indifferent state. Used when IndifferentAccess
         | 
| 72 74 | 
             
                  # is injecting itself into member hashes.
         | 
| 73 75 | 
             
                  def convert!
         | 
| 74 | 
            -
                    keys.each do |k|
         | 
| 75 | 
            -
                      regular_writer convert_key(k),  | 
| 76 | 
            +
                    keys.each do |k| # rubocop:disable Performance/HashEachMethods
         | 
| 77 | 
            +
                      regular_writer convert_key(k), indifferent_value(regular_delete(k))
         | 
| 76 78 | 
             
                    end
         | 
| 77 79 | 
             
                    self
         | 
| 78 80 | 
             
                  end
         | 
| 79 81 |  | 
| 80 | 
            -
                  def  | 
| 82 | 
            +
                  def indifferent_value(value)
         | 
| 81 83 | 
             
                    if hash_lacking_indifference?(value)
         | 
| 82 | 
            -
                      IndifferentAccess.inject(value | 
| 84 | 
            +
                      IndifferentAccess.inject!(value)
         | 
| 83 85 | 
             
                    elsif value.is_a?(::Array)
         | 
| 84 | 
            -
                      value. | 
| 86 | 
            +
                      value.replace(value.map { |e| indifferent_value(e) })
         | 
| 85 87 | 
             
                    else
         | 
| 86 88 | 
             
                      value
         | 
| 87 89 | 
             
                    end
         | 
| @@ -100,11 +102,11 @@ module Hashie | |
| 100 102 | 
             
                  end
         | 
| 101 103 |  | 
| 102 104 | 
             
                  def indifferent_writer(key, value)
         | 
| 103 | 
            -
                    regular_writer convert_key(key),  | 
| 105 | 
            +
                    regular_writer convert_key(key), indifferent_value(value)
         | 
| 104 106 | 
             
                  end
         | 
| 105 107 |  | 
| 106 | 
            -
                  def indifferent_fetch(key, *args)
         | 
| 107 | 
            -
                    regular_fetch convert_key(key), *args
         | 
| 108 | 
            +
                  def indifferent_fetch(key, *args, &block)
         | 
| 109 | 
            +
                    regular_fetch convert_key(key), *args, &block
         | 
| 108 110 | 
             
                  end
         | 
| 109 111 |  | 
| 110 112 | 
             
                  def indifferent_delete(key)
         | 
| @@ -129,18 +131,28 @@ module Hashie | |
| 129 131 | 
             
                    self
         | 
| 130 132 | 
             
                  end
         | 
| 131 133 |  | 
| 134 | 
            +
                  def merge(*args)
         | 
| 135 | 
            +
                    result = super
         | 
| 136 | 
            +
                    IndifferentAccess.inject!(result) if hash_lacking_indifference?(result)
         | 
| 137 | 
            +
                    result.convert!
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  def merge!(*)
         | 
| 141 | 
            +
                    super.convert!
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
             | 
| 132 144 | 
             
                  protected
         | 
| 133 145 |  | 
| 134 146 | 
             
                  def hash_lacking_indifference?(other)
         | 
| 135 147 | 
             
                    other.is_a?(::Hash) &&
         | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 148 | 
            +
                      !(other.respond_to?(:indifferent_access?) &&
         | 
| 149 | 
            +
                        other.indifferent_access?)
         | 
| 138 150 | 
             
                  end
         | 
| 139 151 |  | 
| 140 152 | 
             
                  def hash_with_indifference?(other)
         | 
| 141 153 | 
             
                    other.is_a?(::Hash) &&
         | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 154 | 
            +
                      other.respond_to?(:indifferent_access?) &&
         | 
| 155 | 
            +
                      other.indifferent_access?
         | 
| 144 156 | 
             
                  end
         | 
| 145 157 | 
             
                end
         | 
| 146 158 | 
             
              end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            module Hashie
         | 
| 2 | 
            +
              module Extensions
         | 
| 3 | 
            +
                module KeyConflictWarning
         | 
| 4 | 
            +
                  class CannotDisableMashWarnings < StandardError
         | 
| 5 | 
            +
                    def initialize
         | 
| 6 | 
            +
                      super(
         | 
| 7 | 
            +
                        'You cannot disable warnings on the base Mash class. ' \
         | 
| 8 | 
            +
                        'Please subclass the Mash and disable it in the subclass.'
         | 
| 9 | 
            +
                      )
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  # Disable the logging of warnings based on keys conflicting keys/methods
         | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  # @api semipublic
         | 
| 16 | 
            +
                  # @return [void]
         | 
| 17 | 
            +
                  def disable_warnings(*method_keys)
         | 
| 18 | 
            +
                    raise CannotDisableMashWarnings if self == Hashie::Mash
         | 
| 19 | 
            +
                    if method_keys.any?
         | 
| 20 | 
            +
                      disabled_warnings.concat(method_keys).tap(&:flatten!).uniq!
         | 
| 21 | 
            +
                    else
         | 
| 22 | 
            +
                      disabled_warnings.clear
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    @disable_warnings = true
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # Checks whether this class disables warnings for conflicting keys/methods
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @api semipublic
         | 
| 31 | 
            +
                  # @return [Boolean]
         | 
| 32 | 
            +
                  def disable_warnings?(method_key = nil)
         | 
| 33 | 
            +
                    return disabled_warnings.include?(method_key) if disabled_warnings.any? && method_key
         | 
| 34 | 
            +
                    @disable_warnings ||= false
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Returns an array of methods that this class disables warnings for.
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # @api semipublic
         | 
| 40 | 
            +
                  # @return [Boolean]
         | 
| 41 | 
            +
                  def disabled_warnings
         | 
| 42 | 
            +
                    @_disabled_warnings ||= []
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # Inheritance hook that sets class configuration when inherited.
         | 
| 46 | 
            +
                  #
         | 
| 47 | 
            +
                  # @api semipublic
         | 
| 48 | 
            +
                  # @return [void]
         | 
| 49 | 
            +
                  def inherited(subclass)
         | 
| 50 | 
            +
                    super
         | 
| 51 | 
            +
                    subclass.disable_warnings(disabled_warnings) if disable_warnings?
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
| @@ -1,87 +1,5 @@ | |
| 1 1 | 
             
            module Hashie
         | 
| 2 2 | 
             
              module Extensions
         | 
| 3 | 
            -
                module StringifyKeys
         | 
| 4 | 
            -
                  # Convert all keys in the hash to strings.
         | 
| 5 | 
            -
                  #
         | 
| 6 | 
            -
                  # @example
         | 
| 7 | 
            -
                  #   test = {:abc => 'def'}
         | 
| 8 | 
            -
                  #   test.stringify_keys!
         | 
| 9 | 
            -
                  #   test # => {'abc' => 'def'}
         | 
| 10 | 
            -
                  def stringify_keys!
         | 
| 11 | 
            -
                    keys.each do |k|
         | 
| 12 | 
            -
                      stringify_keys_recursively!(self[k])
         | 
| 13 | 
            -
                      self[k.to_s] = delete(k)
         | 
| 14 | 
            -
                    end
         | 
| 15 | 
            -
                    self
         | 
| 16 | 
            -
                  end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  # Return a new hash with all keys converted
         | 
| 19 | 
            -
                  # to strings.
         | 
| 20 | 
            -
                  def stringify_keys
         | 
| 21 | 
            -
                    dup.stringify_keys!
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  protected
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                  # Stringify all keys recursively within nested
         | 
| 27 | 
            -
                  # hashes and arrays.
         | 
| 28 | 
            -
                  def stringify_keys_recursively!(object)
         | 
| 29 | 
            -
                    if self.class === object
         | 
| 30 | 
            -
                      object.stringify_keys!
         | 
| 31 | 
            -
                    elsif ::Array === object
         | 
| 32 | 
            -
                      object.each do |i|
         | 
| 33 | 
            -
                        stringify_keys_recursively!(i)
         | 
| 34 | 
            -
                      end
         | 
| 35 | 
            -
                      object
         | 
| 36 | 
            -
                    elsif object.respond_to?(:stringify_keys!)
         | 
| 37 | 
            -
                      object.stringify_keys!
         | 
| 38 | 
            -
                    else
         | 
| 39 | 
            -
                      object
         | 
| 40 | 
            -
                    end
         | 
| 41 | 
            -
                  end
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                module SymbolizeKeys
         | 
| 45 | 
            -
                  # Convert all keys in the hash to symbols.
         | 
| 46 | 
            -
                  #
         | 
| 47 | 
            -
                  # @example
         | 
| 48 | 
            -
                  #   test = {'abc' => 'def'}
         | 
| 49 | 
            -
                  #   test.symbolize_keys!
         | 
| 50 | 
            -
                  #   test # => {:abc => 'def'}
         | 
| 51 | 
            -
                  def symbolize_keys!
         | 
| 52 | 
            -
                    keys.each do |k|
         | 
| 53 | 
            -
                      symbolize_keys_recursively!(self[k])
         | 
| 54 | 
            -
                      self[k.to_sym] = delete(k)
         | 
| 55 | 
            -
                    end
         | 
| 56 | 
            -
                    self
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  # Return a new hash with all keys converted
         | 
| 60 | 
            -
                  # to symbols.
         | 
| 61 | 
            -
                  def symbolize_keys
         | 
| 62 | 
            -
                    dup.symbolize_keys!
         | 
| 63 | 
            -
                  end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                  protected
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  # Symbolize all keys recursively within nested
         | 
| 68 | 
            -
                  # hashes and arrays.
         | 
| 69 | 
            -
                  def symbolize_keys_recursively!(object)
         | 
| 70 | 
            -
                    if self.class === object
         | 
| 71 | 
            -
                      object.symbolize_keys!
         | 
| 72 | 
            -
                    elsif ::Array === object
         | 
| 73 | 
            -
                      object.each do |i|
         | 
| 74 | 
            -
                        symbolize_keys_recursively!(i)
         | 
| 75 | 
            -
                      end
         | 
| 76 | 
            -
                      object
         | 
| 77 | 
            -
                    elsif object.respond_to?(:symbolize_keys!)
         | 
| 78 | 
            -
                      object.symbolize_keys!
         | 
| 79 | 
            -
                    else
         | 
| 80 | 
            -
                      object
         | 
| 81 | 
            -
                    end
         | 
| 82 | 
            -
                  end
         | 
| 83 | 
            -
                end
         | 
| 84 | 
            -
             | 
| 85 3 | 
             
                module KeyConversion
         | 
| 86 4 | 
             
                  def self.included(base)
         | 
| 87 5 | 
             
                    base.send :include, SymbolizeKeys
         | 
| @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            module Hashie
         | 
| 2 | 
            +
              module Extensions
         | 
| 3 | 
            +
                module Mash
         | 
| 4 | 
            +
                  module DefineAccessors
         | 
| 5 | 
            +
                    def self.included(klass)
         | 
| 6 | 
            +
                      klass.class_eval do
         | 
| 7 | 
            +
                        mod = Ext.new
         | 
| 8 | 
            +
                        include mod
         | 
| 9 | 
            +
                      end
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    def self.extended(obj)
         | 
| 13 | 
            +
                      included(obj.singleton_class)
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    class Ext < Module
         | 
| 17 | 
            +
                      def initialize
         | 
| 18 | 
            +
                        mod = self
         | 
| 19 | 
            +
                        define_method(:method_missing) do |method_name, *args, &block|
         | 
| 20 | 
            +
                          key, suffix = method_name_and_suffix(method_name)
         | 
| 21 | 
            +
                          case suffix
         | 
| 22 | 
            +
                          when '='.freeze
         | 
| 23 | 
            +
                            mod.define_writer(key, method_name)
         | 
| 24 | 
            +
                          when '?'.freeze
         | 
| 25 | 
            +
                            mod.define_predicate(key, method_name)
         | 
| 26 | 
            +
                          when '!'.freeze
         | 
| 27 | 
            +
                            mod.define_initializing_reader(key, method_name)
         | 
| 28 | 
            +
                          when '_'.freeze
         | 
| 29 | 
            +
                            mod.define_underbang_reader(key, method_name)
         | 
| 30 | 
            +
                          else
         | 
| 31 | 
            +
                            mod.define_reader(key, method_name)
         | 
| 32 | 
            +
                          end
         | 
| 33 | 
            +
                          send(method_name, *args, &block)
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      def define_reader(key, method_name)
         | 
| 38 | 
            +
                        define_method(method_name) do |&block|
         | 
| 39 | 
            +
                          if key? method_name
         | 
| 40 | 
            +
                            self.[](method_name, &block)
         | 
| 41 | 
            +
                          else
         | 
| 42 | 
            +
                            self.[](key, &block)
         | 
| 43 | 
            +
                          end
         | 
| 44 | 
            +
                        end
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      def define_writer(key, method_name)
         | 
| 48 | 
            +
                        define_method(method_name) do |value = nil|
         | 
| 49 | 
            +
                          if key? method_name
         | 
| 50 | 
            +
                            self.[](method_name, &proc)
         | 
| 51 | 
            +
                          else
         | 
| 52 | 
            +
                            assign_property(key, value)
         | 
| 53 | 
            +
                          end
         | 
| 54 | 
            +
                        end
         | 
| 55 | 
            +
                      end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                      def define_predicate(key, method_name)
         | 
| 58 | 
            +
                        define_method(method_name) do
         | 
| 59 | 
            +
                          if key? method_name
         | 
| 60 | 
            +
                            self.[](method_name, &proc)
         | 
| 61 | 
            +
                          else
         | 
| 62 | 
            +
                            !!self[key]
         | 
| 63 | 
            +
                          end
         | 
| 64 | 
            +
                        end
         | 
| 65 | 
            +
                      end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      def define_initializing_reader(key, method_name)
         | 
| 68 | 
            +
                        define_method(method_name) do
         | 
| 69 | 
            +
                          if key? method_name
         | 
| 70 | 
            +
                            self.[](method_name, &proc)
         | 
| 71 | 
            +
                          else
         | 
| 72 | 
            +
                            initializing_reader(key)
         | 
| 73 | 
            +
                          end
         | 
| 74 | 
            +
                        end
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      def define_underbang_reader(key, method_name)
         | 
| 78 | 
            +
                        define_method(method_name) do
         | 
| 79 | 
            +
                          if key? method_name
         | 
| 80 | 
            +
                            self.[](key, &proc)
         | 
| 81 | 
            +
                          else
         | 
| 82 | 
            +
                            underbang_reader(key)
         | 
| 83 | 
            +
                          end
         | 
| 84 | 
            +
                        end
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            module Hashie
         | 
| 2 | 
            +
              module Extensions
         | 
| 3 | 
            +
                module Mash
         | 
| 4 | 
            +
                  # Overrides the indifferent access of a Mash to keep keys in the
         | 
| 5 | 
            +
                  # original format given to the Mash.
         | 
| 6 | 
            +
                  #
         | 
| 7 | 
            +
                  # @example
         | 
| 8 | 
            +
                  #   class KeepingMash < Hashie::Mash
         | 
| 9 | 
            +
                  #     include Hashie::Extensions::Mash::KeepOriginalKeys
         | 
| 10 | 
            +
                  #   end
         | 
| 11 | 
            +
                  #
         | 
| 12 | 
            +
                  #   mash = KeepingMash.new(:symbol_key => :symbol, 'string_key' => 'string')
         | 
| 13 | 
            +
                  #   mash.to_hash  #=> { :symbol_key => :symbol, 'string_key' => 'string' }
         | 
| 14 | 
            +
                  #   mash['string_key'] == mash[:string_key]  #=> true
         | 
| 15 | 
            +
                  #   mash[:symbol_key] == mash['symbol_key']  #=> true
         | 
| 16 | 
            +
                  module KeepOriginalKeys
         | 
| 17 | 
            +
                    def self.included(descendant)
         | 
| 18 | 
            +
                      error_message = "#{descendant} is not a kind of Hashie::Mash"
         | 
| 19 | 
            +
                      raise ArgumentError, error_message unless descendant <= Hashie::Mash
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    # Converts the key when necessary to access the correct Mash key.
         | 
| 25 | 
            +
                    #
         | 
| 26 | 
            +
                    # @param [Object, String, Symbol] key the key to access.
         | 
| 27 | 
            +
                    # @return [Object] the value assigned to the key.
         | 
| 28 | 
            +
                    def convert_key(key)
         | 
| 29 | 
            +
                      if regular_key?(key)
         | 
| 30 | 
            +
                        key
         | 
| 31 | 
            +
                      elsif (converted_key = __convert(key)) && regular_key?(converted_key)
         | 
| 32 | 
            +
                        converted_key
         | 
| 33 | 
            +
                      else
         | 
| 34 | 
            +
                        key
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    # Converts symbol/string keys to their alternative formats, but leaves
         | 
| 39 | 
            +
                    # other keys alone.
         | 
| 40 | 
            +
                    #
         | 
| 41 | 
            +
                    # @param [Object, String, Symbol] key the key to convert.
         | 
| 42 | 
            +
                    # @return [Object, String, Symbol] the converted key.
         | 
| 43 | 
            +
                    def __convert(key)
         | 
| 44 | 
            +
                      case key
         | 
| 45 | 
            +
                      when Symbol then key.to_s
         | 
| 46 | 
            +
                      when String then key.to_sym
         | 
| 47 | 
            +
                      else key
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         |