robsharp-extlib 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/.autotest +21 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/LICENSE +47 -0
  5. data/README.rdoc +17 -0
  6. data/Rakefile +28 -0
  7. data/VERSION +1 -0
  8. data/extlib.gemspec +147 -0
  9. data/lib/extlib.rb +50 -0
  10. data/lib/extlib/array.rb +38 -0
  11. data/lib/extlib/assertions.rb +8 -0
  12. data/lib/extlib/blank.rb +89 -0
  13. data/lib/extlib/boolean.rb +11 -0
  14. data/lib/extlib/byte_array.rb +6 -0
  15. data/lib/extlib/class.rb +179 -0
  16. data/lib/extlib/datetime.rb +29 -0
  17. data/lib/extlib/dictionary.rb +433 -0
  18. data/lib/extlib/hash.rb +450 -0
  19. data/lib/extlib/hook.rb +407 -0
  20. data/lib/extlib/inflection.rb +442 -0
  21. data/lib/extlib/lazy_array.rb +453 -0
  22. data/lib/extlib/lazy_module.rb +18 -0
  23. data/lib/extlib/logger.rb +198 -0
  24. data/lib/extlib/mash.rb +157 -0
  25. data/lib/extlib/module.rb +51 -0
  26. data/lib/extlib/nil.rb +5 -0
  27. data/lib/extlib/numeric.rb +5 -0
  28. data/lib/extlib/object.rb +178 -0
  29. data/lib/extlib/object_space.rb +13 -0
  30. data/lib/extlib/pathname.rb +20 -0
  31. data/lib/extlib/pooling.rb +235 -0
  32. data/lib/extlib/rubygems.rb +38 -0
  33. data/lib/extlib/simple_set.rb +66 -0
  34. data/lib/extlib/string.rb +176 -0
  35. data/lib/extlib/struct.rb +17 -0
  36. data/lib/extlib/symbol.rb +21 -0
  37. data/lib/extlib/time.rb +44 -0
  38. data/lib/extlib/try_dup.rb +44 -0
  39. data/lib/extlib/virtual_file.rb +10 -0
  40. data/spec/array_spec.rb +40 -0
  41. data/spec/blank_spec.rb +86 -0
  42. data/spec/byte_array_spec.rb +8 -0
  43. data/spec/class_spec.rb +158 -0
  44. data/spec/datetime_spec.rb +22 -0
  45. data/spec/hash_spec.rb +536 -0
  46. data/spec/hook_spec.rb +1235 -0
  47. data/spec/inflection/plural_spec.rb +565 -0
  48. data/spec/inflection/singular_spec.rb +498 -0
  49. data/spec/inflection_extras_spec.rb +111 -0
  50. data/spec/lazy_array_spec.rb +1961 -0
  51. data/spec/lazy_module_spec.rb +38 -0
  52. data/spec/mash_spec.rb +312 -0
  53. data/spec/module_spec.rb +71 -0
  54. data/spec/object_space_spec.rb +10 -0
  55. data/spec/object_spec.rb +114 -0
  56. data/spec/pooling_spec.rb +511 -0
  57. data/spec/rcov.opts +6 -0
  58. data/spec/simple_set_spec.rb +58 -0
  59. data/spec/spec.opts +4 -0
  60. data/spec/spec_helper.rb +7 -0
  61. data/spec/string_spec.rb +222 -0
  62. data/spec/struct_spec.rb +13 -0
  63. data/spec/symbol_spec.rb +9 -0
  64. data/spec/time_spec.rb +31 -0
  65. data/spec/try_call_spec.rb +74 -0
  66. data/spec/try_dup_spec.rb +46 -0
  67. data/spec/virtual_file_spec.rb +22 -0
  68. data/tasks/ci.rake +1 -0
  69. data/tasks/metrics.rake +36 -0
  70. data/tasks/spec.rake +25 -0
  71. data/tasks/yard.rake +9 -0
  72. data/tasks/yardstick.rake +19 -0
  73. metadata +198 -0
@@ -0,0 +1,536 @@
1
+ require 'spec_helper'
2
+ require 'extlib/hash'
3
+
4
+ describe Hash, "environmentize_keys!" do
5
+ it "should transform keys to uppercase text" do
6
+ { :test_1 => 'test', 'test_2' => 'test', 1 => 'test' }.environmentize_keys!.should ==
7
+ { 'TEST_1' => 'test', 'TEST_2' => 'test', '1' => 'test' }
8
+ end
9
+
10
+ it "should only transform one level of keys" do
11
+ { :test_1 => { :test2 => 'test'} }.environmentize_keys!.should ==
12
+ { 'TEST_1' => { :test2 => 'test'} }
13
+ end
14
+ end
15
+
16
+
17
+ describe Hash, "only" do
18
+ before do
19
+ @hash = { :one => 'ONE', 'two' => 'TWO', 3 => 'THREE', 4 => nil }
20
+ end
21
+
22
+ it "should return a hash with only the given key(s)" do
23
+ @hash.only(:not_in_there).should == {}
24
+ @hash.only(4).should == {4 => nil}
25
+ @hash.only(:one).should == { :one => 'ONE' }
26
+ @hash.only(:one, 3).should == { :one => 'ONE', 3 => 'THREE' }
27
+ end
28
+ end
29
+
30
+
31
+ describe Hash, "except" do
32
+ before do
33
+ @hash = { :one => 'ONE', 'two' => 'TWO', 3 => 'THREE' }
34
+ end
35
+
36
+ it "should return a hash without only the given key(s)" do
37
+ @hash.except(:one).should == { 'two' => 'TWO', 3 => 'THREE' }
38
+ @hash.except(:one, 3).should == { 'two' => 'TWO' }
39
+ end
40
+ end
41
+
42
+
43
+ describe Hash, "to_xml_attributes" do
44
+ before do
45
+ @hash = { :one => "ONE", "two" => "TWO" }
46
+ end
47
+
48
+ it "should turn the hash into xml attributes" do
49
+ attrs = @hash.to_xml_attributes
50
+ attrs.should match(/one="ONE"/m)
51
+ attrs.should match(/two="TWO"/m)
52
+ end
53
+
54
+ it 'should preserve _ in hash keys' do
55
+ attrs = {
56
+ :some_long_attribute => "with short value",
57
+ :crash => :burn,
58
+ :merb => "uses extlib"
59
+ }.to_xml_attributes
60
+
61
+ attrs.should =~ /some_long_attribute="with short value"/
62
+ attrs.should =~ /merb="uses extlib"/
63
+ attrs.should =~ /crash="burn"/
64
+ end
65
+ end
66
+
67
+
68
+ describe Hash, "from_xml" do
69
+ it "should transform a simple tag with content" do
70
+ xml = "<tag>This is the contents</tag>"
71
+ Hash.from_xml(xml).should == { 'tag' => 'This is the contents' }
72
+ end
73
+
74
+ it "should work with cdata tags" do
75
+ xml = <<-END
76
+ <tag>
77
+ <![CDATA[
78
+ text inside cdata
79
+ ]]>
80
+ </tag>
81
+ END
82
+ Hash.from_xml(xml)["tag"].strip.should == "text inside cdata"
83
+ end
84
+
85
+ it "should transform a simple tag with attributes" do
86
+ xml = "<tag attr1='1' attr2='2'></tag>"
87
+ hash = { 'tag' => { 'attr1' => '1', 'attr2' => '2' } }
88
+ Hash.from_xml(xml).should == hash
89
+ end
90
+
91
+ it "should transform repeating siblings into an array" do
92
+ xml =<<-XML
93
+ <opt>
94
+ <user login="grep" fullname="Gary R Epstein" />
95
+ <user login="stty" fullname="Simon T Tyson" />
96
+ </opt>
97
+ XML
98
+
99
+ Hash.from_xml(xml)['opt']['user'].should be_an_instance_of(Array)
100
+
101
+ hash = {
102
+ 'opt' => {
103
+ 'user' => [{
104
+ 'login' => 'grep',
105
+ 'fullname' => 'Gary R Epstein'
106
+ },{
107
+ 'login' => 'stty',
108
+ 'fullname' => 'Simon T Tyson'
109
+ }]
110
+ }
111
+ }
112
+
113
+ Hash.from_xml(xml).should == hash
114
+ end
115
+
116
+ it "should not transform non-repeating siblings into an array" do
117
+ xml =<<-XML
118
+ <opt>
119
+ <user login="grep" fullname="Gary R Epstein" />
120
+ </opt>
121
+ XML
122
+
123
+ Hash.from_xml(xml)['opt']['user'].should be_an_instance_of(Hash)
124
+
125
+ hash = {
126
+ 'opt' => {
127
+ 'user' => {
128
+ 'login' => 'grep',
129
+ 'fullname' => 'Gary R Epstein'
130
+ }
131
+ }
132
+ }
133
+
134
+ Hash.from_xml(xml).should == hash
135
+ end
136
+
137
+ it "should typecast an integer" do
138
+ xml = "<tag type='integer'>10</tag>"
139
+ Hash.from_xml(xml)['tag'].should == 10
140
+ end
141
+
142
+ it "should typecast a true boolean" do
143
+ xml = "<tag type='boolean'>true</tag>"
144
+ Hash.from_xml(xml)['tag'].should be_true
145
+ end
146
+
147
+ it "should typecast a false boolean" do
148
+ ["false"].each do |w|
149
+ Hash.from_xml("<tag type='boolean'>#{w}</tag>")['tag'].should be_false
150
+ end
151
+ end
152
+
153
+ it "should typecast a datetime" do
154
+ xml = "<tag type='datetime'>2007-12-31 10:32</tag>"
155
+ Hash.from_xml(xml)['tag'].should == Time.parse( '2007-12-31 10:32' ).utc
156
+ end
157
+
158
+ it "should typecast a date" do
159
+ xml = "<tag type='date'>2007-12-31</tag>"
160
+ Hash.from_xml(xml)['tag'].should == Date.parse('2007-12-31')
161
+ end
162
+
163
+ it "should unescape html entities" do
164
+ values = {
165
+ "<" => "&lt;",
166
+ ">" => "&gt;",
167
+ '"' => "&quot;",
168
+ "'" => "&apos;",
169
+ "&" => "&amp;"
170
+ }
171
+ values.each do |k,v|
172
+ xml = "<tag>Some content #{v}</tag>"
173
+ Hash.from_xml(xml)['tag'].should match(Regexp.new(k))
174
+ end
175
+ end
176
+
177
+ it "should undasherize keys as tags" do
178
+ xml = "<tag-1>Stuff</tag-1>"
179
+ Hash.from_xml(xml).should have_key('tag_1')
180
+ end
181
+
182
+ it "should undasherize keys as attributes" do
183
+ xml = "<tag1 attr-1='1'></tag1>"
184
+ Hash.from_xml(xml)['tag1'].should have_key('attr_1')
185
+ end
186
+
187
+ it "should undasherize keys as tags and attributes" do
188
+ xml = "<tag-1 attr-1='1'></tag-1>"
189
+ Hash.from_xml(xml).should have_key('tag_1' )
190
+ Hash.from_xml(xml)['tag_1'].should have_key('attr_1')
191
+ end
192
+
193
+ it "should render nested content correctly" do
194
+ xml = "<root><tag1>Tag1 Content <em><strong>This is strong</strong></em></tag1></root>"
195
+ Hash.from_xml(xml)['root']['tag1'].should == "Tag1 Content <em><strong>This is strong</strong></em>"
196
+ end
197
+
198
+ it "should render nested content with split text nodes correctly" do
199
+ xml = "<root>Tag1 Content<em>Stuff</em> Hi There</root>"
200
+ Hash.from_xml(xml)['root'].should == "Tag1 Content<em>Stuff</em> Hi There"
201
+ end
202
+
203
+ it "should ignore attributes when a child is a text node" do
204
+ xml = "<root attr1='1'>Stuff</root>"
205
+ Hash.from_xml(xml).should == { "root" => "Stuff" }
206
+ end
207
+
208
+ it "should ignore attributes when any child is a text node" do
209
+ xml = "<root attr1='1'>Stuff <em>in italics</em></root>"
210
+ Hash.from_xml(xml).should == { "root" => "Stuff <em>in italics</em>" }
211
+ end
212
+
213
+ it "should correctly transform multiple children" do
214
+ xml = <<-XML
215
+ <user gender='m'>
216
+ <age type='integer'>35</age>
217
+ <name>Home Simpson</name>
218
+ <dob type='date'>1988-01-01</dob>
219
+ <joined-at type='datetime'>2000-04-28 23:01</joined-at>
220
+ <is-cool type='boolean'>true</is-cool>
221
+ </user>
222
+ XML
223
+
224
+ hash = {
225
+ "user" => {
226
+ "gender" => "m",
227
+ "age" => 35,
228
+ "name" => "Home Simpson",
229
+ "dob" => Date.parse('1988-01-01'),
230
+ "joined_at" => Time.parse("2000-04-28 23:01"),
231
+ "is_cool" => true
232
+ }
233
+ }
234
+
235
+ Hash.from_xml(xml).should == hash
236
+ end
237
+
238
+ it "should properly handle nil values (ActiveSupport Compatible)" do
239
+ topic_xml = <<-EOT
240
+ <topic>
241
+ <title></title>
242
+ <id type="integer"></id>
243
+ <approved type="boolean"></approved>
244
+ <written-on type="date"></written-on>
245
+ <viewed-at type="datetime"></viewed-at>
246
+ <content type="yaml"></content>
247
+ <parent-id></parent-id>
248
+ </topic>
249
+ EOT
250
+
251
+ expected_topic_hash = {
252
+ 'title' => nil,
253
+ 'id' => nil,
254
+ 'approved' => nil,
255
+ 'written_on' => nil,
256
+ 'viewed_at' => nil,
257
+ 'content' => nil,
258
+ 'parent_id' => nil
259
+ }
260
+ Hash.from_xml(topic_xml)["topic"].should == expected_topic_hash
261
+ end
262
+
263
+ it "should handle a single record from xml (ActiveSupport Compatible)" do
264
+ topic_xml = <<-EOT
265
+ <topic>
266
+ <title>The First Topic</title>
267
+ <author-name>David</author-name>
268
+ <id type="integer">1</id>
269
+ <approved type="boolean"> true </approved>
270
+ <replies-count type="integer">0</replies-count>
271
+ <replies-close-in type="integer">2592000000</replies-close-in>
272
+ <written-on type="date">2003-07-16</written-on>
273
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
274
+ <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
275
+ <author-email-address>david@loudthinking.com</author-email-address>
276
+ <parent-id></parent-id>
277
+ <ad-revenue type="decimal">1.5</ad-revenue>
278
+ <optimum-viewing-angle type="float">135</optimum-viewing-angle>
279
+ <resident type="symbol">yes</resident>
280
+ </topic>
281
+ EOT
282
+
283
+ expected_topic_hash = {
284
+ 'title' => "The First Topic",
285
+ 'author_name' => "David",
286
+ 'id' => 1,
287
+ 'approved' => true,
288
+ 'replies_count' => 0,
289
+ 'replies_close_in' => 2592000000,
290
+ 'written_on' => Date.new(2003, 7, 16),
291
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
292
+ # Changed this line where the key is :message. The yaml specifies this as a symbol, and who am I to change what you specify
293
+ # The line in ActiveSupport is
294
+ # 'content' => { 'message' => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
295
+ 'content' => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
296
+ 'author_email_address' => "david@loudthinking.com",
297
+ 'parent_id' => nil,
298
+ 'ad_revenue' => BigDecimal("1.50"),
299
+ 'optimum_viewing_angle' => 135.0,
300
+ 'resident' => :yes
301
+ }
302
+
303
+ Hash.from_xml(topic_xml)["topic"].each do |k,v|
304
+ v.should == expected_topic_hash[k]
305
+ end
306
+ end
307
+
308
+ it "should handle multiple records (ActiveSupport Compatible)" do
309
+ topics_xml = <<-EOT
310
+ <topics type="array">
311
+ <topic>
312
+ <title>The First Topic</title>
313
+ <author-name>David</author-name>
314
+ <id type="integer">1</id>
315
+ <approved type="boolean">false</approved>
316
+ <replies-count type="integer">0</replies-count>
317
+ <replies-close-in type="integer">2592000000</replies-close-in>
318
+ <written-on type="date">2003-07-16</written-on>
319
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
320
+ <content>Have a nice day</content>
321
+ <author-email-address>david@loudthinking.com</author-email-address>
322
+ <parent-id nil="true"></parent-id>
323
+ </topic>
324
+ <topic>
325
+ <title>The Second Topic</title>
326
+ <author-name>Jason</author-name>
327
+ <id type="integer">1</id>
328
+ <approved type="boolean">false</approved>
329
+ <replies-count type="integer">0</replies-count>
330
+ <replies-close-in type="integer">2592000000</replies-close-in>
331
+ <written-on type="date">2003-07-16</written-on>
332
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
333
+ <content>Have a nice day</content>
334
+ <author-email-address>david@loudthinking.com</author-email-address>
335
+ <parent-id></parent-id>
336
+ </topic>
337
+ </topics>
338
+ EOT
339
+
340
+ expected_topic_hash = {
341
+ 'title' => "The First Topic",
342
+ 'author_name' => "David",
343
+ 'id' => 1,
344
+ 'approved' => false,
345
+ 'replies_count' => 0,
346
+ 'replies_close_in' => 2592000000,
347
+ 'written_on' => Date.new(2003, 7, 16),
348
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
349
+ 'content' => "Have a nice day",
350
+ 'author_email_address' => "david@loudthinking.com",
351
+ 'parent_id' => nil
352
+ }
353
+ # puts Hash.from_xml(topics_xml)['topics'].first.inspect
354
+ Hash.from_xml(topics_xml)["topics"].first.each do |k,v|
355
+ v.should == expected_topic_hash[k]
356
+ end
357
+ end
358
+
359
+ it "should handle a single record from_xml with attributes other than type (ActiveSupport Compatible)" do
360
+ topic_xml = <<-EOT
361
+ <rsp stat="ok">
362
+ <photos page="1" pages="1" perpage="100" total="16">
363
+ <photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
364
+ </photos>
365
+ </rsp>
366
+ EOT
367
+
368
+ expected_topic_hash = {
369
+ 'id' => "175756086",
370
+ 'owner' => "55569174@N00",
371
+ 'secret' => "0279bf37a1",
372
+ 'server' => "76",
373
+ 'title' => "Colored Pencil PhotoBooth Fun",
374
+ 'ispublic' => "1",
375
+ 'isfriend' => "0",
376
+ 'isfamily' => "0",
377
+ }
378
+ Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"].each do |k,v|
379
+ v.should == expected_topic_hash[k]
380
+ end
381
+ end
382
+
383
+ it "should handle an emtpy array (ActiveSupport Compatible)" do
384
+ blog_xml = <<-XML
385
+ <blog>
386
+ <posts type="array"></posts>
387
+ </blog>
388
+ XML
389
+ expected_blog_hash = {"blog" => {"posts" => []}}
390
+ Hash.from_xml(blog_xml).should == expected_blog_hash
391
+ end
392
+
393
+ it "should handle empty array with whitespace from xml (ActiveSupport Compatible)" do
394
+ blog_xml = <<-XML
395
+ <blog>
396
+ <posts type="array">
397
+ </posts>
398
+ </blog>
399
+ XML
400
+ expected_blog_hash = {"blog" => {"posts" => []}}
401
+ Hash.from_xml(blog_xml).should == expected_blog_hash
402
+ end
403
+
404
+ it "should handle array with one entry from_xml (ActiveSupport Compatible)" do
405
+ blog_xml = <<-XML
406
+ <blog>
407
+ <posts type="array">
408
+ <post>a post</post>
409
+ </posts>
410
+ </blog>
411
+ XML
412
+ expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
413
+ Hash.from_xml(blog_xml).should == expected_blog_hash
414
+ end
415
+
416
+ it "should handle array with multiple entries from xml (ActiveSupport Compatible)" do
417
+ blog_xml = <<-XML
418
+ <blog>
419
+ <posts type="array">
420
+ <post>a post</post>
421
+ <post>another post</post>
422
+ </posts>
423
+ </blog>
424
+ XML
425
+ expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
426
+ Hash.from_xml(blog_xml).should == expected_blog_hash
427
+ end
428
+
429
+ it "should handle file types (ActiveSupport Compatible)" do
430
+ blog_xml = <<-XML
431
+ <blog>
432
+ <logo type="file" name="logo.png" content_type="image/png">
433
+ </logo>
434
+ </blog>
435
+ XML
436
+ hash = Hash.from_xml(blog_xml)
437
+ hash.should have_key('blog')
438
+ hash['blog'].should have_key('logo')
439
+
440
+ file = hash['blog']['logo']
441
+ file.original_filename.should == 'logo.png'
442
+ file.content_type.should == 'image/png'
443
+ end
444
+
445
+ it "should handle file from xml with defaults (ActiveSupport Compatible)" do
446
+ blog_xml = <<-XML
447
+ <blog>
448
+ <logo type="file">
449
+ </logo>
450
+ </blog>
451
+ XML
452
+ file = Hash.from_xml(blog_xml)['blog']['logo']
453
+ file.original_filename.should == 'untitled'
454
+ file.content_type.should == 'application/octet-stream'
455
+ end
456
+
457
+ it "should handle xsd like types from xml (ActiveSupport Compatible)" do
458
+ bacon_xml = <<-EOT
459
+ <bacon>
460
+ <weight type="double">0.5</weight>
461
+ <price type="decimal">12.50</price>
462
+ <chunky type="boolean"> 1 </chunky>
463
+ <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
464
+ <notes type="string"></notes>
465
+ <illustration type="base64Binary">YmFiZS5wbmc=</illustration>
466
+ </bacon>
467
+ EOT
468
+
469
+ expected_bacon_hash = {
470
+ 'weight' => 0.5,
471
+ 'chunky' => true,
472
+ 'price' => BigDecimal("12.50"),
473
+ 'expires_at' => Time.utc(2007,12,25,12,34,56),
474
+ 'notes' => "",
475
+ 'illustration' => "babe.png"
476
+ }
477
+
478
+ Hash.from_xml(bacon_xml)["bacon"].should == expected_bacon_hash
479
+ end
480
+
481
+ it "should let type trickle through when unknown (ActiveSupport Compatible)" do
482
+ product_xml = <<-EOT
483
+ <product>
484
+ <weight type="double">0.5</weight>
485
+ <image type="ProductImage"><filename>image.gif</filename></image>
486
+
487
+ </product>
488
+ EOT
489
+
490
+ expected_product_hash = {
491
+ 'weight' => 0.5,
492
+ 'image' => {'type' => 'ProductImage', 'filename' => 'image.gif' },
493
+ }
494
+
495
+ Hash.from_xml(product_xml)["product"].should == expected_product_hash
496
+ end
497
+
498
+ it "should handle unescaping from xml (ActiveResource Compatible)" do
499
+ xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
500
+ expected_hash = {
501
+ 'bare_string' => 'First & Last Name',
502
+ 'pre_escaped_string' => 'First &amp; Last Name'
503
+ }
504
+
505
+ Hash.from_xml(xml_string)['person'].should == expected_hash
506
+ end
507
+ end
508
+
509
+ describe Hash, 'to_params' do
510
+ {
511
+ { "foo" => "bar", "baz" => "bat" } => "foo=bar&baz=bat",
512
+ { "foo" => [ "bar", "baz" ] } => "foo[]=bar&foo[]=baz",
513
+ { "foo" => [ {"bar" => "1"}, {"bar" => 2} ] } => "foo[][bar]=1&foo[][bar]=2",
514
+ { "foo" => { "bar" => [ {"baz" => 1}, {"baz" => "2"} ] } } => "foo[bar][][baz]=1&foo[bar][][baz]=2",
515
+ { "foo" => {"1" => "bar", "2" => "baz"} } => "foo[1]=bar&foo[2]=baz"
516
+ }.each do |hash, params|
517
+ it "should covert hash: #{hash.inspect} to params: #{params.inspect}" do
518
+ hash.to_params.split('&').sort.should == params.split('&').sort
519
+ end
520
+ end
521
+
522
+ it 'should not leave a trailing &' do
523
+ { :name => 'Bob', :address => { :street => '111 Ruby Ave.', :city => 'Ruby Central', :phones => ['111-111-1111', '222-222-2222'] } }.to_params.should_not match(/&$/)
524
+ end
525
+ end
526
+
527
+ describe Hash, 'to_mash' do
528
+ before :each do
529
+ @hash = Hash.new(10)
530
+ end
531
+
532
+ it "copies default Hash value to Mash" do
533
+ @mash = @hash.to_mash
534
+ @mash[:merb].should == 10
535
+ end
536
+ end