lib/light_mapper.rb in light_mapper-0.0.2 vs lib/light_mapper.rb in light_mapper-1.0.4
- old
+ new
@@ -1,29 +1,78 @@
require 'light_mapper/version'
module LightMapper
- def mapping(mappings, opts = {})
- LightMapper.mapping(clone, mappings, opts)
- end
+ InvalidKey = Class.new(StandardError)
+ KeyMissing = Class.new(StandardError)
- def self.mapping(hash, mappings, opts = {})
- require_keys = opts[:require_keys] == true
- any_keys_kind = opts[:any_keys_kind] == true
- fetch_method = if any_keys_kind
- if require_keys
- -> (hash, key) { hash.fetch(key.to_s, hash.fetch(key.to_sym)) }
+ module Helper
+ def self.raise_key_missing(current, full_path, additional_message = nil)
+
+ raise KeyMissing, ["#{current} key not found; Full path #{full_path.map(&:to_s).join('.')}", additional_message].compact.join('; ')
+ end
+
+ def self.key_destructor(value)
+ case value
+ in String
+ value.split('.')
+ in Symbol
+ [value]
+ in Array
+ value
else
- -> (hash, key) { hash[key.to_s] || hash[key.to_sym] }
+ raise InvalidKey, "Invalid key type: #{value.class}"
end
- else
- if require_keys
- -> (hash, key) { hash.fetch(key) }
+ end
+
+ def self.value_extractor(object, current, path, full_path, strict = false, any_keys = false)
+ result = case object
+ in Hash
+ hash_key_extractor(object, current, full_path, strict, any_keys)
+ in Array
+ array_key_extractor(object, current, full_path, strict, any_keys)
+ in NilClass
+ nil
+ else
+ method_name = current.to_s.to_sym
+ object.respond_to?(method_name) ? object.send(method_name) : !strict ? nil : raise_key_missing(current, full_path)
+ end
+
+ path.compact.empty? ? result : value_extractor(result, path.first, path[1..-1], full_path, strict, any_keys)
+ end
+
+ def self.hash_key_extractor(object, current, full_path, strict, any_keys)
+ keys = any_keys ? [current, current.to_s, current.to_s.to_sym] : [current]
+ raise_key_missing(current, full_path) if strict && !keys.any? { |k| object.key?(k) }
+
+ object.values_at(*keys).compact.first
+ end
+
+ def self.array_key_extractor(object, current, full_path, strict, _any_keys)
+ index = current.to_s.match(/^(\d)+$/) ? current.to_i : nil
+
+ if index
+ raise_key_missing(current, full_path) if strict && index && object.size < index.next
+
+ object[index]
else
- -> (hash, key) { hash[key] }
+ method_name = current.to_s.to_sym
+ raise_key_missing(current, full_path, "Array do not respond on #{method_name}") if strict && !object.respond_to?(method_name)
+
+ object.public_send(method_name)
end
end
+ end
- {}.tap do |h|
- mappings.each { |k, v| h[v] = fetch_method.call(hash, k) }
+ def mapping(mappings, opts = {})
+ LightMapper.mapping(clone, mappings, opts)
+ end
+
+ def self.mapping(hash, mappings, opts = {})
+ strict, any_keys = opts.values_at(:strict, :any_keys)
+ mappings.each_with_object({}) do |(k, v), h|
+ next h[v] = k.call(hash) if k.is_a?(Proc)
+
+ key_path = Helper.key_destructor(k)
+ h[v] = Helper.value_extractor(hash, key_path.first, key_path[1..-1], key_path, strict, any_keys)
end
end
end