lib/quick_travel/init_from_hash.rb
module QuickTravel
module InitFromHash
def initialize(hash = {})
return nil if hash.blank?
define_readers(hash.keys)
Parser.new(hash).parsed_attributes.each do |attr, val|
# set datamember of the object using hash key and value
if respond_to?("#{attr}=")
send("#{attr}=", val)
else
instance_variable_set("@#{attr}".to_sym, val)
end
end
end
def define_readers(keys)
keys.each do |key|
next if respond_to?(key)
define_singleton_method(key) { instance_variable_get("@#{key}") }
if key.to_s.ends_with? '_cents'
name = key.to_s.gsub(/_in_cents$/, '')
define_singleton_method(name) {
cents = instance_variable_get("@#{key}")
return nil unless cents
Money.new(cents)
}
end
end
end
def to_hash
instance_values
end
end
class Parser
def initialize(attributes)
@attributes = attributes
end
def attributes
@attributes ||= {}
end
def parsed_attributes
@parsed_attributes ||= parse_attributes
end
private
def parse_attributes
attributes.map.with_object({}) do |(attribute, value), hash|
hash[attribute] = parse(attribute, value)
end
end
def parse(attribute, value)
return nil if value.nil?
return convert(value, :to_date) if attribute.to_s.ends_with?('_date')
return convert(value, :to_date) if attribute.to_s.ends_with?('_on')
# to_datetime as it converts to app time zone, to_time converts to system time zone
return convert(value, :to_datetime) if attribute.to_s.ends_with?('_time')
return convert(value, :to_datetime) if attribute.to_s.ends_with?('_at')
value
end
def convert(value, conversion_method)
convertable_value = value.is_a?(Hash) ? value['_value'] : value
convertable_value.try(conversion_method) || convertable_value
end
end
end