diff options
author | Michael Herold <github@michaeljherold.com> | 2017-02-22 19:37:07 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-22 19:37:07 -0600 |
commit | c071e4f9fdcd41b078e6be405f9cf54480b76c8e (patch) | |
tree | fe18b8cb2dadf6818dd2b4bc31ffaf33de55d627 /lib | |
parent | b36de9402e80140248c74ea2ce08f7db94375c66 (diff) | |
download | hashie-c071e4f9fdcd41b078e6be405f9cf54480b76c8e.tar.gz |
Add an extension to maintain original Mash keys (#326)
One of the behaviors of Mash that we see regularly surprise users is
that Mash stringifies any keys passed into it. This leads to unexpected
lack of synergy between Mash and its cousins (particularly Dash), since
the property DSLs do not handle indifferent key access.
This extension ensures that the original keys are kept inside the Mash's
data structure, at the expense of more costly logic for fetching
information indifferently. I have included a benchmark that compares the
two. The benchmark shows that when you are passing string keys into a
Mash, using this extension will actually be _faster_ than the default
implementation, but that the reverse is true when passing symbol keys.
In #296, I tried to do this universally for all Mashes, which slowed
down the fetching behavior for Mash significantly. I like this attempt
much better because it allows users to opt into the new behavior if they
want it, while still keeping the default implementation as-is.
Fixes #196 by giving the option of keeping the original structure of the
Mash when using it with Dash.
Fixes #246 by giving the option of opting into keeping the original
keys.
Closes #296 by giving a more flexible path forward that doesn't change
the semantics of the main Mash class.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/hashie.rb | 1 | ||||
-rw-r--r-- | lib/hashie/extensions/mash/keep_original_keys.rb | 54 | ||||
-rw-r--r-- | lib/hashie/mash.rb | 1 |
3 files changed, 56 insertions, 0 deletions
diff --git a/lib/hashie.rb b/lib/hashie.rb index 323f80f..b6e1d13 100644 --- a/lib/hashie.rb +++ b/lib/hashie.rb @@ -44,6 +44,7 @@ module Hashie end module Mash + autoload :KeepOriginalKeys, 'hashie/extensions/mash/keep_original_keys' autoload :SafeAssignment, 'hashie/extensions/mash/safe_assignment' autoload :SymbolizeKeys, 'hashie/extensions/mash/symbolize_keys' end diff --git a/lib/hashie/extensions/mash/keep_original_keys.rb b/lib/hashie/extensions/mash/keep_original_keys.rb new file mode 100644 index 0000000..1b529a7 --- /dev/null +++ b/lib/hashie/extensions/mash/keep_original_keys.rb @@ -0,0 +1,54 @@ +module Hashie + module Extensions + module Mash + # Overrides the indifferent access of a Mash to keep keys in the + # original format given to the Mash. + # + # @example + # class KeepingMash < Hashie::Mash + # include Hashie::Extensions::Mash::KeepOriginalKeys + # end + # + # mash = KeepingMash.new(:symbol_key => :symbol, 'string_key' => 'string') + # mash.to_hash #=> { :symbol_key => :symbol, 'string_key' => 'string' } + # mash['string_key'] == mash[:string_key] #=> true + # mash[:symbol_key] == mash['symbol_key'] #=> true + module KeepOriginalKeys + private + + def self.included(descendant) + unless descendant <= Hashie::Mash + fail ArgumentError, "#{descendant} is not a kind of Hashie::Mash" + end + end + + # Converts the key when necessary to access the correct Mash key. + # + # @param [Object, String, Symbol] key the key to access. + # @return [Object] the value assigned to the key. + def convert_key(key) + if regular_key?(key) + key + elsif (converted_key = __convert(key)) && regular_key?(converted_key) + converted_key + else + key + end + end + + # Converts symbol/string keys to their alternative formats, but leaves + # other keys alone. + # + # @param [Object, String, Symbol] key the key to convert. + # @return [Object, String, Symbol] the converted key. + def __convert(key) + case key + when Symbol then key.to_s + when String then key.to_sym + else key + end + end + end + end + end +end diff --git a/lib/hashie/mash.rb b/lib/hashie/mash.rb index b45ccce..cc8cb20 100644 --- a/lib/hashie/mash.rb +++ b/lib/hashie/mash.rb @@ -189,6 +189,7 @@ module Hashie self.class.new(self, default) end + alias_method :regular_key?, :key? def key?(key) super(convert_key(key)) end |