Module: Flatten::UtilityMethods
- Included in:
- Flatten
- Defined in:
- lib/flatten/utility_methods.rb
Overview
The Utility Methods provide a significant (~4x) performance increase over extend-ing instance methods everywhere we need them.
Instance Method Summary collapse
-
#expand(smash_hsh, smash_key, options = {}, &block) ⇒ Object
Given a smash hash, unflatten a subset by address, returning a *modified copy* of the original smash hash.
-
#expand!(smash_hsh, *args) ⇒ Object
Given a smash hash, unflatten a subset by address *in place* (@see Flatten::UtilityMethods#expand).
-
#smash(hsh, options = {}) ⇒ Hash<String,Object>
Returns a smash version of the given hash.
-
#smash_each(hsh, options = {}, &block) ⇒ Object
Provides a way to iterate through a deeply-nested hash as if it were a smash-hash.
-
#smash_fetch(hsh, smash_key, *args, &block) ⇒ Object
Fetch a smash key from the given deeply-nested hash.
-
#smash_get(hsh, smash_key, options = {}) ⇒ Object
Get a smash key from the given deeply-nested hash, or return nil if key not found.
-
#unsmash(hsh, options = {}) ⇒ Hash<String,Object>
Returns a deeply-nested version of the given smash hash.
Instance Method Details
#expand(smash_hsh, smash_key, options = {}, &block) ⇒ Object
Given a smash hash, unflatten a subset by address, returning a *modified copy* of the original smash hash.
~~~ ruby smash = => 2, ‘a.c.d’ => 4, ‘a.c.e’ => 3, ‘b.f’ => 4 Flatten::expand(smash, ‘a.c’) # => => 2, ‘a.c’ => {‘d’ => 4, ‘e’ => 3, ‘b.f’ => 4} ~~~
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/flatten/utility_methods.rb', line 147 def (smash_hsh, smash_key, *args) # if smash_hsh includes our key, its value is already expanded. return smash_hsh if smash_hsh.include?(smash_key) = (args.last.kind_of?(Hash) ? args.pop : {}) separator = .fetch(:separator, DEFAULT_SEPARATOR) pattern = /\A#{Regexp.escape(smash_key)}#{Regexp.escape(separator)}/i match = {} unmatch = {} smash_hsh.each do |k, v| if pattern =~ k sk = k.gsub(pattern, '') match[sk] = v else unmatch[k] = v end end unmatch.update(smash_key => unsmash(match, )) unless match.empty? unmatch end |
#expand!(smash_hsh, *args) ⇒ Object
Given a smash hash, unflatten a subset by address *in place* (@see Flatten::UtilityMethods#expand)
172 173 174 |
# File 'lib/flatten/utility_methods.rb', line 172 def (smash_hsh, *args) smash_hsh.replace (smash_hsh, *args) end |
#smash(hsh, options = {}) ⇒ Hash<String,Object>
Returns a smash version of the given hash
47 48 49 50 51 52 |
# File 'lib/flatten/utility_methods.rb', line 47 def smash(hsh, = {}) enum = smash_each(hsh, ) enum.each_with_object(Hash.new) do |(key, value), memo| memo[key] = value end end |
#smash_each(hsh, options = {}) {|| ... } ⇒ void #smash_each(hsh, options = {}) ⇒ Enumerator<(smash_key,value)>
Provides a way to iterate through a deeply-nested hash as if it were a smash-hash. Used internally for generating and deconstructing smash hashes.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/flatten/utility_methods.rb', line 22 def smash_each(hsh, = {}, &block) return enum_for(:smash_each, hsh, ) unless block_given? inherited_prefix = .fetch(:prefix, nil) separator = .fetch(:separator, DEFAULT_SEPARATOR) smash_array = .fetch(:smash_array, false) hsh.each do |partial_key, value| key = escaped_join(inherited_prefix, partial_key.to_s, separator) if value.kind_of?(Hash) && !value.empty? smash_each(value, .merge(prefix: key), &block) elsif smash_array && value.kind_of?(Array) && !value.empty? zps = (smash_array == :zero_pad ? "%0#{value.count.to_s.size}d" : '%d')# zero-pad string smash_each(value.count.times.map(&zps.method(:%)).zip(value), .merge(prefix: key), &block) else yield key, value end end end |
#smash_fetch(hsh, smash_key, default, options = {}) ⇒ Object #smash_fetch(hsh, smash_key, options = {}, &block) ⇒ Object #smash_fetch(hsh, smash_key, options = {}) ⇒ Object
Fetch a smash key from the given deeply-nested hash.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/flatten/utility_methods.rb', line 99 def smash_fetch(hsh, smash_key, *args, &block) = ( args.last.kind_of?(Hash) ? args.pop : {}) default = args.pop separator = .fetch(:separator, DEFAULT_SEPARATOR) escaped_split(smash_key, separator).reduce(hsh) do |memo, kp| if memo.kind_of?(Hash) and memo.has_key?(kp) memo.fetch(kp) elsif default return default elsif block_given? return yield else raise KeyError, smash_key end end end |
#smash_get(hsh, smash_key, options = {}) ⇒ Object
Get a smash key from the given deeply-nested hash, or return nil if key not found.
Worth noting is that Hash#default_proc is not used, as the intricacies of implementation would lead to all sorts of terrible surprises.
128 129 130 |
# File 'lib/flatten/utility_methods.rb', line 128 def smash_get(hsh, smash_key, = {}) smash_fetch(hsh, smash_key, ) { nil } end |
#unsmash(hsh, options = {}) ⇒ Hash<String,Object>
Returns a deeply-nested version of the given smash hash
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/flatten/utility_methods.rb', line 58 def unsmash(hsh, = {}) separator = .fetch(:separator, DEFAULT_SEPARATOR) hsh.each_with_object({}) do |(k, v), memo| current = memo key = escaped_split(k, separator) puts "key: #{key}" up_next = partial = key.shift until key.size.zero? up_next = key.shift up_next = up_next.to_i if (up_next =~ /\A[0-9]+\Z/) current = (current[partial] ||= (up_next.kind_of?(Integer) ? [] : {})) case up_next when Integer then raise KeyError unless current.kind_of?(Array) else raise KeyError unless current.kind_of?(Hash) end partial = up_next end current[up_next] = v end end |