Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 6481

Show
Ignore:
Timestamp:
03/27/07 20:55:56 (2 years ago)
Author:
madrobby
Message:

Make Hash.toQueryString serialize undefined values. Ensure consistency with String.prototype.toQueryParams. Closes #7806. [Mislav Marohnic]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • spinoffs/prototype/trunk/CHANGELOG

    r6478 r6481  
    11*SVN* 
    22 
     3* Make Hash.toQueryString serialize undefined values. Ensure consistency with String.prototype.toQueryParams.  Closes #7806.  [Mislav Marohnić] 
     4  Examples: 
     5    $H({a:'b',c:undefined}).toQueryString()      -> 'a=b&c' 
     6    $H({a:'b',c:null}).toQueryString()           -> 'a=b&c=' 
     7    $H('a=b&c'.toQueryParams()).toQueryString()  -> 'a=b&c' 
     8    $H('a=b&c='.toQueryParams()).toQueryString() -> 'a=b&c=' 
     9     
    310* Fix issues with Selector an+b logic, :not support, attribute selector double quotes, plus performance improvements.  Closes #7873, #7901.  [Andrew Dupont] 
    411 
  • spinoffs/prototype/trunk/src/hash.js

    r6368 r6481  
    3636 
    3737Hash.toQueryString.addPair = function(key, value, prefix) { 
    38   if (value == null) return; 
    3938  key = encodeURIComponent(key); 
    40   this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); 
     39  if (value === undefined) this.push(key); 
     40  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); 
    4141} 
    4242 
  • spinoffs/prototype/trunk/src/string.js

    r6473 r6481  
    9696    return match[1].split(separator || '&').inject({}, function(hash, pair) { 
    9797      if ((pair = pair.split('='))[0]) { 
    98         var name = decodeURIComponent(pair[0]); 
    99         var value = pair[1] ? decodeURIComponent(pair[1]) : undefined
    100  
    101         if (hash[name] !== undefined) { 
    102           if (hash[name].constructor != Array) 
    103             hash[name] = [hash[name]]; 
    104           if (value) hash[name].push(value); 
     98        var key = decodeURIComponent(pair.shift()); 
     99        var value = pair.length > 1 ? pair.join('=') : pair[0]
     100        if (value != undefined) value = decodeURIComponent(value); 
     101         
     102        if (key in hash) { 
     103          if (hash[key].constructor != Array) hash[key] = [hash[key]]; 
     104          hash[key].push(value); 
    105105        } 
    106         else hash[name] = value; 
     106        else hash[key] = value; 
    107107      } 
    108108      return hash; 
  • spinoffs/prototype/trunk/test/lib/unittest.js

    r6366 r6481  
    304304    catch(e) { this.error(e); } 
    305305  }, 
     306  assertNotEqual: function(expected, actual) { 
     307    var message = arguments[2] || "assertNotEqual"; 
     308    try { (expected != actual) ? this.pass() :  
     309      this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } 
     310    catch(e) { this.error(e); } 
     311  }, 
    306312  assertEnumEqual: function(expected, actual) { 
    307313    var message = arguments[2] || "assertEnumEqual"; 
     
    314320    catch(e) { this.error(e); } 
    315321  }, 
    316   assertNotEqual: function(expected, actual) { 
    317     var message = arguments[2] || "assertNotEqual"; 
    318     try { (expected != actual) ? this.pass() :  
    319       this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } 
     322  assertEnumNotEqual: function(expected, actual) { 
     323    var message = arguments[2] || "assertEnumEqual"; 
     324    expected = $A(expected); 
     325    actual = $A(actual); 
     326    try { expected.length != actual.length ||  
     327      expected.zip(actual).any(function(pair) { return pair[0] != pair[1] }) ? 
     328        this.pass() : this.fail(message + ': ' + Test.Unit.inspect(expected) +  
     329          ' was the same as ' + Test.Unit.inspect(actual)); } 
     330    catch(e) { this.error(e); } 
     331  }, 
     332  assertHashEqual: function(expected, actual) { 
     333    var message = arguments[2] || "assertHashEqual"; 
     334    expected = $H(expected); 
     335    actual = $H(actual); 
     336    var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort(); 
     337    // from now we recursively zip & compare nested arrays 
     338    try { expected_array.length == actual_array.length &&  
     339      expected_array.zip(actual_array).all(function(pair) { 
     340        return pair.all(function(i){ return i && i.constructor == Array }) ? 
     341          pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1]; 
     342      }) ? 
     343        this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +  
     344          ', actual ' + Test.Unit.inspect(actual)); } 
     345    catch(e) { this.error(e); } 
     346  }, 
     347  assertHashNotEqual: function(expected, actual) { 
     348    var message = arguments[2] || "assertHashEqual"; 
     349    expected = $H(expected); 
     350    actual = $H(actual); 
     351    var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort(); 
     352    // from now we recursively zip & compare nested arrays 
     353    try { !(expected_array.length == actual_array.length &&  
     354      expected_array.zip(actual_array).all(function(pair) { 
     355        return pair.all(function(i){ return i && i.constructor == Array }) ? 
     356          pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1]; 
     357      })) ? 
     358        this.pass() : this.fail(message + ': ' + Test.Unit.inspect(expected) +  
     359          ' was the same as ' + Test.Unit.inspect(actual)); } 
    320360    catch(e) { this.error(e); } 
    321361  }, 
     
    373413    var message = arguments[2] || 'assertMatch'; 
    374414    var regex = new RegExp(expected); 
    375     try { (regex.exec(actual)) ? this.pass() : 
     415    try { regex.exec(actual) ? this.pass() : 
    376416      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); } 
     417    catch(e) { this.error(e); } 
     418  }, 
     419  assertNoMatch: function(expected, actual) { 
     420    var message = arguments[2] || 'assertMatch'; 
     421    var regex = new RegExp(expected); 
     422    try { !regex.exec(actual) ? this.pass() : 
     423      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' matched: ' + Test.Unit.inspect(actual) + '"'); } 
    377424    catch(e) { this.error(e); } 
    378425  }, 
     
    380427    var message = arguments[1] || 'assertHidden'; 
    381428    this.assertEqual("none", element.style.display, message); 
    382   }, 
    383   assertNotNull: function(object) { 
    384     var message = arguments[1] || 'assertNotNull'; 
    385     this.assert(object != null, message); 
    386429  }, 
    387430  assertInstanceOf: function(expected, actual) { 
  • spinoffs/prototype/trunk/test/unit/hash.html

    r6363 r6481  
    3939 
    4040    functions: { 
    41       alpha: 'foo'
    42       beta:  function(n) { return n+1;
     41      quad: function(n) { return n*n }
     42      plus: function(n) { return n+n
    4343    }, 
    4444     
     
    6666     
    6767    testConstruct: function(){ with(this) { 
    68       var h = $H(Fixtures.one) 
    69       assertNotIdentical(Fixtures.one, h) 
    70       assertIdentical(h, $H(h)) 
     68      var h = $H(Fixtures.one); 
     69      assertNotIdentical(Fixtures.one, h); 
     70      assertIdentical(h, $H(h)); 
    7171 
    72       var h2 = new Hash(h) 
    73       assertNotIdentical(h, h2) 
    74       assertEqual(h.inspect(), h2.inspect()) 
     72      var h2 = new Hash(h); 
     73      assertNotIdentical(h, h2); 
     74      assertHashEqual(h, h2); 
    7575    }}, 
    7676     
     
    7878      assertEnumEqual([],               $H({}).keys()); 
    7979      assertEnumEqual(['a'],            $H(Fixtures.one).keys()); 
    80       assertEnumEqual($w('a b c d'),    $H(Fixtures.many).keys()); 
    81       assertEnumEqual($w('alpha beta'), $H(Fixtures.functions).keys()); 
     80      assertEnumEqual($w('a b c d'),    $H(Fixtures.many).keys().sort()); 
     81      assertEnumEqual($w('plus quad'),  $H(Fixtures.functions).keys().sort()); 
    8282    }}, 
    8383     
     
    8585      assertEnumEqual([],             $H({}).values()); 
    8686      assertEnumEqual(['A#'],         $H(Fixtures.one).values()); 
    87       assertEnumEqual($w('A B C D#'), $H(Fixtures.many).values()); 
    88       assertEqual('function', typeof $H(Fixtures.functions).values()[1]); 
    89       assertEqual(2, $H(Fixtures.functions).beta(1)); 
     87      assertEnumEqual($w('A B C D#'), $H(Fixtures.many).values().sort()); 
     88      assertEnumEqual($w('function function'), 
     89        $H(Fixtures.functions).values().map(function(i){ return typeof i })); 
     90      assertEqual(9, $H(Fixtures.functions).quad(3)); 
     91      assertEqual(6, $H(Fixtures.functions).plus(3)); 
    9092    }},   
    9193       
    9294    testMerge: function(){ with(this) { 
    93       assertEqual($H(Fixtures.many).inspect(), $H(Fixtures.many).merge().inspect()); 
    94       assertEqual($H(Fixtures.many).inspect(), $H(Fixtures.many).merge({}).inspect()); 
    95       assertEqual("#<Hash:{'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D#', 'aaa': 'AAA'}>", $H(Fixtures.many).merge({aaa: 'AAA'}).inspect()); 
    96       assertEqual("#<Hash:{'a': 'A#', 'b': 'B', 'c': 'C', 'd': 'D#'}>", $H(Fixtures.many).merge(Fixtures.one).inspect()); 
     95      assertHashEqual(Fixtures.many, $H(Fixtures.many).merge()); 
     96      assertHashEqual(Fixtures.many, $H(Fixtures.many).merge({})); 
     97      assertHashEqual(Fixtures.many, $H(Fixtures.many).merge($H())); 
     98      assertHashEqual({a:'A',  b:'B', c:'C', d:'D#', aaa:'AAA' }, $H(Fixtures.many).merge({aaa: 'AAA'})); 
     99      assertHashEqual({a:'A#', b:'B', c:'C', d:'D#' }, $H(Fixtures.many).merge(Fixtures.one)); 
    97100    }}, 
    98101 
     
    100103      var hash = $H(Fixtures.many); 
    101104      var values = hash.remove('b', 'c'); 
    102       assertEnumEqual($w('a d'), hash.keys()); 
     105      assertHashEqual({a:'A', d:'D#'}, hash); 
    103106      assertEnumEqual($w('B C'), values); 
    104107    }}, 
    105108     
    106109    testToQueryString: function(){ with(this) { 
    107       assertEqual('',                        $H({}).toQueryString()); 
    108       assertEqual('a=A%23',                  $H(Fixtures.one).toQueryString()); 
    109       assertEqual('a=A&b=B&c=C&d=D%23',      $H(Fixtures.many).toQueryString()); 
    110       assertEqual("a=b",                     $H(Fixtures.value_undefined).toQueryString()); 
    111       assertEqual("a=b",                     $H(Fixtures.value_null).toQueryString()); 
    112       assertEqual("a=b&c=0",                 $H(Fixtures.value_zero).toQueryString()); 
     110      assertEqual('',                   $H({}).toQueryString()); 
     111      assertEqual('a=A%23',             $H(Fixtures.one).toQueryString()); 
     112      assertEqual('a=A&b=B&c=C&d=D%23', $H(Fixtures.many).toQueryString()); 
     113      assertEqual("a=b&c",              $H(Fixtures.value_undefined).toQueryString()); 
     114      assertEqual("a=b&c",              $H("a=b&c".toQueryParams()).toQueryString()); 
     115      assertEqual("a=b&c=",             $H(Fixtures.value_null).toQueryString()); 
     116      assertEqual("a=b&c=0",            $H(Fixtures.value_zero).toQueryString()); 
    113117      assertEqual("color=r&color=g&color=b", $H(Fixtures.multiple).toQueryString()); 
    114       assertEqual("color=r&color=g&color=0", $H(Fixtures.multiple_nil).toQueryString()); 
    115       assertEqual("",                        $H(Fixtures.multiple_all_nil).toQueryString()); 
    116       assertEqual("",                        $H(Fixtures.multiple_empty).toQueryString()); 
     118      assertEqual("color=r&color=&color=g&color&color=0", $H(Fixtures.multiple_nil).toQueryString()); 
     119      assertEqual("color=&color",       $H(Fixtures.multiple_all_nil).toQueryString()); 
     120      assertEqual("",                   $H(Fixtures.multiple_empty).toQueryString()); 
    117121      assertEqual("stuff%5B%5D=%24&stuff%5B%5D=a&stuff%5B%5D=%3B", $H(Fixtures.multiple_special).toQueryString()); 
    118  
    119       assertEnumEqual($w("_each=E map=M keys=K values=V collect=C inject=I").sort(), 
    120         Hash.toQueryString(Fixtures.dangerous).split('&').sort()); 
    121       assertEnumEqual($w('_each=E map=M keys=K values=V collect=C inject=I').sort(), 
    122       $H(Fixtures.dangerous).toQueryString().split('&').sort()); 
     122      assertHashEqual(Fixtures.multiple_special, $H(Fixtures.multiple_special).toQueryString().toQueryParams()); 
     123       
     124      var danger = $w("_each=E collect=C inject=I keys=K map=M values=V"); 
     125      assertEnumEqual(danger, Hash.toQueryString(Fixtures.dangerous).split('&').sort()); 
     126      assertEnumEqual(danger, $H(Fixtures.dangerous).toQueryString().split('&').sort()); 
    123127    }}, 
    124128     
  • spinoffs/prototype/trunk/test/unit/string.html

    r6473 r6481  
    290290     
    291291    testToQueryParams: function() {with(this) { 
    292       assertEnumEqual([], Object.keys(''.toQueryParams())); 
    293       assertEnumEqual([], Object.keys('foo?'.toQueryParams())); 
    294        
    295       assertEnumEqual(['a', 'b'], Object.keys('foo?a&b'.toQueryParams())); 
    296       assertEnumEqual(['a', 'b'], Object.keys('foo?a&b#fragment'.toQueryParams())); 
    297       assertEnumEqual(['a', 'b'], Object.keys('a;b'.toQueryParams(';'))); 
    298        
    299       var result = 'a'.toQueryParams(); 
    300       assertEqual(undefined, result['a']); 
    301       assert(result.hasOwnProperty('a')); 
    302        
    303       result = 'a&b=c'.toQueryParams(); 
    304       assertEqual(undefined, result['a']); 
    305       assert(result.hasOwnProperty('a')); 
    306       assertEqual('c', result['b']); 
    307        
    308       result = 'a%20b=c&d=e%20f&g=h'.toQueryParams(); 
    309       assertEqual('c', result['a b']); 
    310       assertEqual('e f', result['d']); 
    311       assertEqual('h', result['g']); 
    312        
    313       result = 'color=r&color=g&color=b'.toQueryParams(); 
    314       assertEnumEqual(['r', 'g', 'b'], result['color']); 
    315       assertEnumEqual(['r', 'b'], 'c=r&c=&c=b'.toQueryParams()['c']); 
    316       assertEqual('blue', 'c=&c=blue'.toQueryParams()['c']); 
    317       assertEqual('blue', 'c=blue&c='.toQueryParams()['c']); 
     292      // only the query part 
     293      var result = {a:undefined, b:'c'}; 
     294      assertHashEqual({}, ''.toQueryParams(), 'empty query'); 
     295      assertHashEqual({}, 'foo?'.toQueryParams(), 'empty query with URL'); 
     296      assertHashEqual(result, 'foo?a&b=c'.toQueryParams(), 'query with URL'); 
     297      assertHashEqual(result, 'foo?a&b=c#fragment'.toQueryParams(), 'query with URL and fragment'); 
     298      assertHashEqual(result, 'a;b=c'.toQueryParams(';'), 'custom delimiter'); 
     299     
     300      assertHashEqual({a:undefined}, 'a'.toQueryParams(), 'key without value'); 
     301      assertHashEqual({a:'b'},  'a=b&=c'.toQueryParams(), 'empty key'); 
     302      assertHashEqual({a:'b', c:''}, 'a=b&c='.toQueryParams(), 'empty value'); 
     303       
     304      assertHashEqual({'a b':'c', d:'e f', g:'h'}, 
     305        'a%20b=c&d=e%20f&g=h'.toQueryParams(), 'proper decoding'); 
     306      assertHashEqual({a:'b=c=d'}, 'a=b=c=d'.toQueryParams(), 'multiple equal signs'); 
     307      assertHashEqual({a:'b', c:'d'}, '&a=b&&&c=d'.toQueryParams(), 'proper splitting'); 
     308       
     309      assertEnumEqual($w('r g b'), 'col=r&col=g&col=b'.toQueryParams()['col'], 
     310        'collection without square brackets'); 
     311      var msg = 'empty values inside collection'; 
     312      assertEnumEqual(['r', '', 'b'], 'c=r&c=&c=b'.toQueryParams()['c'], msg); 
     313      assertEnumEqual(['', 'blue'],   'c=&c=blue'.toQueryParams()['c'], msg); 
     314      assertEnumEqual(['blue', ''],   'c=blue&c='.toQueryParams()['c'], msg); 
    318315    }}, 
    319316