Skip to content
Browse files

Recursively convert nested hash to flat parameters hash for POST. Add…

… corresponding tests.
  • Loading branch information...
1 parent 8f9deb2 commit ad492def1298956730fde2f50c5117bd2fb8270c @pmahoney committed Nov 4, 2011
Showing with 105 additions and 10 deletions.
  1. +54 −10 lib/capybara/mechanize/browser.rb
  2. +51 −0 spec/browser/mechanize_browser_spec.rb
View
64 lib/capybara/mechanize/browser.rb
@@ -98,6 +98,9 @@ def get(path, attributes = {}, headers = {})
alias :racktest_post :post
def post(path, attributes = {}, headers = {})
+ puts "Posting data: "
+ puts post_data(attributes)
+
process_without_redirect(:post, path, post_data(attributes), headers)
end
@@ -111,18 +114,59 @@ def delete(path, attributes = {}, headers = {})
process_without_redirect(:delete, path, attributes, headers)
end
- def post_data(params)
- params.inject({}) do |memo, param|
- case param
- when Hash
- param.each {|attribute, value| memo[attribute] = value }
- memo
- when Array
- case param.last
+ # Convert a deep hash of parameters recursively into a one-level
+ # hash in the style of Rails where nested hashes become long keys
+ # with secondary keys enclosed in square brackets.
+ #
+ # No attempt is make to prevent duplicate keys. For example, if
+ # there is a toplevel key of 'a[b][c]' and also an identical
+ # expanded key, the value will be that of whichever was encountered
+ # last according to the order of iteration through the hash
+ # (i.e. unspecified).
+ #
+ # For example,
+ #
+ # {
+ # 'a' => 1,
+ # 'b' => {
+ # 'c' => 1,
+ # 'd' => { 'e' => 1, 'f' => 2 }
+ # }
+ # }
+ #
+ # becomes
+ #
+ # {
+ # 'a' => 1,
+ # 'b[c]' => 1,
+ # 'b[d][e]' => 1,
+ # 'b[d][f]' => 2
+ # }
+ #
+ # @param [Hash] params a possibly deep hash of parameters (with no
+ # circular references). Can also be an array of hashes in which
+ # case the hashes will be effectively merged prior to conversion.
+ #
+ # @param [Proc] make_key a procedure for making the expanded key
+ # given the key at this level
+ #
+ # @param [Hash] acc the hash with expanded keys
+ def post_data(params, make_key = proc {|k| k}, acc = {})
+ case params
+ when Array
+ params.each { |p| post_data(p, make_key, acc) }
+ acc
+ when Hash
+ params.inject(acc) do |memo, keyval|
+ key, val = keyval
+
+ case val
when Hash
- param.last.each {|attribute, value| memo["#{param.first}[#{attribute}]"] = value }
+ post_data(val,
+ proc { |k| make_key.call(key) + '[' + k + ']' },
+ memo)
else
- memo[param.first] = param.last
+ memo[make_key.call(key)] = val
end
memo
end
View
51 spec/browser/mechanize_browser_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe Capybara::Mechanize::Browser do
+
+ describe '#post_data' do
+
+ before(:each) do
+ @browser = Capybara::Mechanize::Browser.new(nil)
+ end
+
+ # Hash#to_a sorted by key
+ def normalize(hash)
+ hash.to_a.sort { |a,b| a[0] <=> b[0] }
+ end
+
+ it 'converts simple hash' do
+ params = {
+ 'k1' => 'v1',
+ 'k2' => 'v2'
+ }
+
+ normalize(@browser.post_data(params)).should ==
+ [['k1', 'v1'], ['k2', 'v2']]
+ end
+
+ it 'converts triply nested hash' do
+ params = {
+ 'a' => 1,
+ 'b' => {
+ 'c' => 1,
+ 'd' => { 'e' => 1, 'f' => 2 }
+ }
+ }
+
+ normalize(@browser.post_data(params)).should ==
+ [['a', 1],
+ ['b[c]', 1],
+ ['b[d][e]', 1],
+ ['b[d][f]', 2]]
+ end
+
+ it 'converts array of hashes' do
+ params = [ { 'a' => 1 }, { 'b' => 2 } ]
+
+ normalize(@browser.post_data(params)).should ==
+ [['a', 1], ['b', 2]]
+ end
+
+ end
+
+end

0 comments on commit ad492de

Please sign in to comment.
Something went wrong with that request. Please try again.