robsharp-extlib 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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