module Hash2obj

Hash2obj module

Public Class Methods

cast(hash, example) click to toggle source
# File lib/hash2obj.rb, line 5
def self.cast(hash, example)
  klass = example.class
  writable_attr = []
  potential_keyrest_args = example.instance_variables.inject({}) { |r, s|
    field = s.to_s.sub('@', '')
    if hash.key? field
      r.merge!({field.to_sym => hash[field.to_sym]})
    elsif example.respond_to?(field)
      r.merge!({field.to_sym => example.send(field)})
    end
    r
  }
  example.instance_variables.each do |attr|
    attr = attr.to_s.sub('@', '').to_sym
    if example.respond_to? ("#{attr}=")
      writable_attr << attr
    end
  end

  key_args = {}
  args = []
  construct_params = example.method(:initialize).parameters
  construct_params.each do |param|
    arg_required, arg_name = param
    potential_keyrest_args.delete "#{arg_name}".to_sym

    case arg_required
      when :req
        args << arg_name
      when :opt
        args << arg_name if hash.key? arg_name
      when :keyreq
        raise "parameter #{arg_name} is mandatory but missing in #{hash}" unless hash.key? arg_name
        key_args[arg_name] = hash[arg_name]
      when :keyrest
        key_args.merge! hash
        break
    end
  end

  key_args = potential_keyrest_args.merge(key_args)

  args.map! { |val| hash[val] || example.send(val) }

  if args.empty? and key_args.empty?
    instance = klass.send(:new)
  elsif args.empty?
    instance = klass.send(:new, key_args)
  elsif key_args.empty?
    instance = klass.send(:new, *args)
  else
    instance = klass.send(:new, *args, **key_args)
  end

  writable_attr.each do |attr|
    instance.send("#{attr}=", hash[attr]) if hash.key? attr
  end

  instance
end