module TranslationIO::FlatHash

Public Class Methods

to_flat_hash(hash) click to toggle source
# File lib/translation_io/flat_hash.rb, line 4
def to_flat_hash(hash)
  hash = brackets_to_joker!(hash)
  hash = remove_reserved_keys!(hash)
  get_flat_hash_for_level(hash)
end
to_hash(flat_hash, remove_empty_keys = false) click to toggle source
# File lib/translation_io/flat_hash.rb, line 10
def to_hash(flat_hash, remove_empty_keys = false)
  hash = {}

  if remove_empty_keys
    flat_hash = flat_hash.reject { |k, v| v.blank? && !k.end_with?(']') }
  end

  flat_hash.each_pair do |key, value|
    build_hash_with_flat(hash, key, value)
  end

  joker_to_brackets!(hash)
end

Private Class Methods

brackets_to_joker!(h) click to toggle source
# File lib/translation_io/flat_hash.rb, line 118
def brackets_to_joker!(h)
  gsub_keys!(h, '[', ']', '<@~<', '>@~>')
end
build_hash_with_flat(hash, key_string, value) click to toggle source
# File lib/translation_io/flat_hash.rb, line 26
def build_hash_with_flat(hash, key_string, value)
  current_object = hash
  splitted       = key_string.split(/\.|\[/, 2)
  current_key    = splitted[0] # first is always a hash
  key_string     = splitted[1]

  if key_string.blank? # if only one key like { 'en' => 'salut' }
    current_object[current_key] = value
  else
    # Put back '[' if needed
    if key_string.count(']') > key_string.count('[')
      key_string = '[' + key_string
    end

    while key_string != '' && !current_object.is_a?(String) && !current_object.nil?
      # Next is array
      if key_string[0] == '['
        array_pos = key_string.split(']', 2)[0]
        array_pos = array_pos.split('[', 2)[1].to_i

        key_string = key_string.split(']', 2).count == 2 ? key_string.split(']', 2)[1] : ""
        key_string = key_string[1..-1] if key_string[0] == '.'

        if no_key?(current_object, current_key)
          current_object[current_key] = []
        end

        current_object = current_object[current_key]
        current_key    = array_pos

        # array is terminal
        if key_string == ''
          current_object[array_pos] = value if current_object.is_a?(Array)
        end
      # next is hash
      elsif key_string[0] != '[' && (key_string.include?('.') || key_string.include?('['))
        splitted   = key_string.split(/\.|\[/, 2)
        new_key    = splitted[0]
        key_string = splitted[1]

        # Put back '[' if needed
        if key_string.count(']') > key_string.count('[')
          key_string = '[' + key_string
        end

        if no_key?(current_object, current_key)
          current_object[current_key] = {}
        end
        current_object = current_object[current_key]
        current_key    = new_key
      # next (last) is value
      else
        new_key = key_string

        if no_key?(current_object, current_key)
          current_object[current_key] = {}
        end
        current_object          = current_object[current_key]
        current_object[new_key] = value if current_object.is_a?(Hash)

        key_string = ''
      end
    end
  end
end
get_flat_hash_for_level(value, parent_key = nil) click to toggle source
# File lib/translation_io/flat_hash.rb, line 99
def get_flat_hash_for_level(value, parent_key = nil)
  flat_hash = {}

  if value.is_a? Hash
    value.each_pair do |key, value|
      current_level_key = [ parent_key, key ].reject(&:blank?).join('.')
      flat_hash.merge!(get_flat_hash_for_level(value, current_level_key))
    end
  elsif value.is_a? Array
    value.each_with_index do |item, index|
      flat_hash.merge!(get_flat_hash_for_level(item, "#{parent_key}[#{index}]"))
    end
  else
    flat_hash[parent_key] = value
  end

  flat_hash
end
gsub_keys!(h, from_1, from_2, to_1, to_2) click to toggle source
# File lib/translation_io/flat_hash.rb, line 126
def gsub_keys!(h, from_1, from_2, to_1, to_2)
  if h.is_a?(Hash)
    h.keys.each do |key|
      if key.to_s.include?(from_1) || key.to_s.include?(from_2)
        new_key = key.to_s.gsub(from_1, to_1).gsub(from_2, to_2)
      else
        new_key = key
      end
      h[new_key] = h.delete(key)
      gsub_keys!(h[new_key], from_1, from_2, to_1, to_2)
    end
  elsif h.respond_to?(:each)
    h.each { |e| gsub_keys!(e, from_1, from_2, to_1, to_2) }
  end
  h
end
joker_to_brackets!(h) click to toggle source
# File lib/translation_io/flat_hash.rb, line 122
def joker_to_brackets!(h)
  gsub_keys!(h, '<@~<', '>@~>', '[', ']')
end
no_key?(array_or_hash, key) click to toggle source
# File lib/translation_io/flat_hash.rb, line 92
def no_key?(array_or_hash, key)
  is_a_hash_without_key   = array_or_hash.is_a?(Hash)  && (!array_or_hash.has_key?(key) || array_or_hash[key] == nil)
  is_an_array_without_key = array_or_hash.is_a?(Array) && array_or_hash[key] == nil

  is_a_hash_without_key || is_an_array_without_key
end
remove_reserved_keys!(h) click to toggle source
# File lib/translation_io/flat_hash.rb, line 143
def remove_reserved_keys!(h)
  if h.is_a?(Hash)
    h.keys.each do |key|
      if [TrueClass, FalseClass].include?(key.class)
        # # This warning is commented because Rails admin uses bad keys: https://github.com/sferik/rails_admin/blob/master/config/locales/rails_admin.en.yml
        # TranslationIO.info("Warning - We found some YAML protected keys in your project, they will not be synchronized: 'yes', 'no', 'y', 'n', 'on', 'off', 'true', 'false'")
        # TranslationIO.info(h.inspect)
        h.delete(key)
      else
        remove_reserved_keys!(h[key])
      end
    end
  elsif h.respond_to?(:each)
    h.each { |e| remove_reserved_keys!(e) }
  end
  h
end