lib/config_volumizer/parser.rb in config_volumizer-0.2.0 vs lib/config_volumizer/parser.rb in config_volumizer-0.3.0

- old
+ new

@@ -1,7 +1,8 @@ require 'strscan' require 'yaml' +require 'csv' module ConfigVolumizer module Parser class << self @@ -11,79 +12,83 @@ # # See Readme for an example # # @param [Hash] source # @param [String] base_name + # @param [Hash] mapping # @return [Hash] - def parse(source, base_name) + def parse(source, mapping) result = {} - source.each do |key, value| - if matches_name(base_name, key) - fragments = key.gsub(/^#{base_name}/, '') - handle_item(result, base_name, fragments, value) + mapping.each do |mapping_key, mapping_info| + source.each do |key, value| + if matches_name(mapping_key, key) + handle_item(result, key, value, mapping_key, mapping_info) + end end end result end private def matches_name(base_name, key) - key == base_name || key =~ /^#{base_name}([.\[])/ + key == base_name || key =~ /^#{base_name}_/ end def format_value(value) YAML.load(value) end - def initialize_array(result, key) - validate_result_key_kind(result, key, Array) - result[key] ||= [] + def format_array_value(value) + CSV.parse_line(value).map { |inner_value| format_value(inner_value) } end - def initialize_hash(result, key) - validate_result_key_kind(result, key, Hash) - result[key] ||= {} + def handle_item(result, name, value, mapping_key, mapping_info) + case mapping_info + when Array + handle_array_item(mapping_info, mapping_key, name, result, value) + when Hash + handle_hash_item(mapping_info, mapping_key, name, result, value) + when :value + result[mapping_key] = format_value(value) + when :hash + new_name = name.gsub(/^#{mapping_key}_/, '') + result[mapping_key] ||= {} + result[mapping_key][new_name] = format_value(value) + else + raise ArgumentError, "don't know how to deal with #{mapping_info.inspect}" + end + end - def validate_result_key_kind(result, key, kind) - if result[key] && !result[key].kind_of?(kind) - raise ArgumentError, "referencing #{kind} key #{name} when its already a #{result[key].class}" + def handle_hash_item(mapping_info, mapping_key, name, result, value) + result[mapping_key] ||= {} + new_name = name.gsub(/^#{mapping_key}_/, '') + mapping_info.each do |inner_mapping_key, inner_mapping_info| + if matches_name(inner_mapping_key, new_name) + handle_item(result[mapping_key], new_name, value, inner_mapping_key, inner_mapping_info) + end end end - def handle_item(result, base_name, name, value) - dst, key = result, base_name - scanner = StringScanner.new(name) - - until scanner.eos? - dst, key = case next_fragment(scanner) - when /^\.(.+)/ - handle_hash($~, dst, key) - when /\[(\d+)\]/ - handle_array($~, dst, key) - end + def handle_array_item(mapping_info, mapping_key, name, result, value) + result[mapping_key] ||= [] + mapping_info.each do |inner_mapping_info| + case inner_mapping_info + when :value + result[mapping_key] += format_array_value(value) + when :hash, Hash + handle_array_hash_item(inner_mapping_info, mapping_key, name, result, value) + else + raise "don't know how to handle: #{inner_mapping_info.inspect}" + end end - - dst[key] = format_value(value) end - def handle_array(match, dst, key) - index = match[1].to_i - initialize_array(dst, key) - return dst[key], index - end - - def handle_hash(match, dst, key) - hash_key = match[1] - initialize_hash(dst, key) - return dst[key], hash_key - end - - def next_fragment(scanner) - fragment = scanner.scan /\.[^.\[]+|\[\d+\]/ - raise "failed: rest: #{scanner.rest} inside #{scanner.string}" unless fragment - fragment + def handle_array_hash_item(inner_mapping_info, mapping_key, name, result, value) + new_name = name.gsub(/^#{mapping_key}_(\d+)(?:_)?/, '') + index = $~[1].to_i + handle_item(result[mapping_key], new_name, value, index, inner_mapping_info) end end end end