Module: Locallingo::KeyFlattener
- Defined in:
- lib/locallingo/key_flattener.rb
Overview
Converts between nested locale hashes (as loaded from YAML) and the flat dotted-key representation the engine works in, and back.
Flat keys use dot notation with bracket indices for arrays, e.g.
items[0].name. This is a faithful extraction of the algorithms that lived
in TranslationManager (flatten_hash / parse_key_segments / set_nested_value /
navigate_or_create) so the round-trip behavior is byte-identical.
Class Method Summary collapse
- .ensure_array_size(array, index) ⇒ Object
-
.flatten(hash, prefix = "") ⇒ Object
Flatten a nested hash to
{ "a.b.c" => "value" }. -
.navigate_or_create(current, segment) ⇒ Object
Navigate to or create the appropriate container (hash or array) for a segment.
-
.parse_key_segments(key) ⇒ Object
Parse a flattened key into segments, handling both dot notation and bracket indices.
-
.set_nested_value(hash, key, value) ⇒ Object
Set a flattened
keytovalueinside the nestedhash, creating intermediate hashes/arrays as needed.
Class Method Details
.ensure_array_size(array, index) ⇒ Object
110 111 112 |
# File 'lib/locallingo/key_flattener.rb', line 110 def ensure_array_size(array, index) array << nil while array.size <= index end |
.flatten(hash, prefix = "") ⇒ Object
Flatten a nested hash to { "a.b.c" => "value" }. Arrays are indexed with
bracket notation. Only leaf values are kept; the caller decides which types
to retain.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/locallingo/key_flattener.rb', line 17 def flatten(hash, prefix = "") result = {} hash.each do |key, value| full_key = prefix.empty? ? key.to_s : "#{prefix}.#{key}" case value when Hash result.merge!(flatten(value, full_key)) when Array value.each_with_index do |item, i| if item.is_a?(String) result["#{full_key}[#{i}]"] = item elsif item.is_a?(Hash) result.merge!(flatten(item, "#{full_key}[#{i}]")) end end else result[full_key] = value end end result end |
.navigate_or_create(current, segment) ⇒ Object
Navigate to or create the appropriate container (hash or array) for a segment.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/locallingo/key_flattener.rb', line 92 def navigate_or_create(current, segment) if segment[:index] if segment[:key] current[segment[:key]] ||= [] ensure_array_size(current[segment[:key]], segment[:index]) current[segment[:key]][segment[:index]] ||= {} current[segment[:key]][segment[:index]] else ensure_array_size(current, segment[:index]) current[segment[:index]] ||= {} current[segment[:index]] end else current[segment[:key]] ||= {} current[segment[:key]] end end |
.parse_key_segments(key) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/locallingo/key_flattener.rb', line 62 def parse_key_segments(key) segments = [] parts = key.split(".") parts.each do |part| if part =~ /^([^\[]*)\[(\d+)\](.*)$/ base_key = ::Regexp.last_match(1) index = ::Regexp.last_match(2).to_i remainder = ::Regexp.last_match(3) segments << if base_key.empty? { key: nil, index: } else { key: base_key, index: } end while remainder =~ /^\[(\d+)\](.*)$/ segments << { key: nil, index: ::Regexp.last_match(1).to_i } remainder = ::Regexp.last_match(2) end else segments << { key: part, index: nil } end end segments end |
.set_nested_value(hash, key, value) ⇒ Object
Set a flattened key to value inside the nested hash, creating
intermediate hashes/arrays as needed.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/locallingo/key_flattener.rb', line 41 def set_nested_value(hash, key, value) segments = parse_key_segments(key) current = hash segments[0..-2].each do |segment| current = navigate_or_create(current, segment) end final_segment = segments.last if final_segment[:index] current[final_segment[:key]] ||= [] current[final_segment[:key]][final_segment[:index]] = value else current[final_segment[:key]] = value end end |