53 lines
1.8 KiB
Ruby
53 lines
1.8 KiB
Ruby
# Transform a nested tructure indicated by dots to a structure as used by the ActiveRecord includes statement
|
|
# - dslams
|
|
# - ppls.distribution_cables
|
|
# =>
|
|
# [:dslams, {ppls: :distribution_cables}]
|
|
class FlatKeys
|
|
class << self
|
|
|
|
def as_nested_structure(ary)
|
|
return ary unless ary.first.is_a?(String)
|
|
nested_keys, flat_keys = ary.partition{|spec| spec['.']}
|
|
result = flat_keys.map(&:to_sym)
|
|
if nested_keys.any?
|
|
obj = {}
|
|
nested_keys.map{ |key| key.split('.').map(&:to_sym) }.each do |parts|
|
|
traverse_nest_structure(parts, obj)
|
|
end
|
|
result -= obj.keys
|
|
result.push obj
|
|
end
|
|
result
|
|
end
|
|
|
|
def traverse_nest_structure(parts, obj)
|
|
key = parts.shift
|
|
if parts.size == 1
|
|
case obj[key]
|
|
when nil then obj[key] = parts[0]
|
|
when Array then obj[key] |= [parts[0]]
|
|
when Hash
|
|
raise "Colliding keys for nesting of #{key} -> #{parts[0]}" unless obj[key].has_key?(parts[0])
|
|
else # expect symbol
|
|
obj[key] = Array.wrap(obj[key]).push parts[0] unless obj[key] == parts[0] # no duplicate
|
|
end
|
|
else # parts.size > 2
|
|
case obj[key]
|
|
when nil
|
|
obj[key] = {}
|
|
traverse_nest_structure(parts, obj[key])
|
|
when Array
|
|
raise "Cannot traverse #{key} -> #{parts.join('.')} because existing array value #{obj[key].inspect}"
|
|
when Hash
|
|
traverse_nest_structure(parts, obj[key])
|
|
else # expect symbol
|
|
raise "Cannot add deeper nesting for endpoing with different name #{key} -> #{obj[key]} => #{parts.join('.')}" unless obj[key] = parts[0] # same name, allows deeper nesting
|
|
obj[key] = {obj[key] => nil} # prepare for nesting
|
|
traverse_nest_structure(parts, obj[key])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|