Module: Faraday::NestedParamsEncoder

Extended by:
Forwardable
Defined in:
lib/faraday/parameters.rb

Class Method Summary collapse

Class Method Details

.decode(query) ⇒ Object


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/faraday/parameters.rb', line 66

def self.decode(query)
  return nil if query == nil

  params = {}
  query.split("&").each do |pair|
    next if pair.empty?
    key, value = pair.split("=", 2)
    key = unescape(key)
    value = unescape(value.gsub(/\+/, ' ')) if value

    subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
    context = params
    subkeys.each_with_index do |subkey, i|
      is_array = subkey =~ /[\[\]]+\Z/
      subkey = $` if is_array
      last_subkey = i == subkeys.length - 1

      if !last_subkey || is_array
        value_type = is_array ? Array : Hash
        if context[subkey] && !context[subkey].is_a?(value_type)
          raise TypeError, "expected %s (got %s) for param `%s'" % [
            value_type.name,
            context[subkey].class.name,
            subkey
          ]
        end
        context = (context[subkey] ||= value_type.new)
      end

      if context.is_a?(Array) && !is_array
        if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
          context << {}
        end
        context = context.last
      end

      if last_subkey
        if is_array
          context << value
        else
          context[subkey] = value
        end
      end
    end
  end

  dehash(params, 0)
end

.dehash(hash, depth) ⇒ Object

Internal: convert a nested hash with purely numeric keys into an array. FIXME: this is not compatible with Rack::Utils.parse_nested_query


117
118
119
120
121
122
123
124
125
126
127
# File 'lib/faraday/parameters.rb', line 117

def self.dehash(hash, depth)
  hash.each do |key, value|
    hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
  end

  if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
    hash.keys.sort.inject([]) { |all, key| all << hash[key] }
  else
    hash
  end
end

.encode(params) ⇒ Object


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/faraday/parameters.rb', line 10

def self.encode(params)
  return nil if params == nil

  if !params.is_a?(Array)
    if !params.respond_to?(:to_hash)
      raise TypeError,
        "Can't convert #{params.class} into Hash."
    end
    params = params.to_hash
    params = params.map do |key, value|
      key = key.to_s if key.kind_of?(Symbol)
      [key, value]
    end
    # Useful default for OAuth and caching.
    # Only to be used for non-Array inputs. Arrays should preserve order.
    params.sort!
  end

  # Helper lambda
  to_query = lambda do |parent, value|
    if value.is_a?(Hash)
      value = value.map do |key, val|
        key = escape(key)
        [key, val]
      end
      value.sort!
      buffer = ""
      value.each do |key, val|
        new_parent = "#{parent}%5B#{key}%5D"
        buffer << "#{to_query.call(new_parent, val)}&"
      end
      return buffer.chop
    elsif value.is_a?(Array)
      buffer = ""
      value.each_with_index do |val, i|
        new_parent = "#{parent}%5B%5D"
        buffer << "#{to_query.call(new_parent, val)}&"
      end
      return buffer.chop
    elsif value.nil?
      return parent
    else
      encoded_value = escape(value)
      return "#{parent}=#{encoded_value}"
    end
  end

  # The params have form [['key1', 'value1'], ['key2', 'value2']].
  buffer = ''
  params.each do |parent, value|
    encoded_parent = escape(parent)
    buffer << "#{to_query.call(encoded_parent, value)}&"
  end
  return buffer.chop
end