class ReeObject::ToObj

def build_array(array)

def build_array(array)
  array.map do |value|
    if value.is_a?(Array)
      build_array(value)
    elsif value.is_a?(Hash)
      recursively_assign(Object.new, value)
    else
      value
    end
  end
end

def call(obj, **opts)

def call(obj, **opts)
  dump = as_json(obj)
  options = prepare_options(opts)
  if opts[:include]
    dump = slice(dump, options[:include])
  end
  if opts[:exclude]
    dump = except(dump, options[:exclude])
  end
  if opts[:global_exclude]
    dump = except(dump, global_except: options[:global_exclude])
  end
  ancestors = dump.class.ancestors
  return dump if ancestors.intersection(BASIC_TYPES).size > 0
    
  if dump.is_a?(Array)
    build_array(dump)
  else
    recursively_assign(Object.new, dump)
  end
end

def opts_keys(arr)

def opts_keys(arr)
  arr.reject { |e| e.is_a?(Hash) }
end

def prepare_options(opts)

def prepare_options(opts)
  if opts[:include] && (opts[:exclude] || opts[:global_exclude])
    intersection = opts_keys(opts[:include]).intersection(opts_keys(opts[:exclude] || opts[:global_exclude]))
    if intersection.length > 0
      raise ArgumentError, "Exclude and include have the same values: #{intersection}"
    end
  end
  opts
end

def recursively_assign(obj, hash)

def recursively_assign(obj, hash)
  hash.each do |key, value|
    var = :"@#{key}"
    obj.define_singleton_method key do 
      instance_variable_get(var)
    end
    if value.is_a?(Array)
      obj.instance_variable_set(var, build_array(value))
    elsif value.is_a?(Hash)
      obj.instance_variable_set(var, recursively_assign(Object.new, value))
    else
      obj.instance_variable_set(var, value)
    end
  end
  
  obj
end