Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions lib/http/form_data/urlencoded.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,45 @@ def encoder=(implementation)
end

# Returns form data encoder implementation.
# Default: `URI.encode_www_form`.
# Default: custom realization.
#
# @see .encoder=
# @return [#call]
def encoder
@encoder ||= ::URI.method(:encode_www_form)
@encoder ||= DefaultEncoder.method(:encode)
end

# Default encoder
module DefaultEncoder
class << self
def encode(value, prefix = nil)
case value
when Hash
encode_hash(value, prefix)
when Array
value.map { |v| encode(v, "#{prefix}[]") }.join("&")
when nil then prefix.to_s
else
raise ArgumentError, "value must be a Hash" if prefix.nil?
"#{prefix}=#{escape(value)}"
end
end

private

def encode_hash(hash, prefix)
hash.map do |k, v|
encode(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
end.reject(&:empty?).join("&")
end

def escape(value)
URI.encode_www_form_component(value)
end
end
end

private_constant :DefaultEncoder
end

# @param [#to_h, Hash] data form data key-value Hash
Expand Down
15 changes: 13 additions & 2 deletions spec/lib/http/form_data/urlencoded_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
it { is_expected.to eq "foo%5Bbar%5D=%D1%82%D0%B5%D1%81%D1%82" }
end

context "with nested hashes" do
let(:data) { { "foo" => { "bar" => "test" } } }
it { is_expected.to eq "foo[bar]=test" }
end

it "rewinds content" do
content = form_data.read
expect(form_data.to_s).to eq content
Expand Down Expand Up @@ -57,8 +62,14 @@
end

describe ".encoder=" do
before { described_class.encoder = ::JSON.method(:dump) }
after { described_class.encoder = ::URI.method(:encode_www_form) }
before do
@original_encoder = described_class.encoder
described_class.encoder = ::JSON.method(:dump)
end

after do
described_class.encoder = @original_encoder
end

it "switches form encoder implementation" do
expect(form_data.to_s).to eq('{"foo[bar]":"test"}')
Expand Down