motion-support 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +1 -1
  3. data/README.md +231 -2
  4. data/Rakefile +3 -3
  5. data/app/app_delegate.rb +0 -2
  6. data/examples/Inflector/.gitignore +16 -0
  7. data/examples/Inflector/Gemfile +5 -0
  8. data/examples/Inflector/Rakefile +13 -0
  9. data/examples/Inflector/app/app_delegate.rb +8 -0
  10. data/examples/Inflector/app/inflections.rb +5 -0
  11. data/examples/Inflector/app/inflector_view_controller.rb +120 -0
  12. data/examples/Inflector/app/words_view_controller.rb +101 -0
  13. data/examples/Inflector/resources/Default-568h@2x.png +0 -0
  14. data/examples/Inflector/spec/main_spec.rb +9 -0
  15. data/lib/motion-support/core_ext/array.rb +13 -0
  16. data/lib/motion-support/core_ext/class.rb +8 -0
  17. data/lib/motion-support/core_ext/hash.rb +16 -0
  18. data/lib/motion-support/core_ext/integer.rb +9 -0
  19. data/lib/motion-support/core_ext/module.rb +14 -0
  20. data/lib/motion-support/core_ext/numeric.rb +8 -0
  21. data/lib/motion-support/core_ext/object.rb +14 -0
  22. data/lib/motion-support/core_ext/range.rb +8 -0
  23. data/lib/motion-support/core_ext/string.rb +14 -0
  24. data/lib/motion-support/core_ext/time.rb +19 -0
  25. data/lib/motion-support/core_ext.rb +3 -0
  26. data/lib/motion-support/inflector.rb +12 -156
  27. data/lib/motion-support.rb +5 -5
  28. data/motion/_stdlib/cgi.rb +22 -0
  29. data/motion/_stdlib/date.rb +77 -0
  30. data/motion/_stdlib/time.rb +19 -0
  31. data/motion/core_ext/array/access.rb +28 -0
  32. data/motion/core_ext/array/conversions.rb +86 -0
  33. data/motion/core_ext/array/extract_options.rb +11 -0
  34. data/motion/core_ext/array/grouping.rb +99 -0
  35. data/motion/core_ext/array/prepend_and_append.rb +7 -0
  36. data/motion/core_ext/array/wrap.rb +45 -0
  37. data/{lib/motion-support → motion/core_ext}/array.rb +0 -4
  38. data/motion/core_ext/class/attribute.rb +119 -0
  39. data/motion/core_ext/class/attribute_accessors.rb +168 -0
  40. data/motion/core_ext/date/acts_like.rb +8 -0
  41. data/motion/core_ext/date/calculations.rb +117 -0
  42. data/motion/core_ext/date/conversions.rb +56 -0
  43. data/motion/core_ext/date_and_time/calculations.rb +232 -0
  44. data/motion/core_ext/enumerable.rb +90 -0
  45. data/motion/core_ext/hash/deep_merge.rb +27 -0
  46. data/motion/core_ext/hash/except.rb +15 -0
  47. data/motion/core_ext/hash/indifferent_access.rb +19 -0
  48. data/motion/core_ext/hash/keys.rb +138 -0
  49. data/motion/core_ext/hash/reverse_merge.rb +22 -0
  50. data/motion/core_ext/hash/slice.rb +40 -0
  51. data/motion/core_ext/integer/inflections.rb +27 -0
  52. data/motion/core_ext/integer/multiple.rb +10 -0
  53. data/motion/core_ext/integer/time.rb +41 -0
  54. data/{lib/motion-support → motion/core_ext}/metaclass.rb +0 -0
  55. data/motion/core_ext/module/aliasing.rb +69 -0
  56. data/motion/core_ext/module/anonymous.rb +19 -0
  57. data/motion/core_ext/module/attr_internal.rb +38 -0
  58. data/motion/core_ext/module/attribute_accessors.rb +64 -0
  59. data/motion/core_ext/module/delegation.rb +175 -0
  60. data/motion/core_ext/module/introspection.rb +60 -0
  61. data/motion/core_ext/module/reachable.rb +5 -0
  62. data/motion/core_ext/module/remove_method.rb +12 -0
  63. data/motion/core_ext/ns_dictionary.rb +11 -0
  64. data/motion/core_ext/numeric/bytes.rb +44 -0
  65. data/motion/core_ext/numeric/conversions.rb +7 -0
  66. data/motion/core_ext/numeric/time.rb +75 -0
  67. data/motion/core_ext/object/acts_like.rb +10 -0
  68. data/motion/core_ext/object/blank.rb +105 -0
  69. data/motion/core_ext/object/deep_dup.rb +44 -0
  70. data/motion/core_ext/object/duplicable.rb +83 -0
  71. data/motion/core_ext/object/instance_variables.rb +28 -0
  72. data/motion/core_ext/object/to_param.rb +58 -0
  73. data/motion/core_ext/object/to_query.rb +26 -0
  74. data/motion/core_ext/object/try.rb +78 -0
  75. data/motion/core_ext/range/include_range.rb +23 -0
  76. data/motion/core_ext/range/overlaps.rb +8 -0
  77. data/motion/core_ext/regexp.rb +5 -0
  78. data/motion/core_ext/string/access.rb +104 -0
  79. data/motion/core_ext/string/behavior.rb +6 -0
  80. data/motion/core_ext/string/exclude.rb +11 -0
  81. data/motion/core_ext/string/filters.rb +55 -0
  82. data/motion/core_ext/string/indent.rb +43 -0
  83. data/motion/core_ext/string/inflections.rb +195 -0
  84. data/motion/core_ext/string/starts_ends_with.rb +4 -0
  85. data/motion/core_ext/string/strip.rb +24 -0
  86. data/motion/core_ext/time/acts_like.rb +8 -0
  87. data/motion/core_ext/time/calculations.rb +215 -0
  88. data/motion/core_ext/time/conversions.rb +52 -0
  89. data/motion/duration.rb +104 -0
  90. data/motion/hash_with_indifferent_access.rb +251 -0
  91. data/motion/inflections.rb +67 -0
  92. data/motion/inflector/inflections.rb +203 -0
  93. data/motion/inflector/methods.rb +321 -0
  94. data/{lib/motion-support → motion}/logger.rb +0 -0
  95. data/{lib/motion-support → motion}/version.rb +1 -1
  96. data/motion-support.gemspec +2 -2
  97. data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
  98. data/spec/motion-support/_helpers/inflector_test_cases.rb +313 -0
  99. data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
  100. data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
  101. data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
  102. data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
  103. data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
  104. data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
  105. data/spec/motion-support/{array_spec.rb → core_ext/array_spec.rb} +0 -5
  106. data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
  107. data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
  108. data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
  109. data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
  110. data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
  111. data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
  112. data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
  113. data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
  114. data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
  115. data/spec/motion-support/core_ext/hash/key_spec.rb +230 -0
  116. data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
  117. data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
  118. data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
  119. data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
  120. data/spec/motion-support/{metaclass_spec.rb → core_ext/metaclass_spec.rb} +0 -0
  121. data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
  122. data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
  123. data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
  124. data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
  125. data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
  126. data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
  127. data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
  128. data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
  129. data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
  130. data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
  131. data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
  132. data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
  133. data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
  134. data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
  135. data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
  136. data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
  137. data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
  138. data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
  139. data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
  140. data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
  141. data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
  142. data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
  143. data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
  144. data/spec/motion-support/core_ext/string/filter_spec.rb +48 -0
  145. data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
  146. data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
  147. data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
  148. data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
  149. data/spec/motion-support/core_ext/string_spec.rb +88 -0
  150. data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
  151. data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
  152. data/spec/motion-support/core_ext/time/conversion_spec.rb +54 -0
  153. data/spec/motion-support/duration_spec.rb +107 -0
  154. data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
  155. data/spec/motion-support/inflector_spec.rb +474 -35
  156. data/spec/motion-support/ns_dictionary_spec.rb +29 -0
  157. metadata +212 -35
  158. data/lib/motion-support/cattr_accessor.rb +0 -19
  159. data/lib/motion-support/class_inheritable_accessor.rb +0 -23
  160. data/lib/motion-support/class_inheritable_array.rb +0 -29
  161. data/lib/motion-support/hash.rb +0 -31
  162. data/lib/motion-support/nilclass.rb +0 -5
  163. data/lib/motion-support/object.rb +0 -17
  164. data/lib/motion-support/string.rb +0 -71
  165. data/spec/motion-support/cattr_accessor_spec.rb +0 -49
  166. data/spec/motion-support/class_inheritable_accessor_spec.rb +0 -49
  167. data/spec/motion-support/class_inheritable_array_spec.rb +0 -61
  168. data/spec/motion-support/hash_spec.rb +0 -31
  169. data/spec/motion-support/nilclass_spec.rb +0 -5
  170. data/spec/motion-support/object_spec.rb +0 -43
  171. data/spec/motion-support/string_spec.rb +0 -145
@@ -0,0 +1,605 @@
1
+ class IndifferentHash < MotionSupport::HashWithIndifferentAccess
2
+ end
3
+
4
+ class SubclassingArray < Array
5
+ end
6
+
7
+ class SubclassingHash < Hash
8
+ end
9
+
10
+ class NonIndifferentHash < Hash
11
+ def nested_under_indifferent_access
12
+ self
13
+ end
14
+ end
15
+
16
+ describe "HashWithIndifferentAccess" do
17
+ before do
18
+ @strings = { 'a' => 1, 'b' => 2 }
19
+ @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } }
20
+ @symbols = { :a => 1, :b => 2 }
21
+ @nested_symbols = { :a => { :b => { :c => 3 } } }
22
+ @mixed = { :a => 1, 'b' => 2 }
23
+ @nested_mixed = { 'a' => { :b => { 'c' => 3 } } }
24
+ @fixnums = { 0 => 1, 1 => 2 }
25
+ @nested_fixnums = { 0 => { 1 => { 2 => 3} } }
26
+ @illegal_symbols = { [] => 3 }
27
+ @nested_illegal_symbols = { [] => { [] => 3} }
28
+ @upcase_strings = { 'A' => 1, 'B' => 2 }
29
+ @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } }
30
+ end
31
+
32
+ describe "constructor" do
33
+ it "should construct hash" do
34
+ hash = HashWithIndifferentAccess[:foo, 1]
35
+ hash[:foo].should == 1
36
+ hash['foo'].should == 1
37
+ hash[:foo] = 3
38
+ hash[:foo].should == 3
39
+ hash['foo'].should == 3
40
+ end
41
+
42
+ it "should return duplicate for with_indifferent_access" do
43
+ hash_wia = HashWithIndifferentAccess.new
44
+ hash_wia.with_indifferent_access.should == hash_wia
45
+ hash_wia.with_indifferent_access.object_id.should.not == hash_wia.object_id
46
+ end
47
+ end
48
+
49
+ describe "conversion" do
50
+ it "should not convert other key objects" do
51
+ original = {Object.new => 2, 1 => 2, [] => true}
52
+ indiff = original.with_indifferent_access
53
+ indiff.keys.any? {|k| k.kind_of? String}.should == false
54
+ end
55
+ end
56
+
57
+ describe "symbolize_keys" do
58
+ it "should return normal hash instance" do
59
+ @symbols.with_indifferent_access.symbolize_keys.should.is_a Hash
60
+ end
61
+
62
+ it "should symbolize keys" do
63
+ @symbols.with_indifferent_access.symbolize_keys.should == @symbols
64
+ @strings.with_indifferent_access.symbolize_keys.should == @symbols
65
+ @mixed.with_indifferent_access.symbolize_keys.should == @symbols
66
+ end
67
+
68
+ it "should preserve keys that can't be symbolized" do
69
+ @illegal_symbols.with_indifferent_access.symbolize_keys.should == @illegal_symbols
70
+ lambda { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }.should.raise NoMethodError
71
+ end
72
+
73
+ it "should preserve Fixnum keys" do
74
+ @fixnums.with_indifferent_access.symbolize_keys.should == @fixnums
75
+ lambda { @fixnums.with_indifferent_access.dup.symbolize_keys! }.should.raise NoMethodError
76
+ end
77
+
78
+ it "should preserve hash" do
79
+ h = HashWithIndifferentAccess.new
80
+ h['first'] = 1
81
+ h = h.symbolize_keys
82
+ h[:first].should == 1
83
+ end
84
+ end
85
+
86
+ describe "symbolize_keys!" do
87
+ it "should not work" do
88
+ lambda { @symbols.with_indifferent_access.dup.symbolize_keys! }.should.raise NoMethodError
89
+ lambda { @strings.with_indifferent_access.dup.symbolize_keys! }.should.raise NoMethodError
90
+ lambda { @mixed.with_indifferent_access.dup.symbolize_keys! }.should.raise NoMethodError
91
+ end
92
+ end
93
+
94
+ describe "deep_symbolize_keys" do
95
+ it "should return normal hash instance" do
96
+ @symbols.with_indifferent_access.deep_symbolize_keys.should.is_a Hash
97
+ end
98
+
99
+ it "should deep symbolize keys" do
100
+ @nested_symbols.with_indifferent_access.deep_symbolize_keys.should == @nested_symbols
101
+ @nested_strings.with_indifferent_access.deep_symbolize_keys.should == @nested_symbols
102
+ @nested_mixed.with_indifferent_access.deep_symbolize_keys.should == @nested_symbols
103
+ end
104
+
105
+ it "should preserve keys that can't be symbolized" do
106
+ @nested_illegal_symbols.with_indifferent_access.deep_symbolize_keys.should == @nested_illegal_symbols
107
+ lambda { @nested_illegal_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! }.should.raise NoMethodError
108
+ end
109
+
110
+ it "should preserve Fixnum keys for" do
111
+ @nested_fixnums.with_indifferent_access.deep_symbolize_keys.should == @nested_fixnums
112
+ lambda { @nested_fixnums.with_indifferent_access.deep_dup.deep_symbolize_keys! }.should.raise NoMethodError
113
+ end
114
+
115
+ it "should preserve hash" do
116
+ h = HashWithIndifferentAccess.new
117
+ h['first'] = 1
118
+ h = h.deep_symbolize_keys
119
+ h[:first].should == 1
120
+ end
121
+ end
122
+
123
+ describe "deep_symbolize_keys!" do
124
+ it "should not work" do
125
+ lambda { @nested_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! }.should.raise NoMethodError
126
+ lambda { @nested_strings.with_indifferent_access.deep_dup.deep_symbolize_keys! }.should.raise NoMethodError
127
+ lambda { @nested_mixed.with_indifferent_access.deep_dup.deep_symbolize_keys! }.should.raise NoMethodError
128
+ end
129
+ end
130
+
131
+ describe "stringify_keys" do
132
+ it "should return hash with indifferent access" do
133
+ @symbols.with_indifferent_access.stringify_keys.should.is_a MotionSupport::HashWithIndifferentAccess
134
+ end
135
+
136
+ it "should stringify keys" do
137
+ @symbols.with_indifferent_access.stringify_keys.should == @strings
138
+ @strings.with_indifferent_access.stringify_keys.should == @strings
139
+ @mixed.with_indifferent_access.stringify_keys.should == @strings
140
+ end
141
+
142
+ it "should preserve hash" do
143
+ h = HashWithIndifferentAccess.new
144
+ h[:first] = 1
145
+ h = h.stringify_keys
146
+ h['first'].should == 1
147
+ end
148
+ end
149
+
150
+ describe "deep_stringify_keys" do
151
+ it "should return hash with indifferent access" do
152
+ @nested_symbols.with_indifferent_access.deep_stringify_keys.should.is_a MotionSupport::HashWithIndifferentAccess
153
+ end
154
+
155
+ it "should deep stringify keys" do
156
+ @nested_symbols.with_indifferent_access.deep_stringify_keys.should == @nested_strings
157
+ @nested_strings.with_indifferent_access.deep_stringify_keys.should == @nested_strings
158
+ @nested_mixed.with_indifferent_access.deep_stringify_keys.should == @nested_strings
159
+ end
160
+
161
+ it "should preserve hash" do
162
+ h = HashWithIndifferentAccess.new
163
+ h[:first] = 1
164
+ h = h.deep_stringify_keys
165
+ h['first'].should == 1
166
+ end
167
+ end
168
+
169
+ describe "stringify_keys!" do
170
+ it "should return hash with indifferent access" do
171
+ @symbols.with_indifferent_access.dup.stringify_keys!.should.is_a MotionSupport::HashWithIndifferentAccess
172
+ end
173
+
174
+ it "should stringify keys (for dupped instance)" do
175
+ @symbols.with_indifferent_access.dup.stringify_keys!.should == @strings
176
+ @strings.with_indifferent_access.dup.stringify_keys!.should == @strings
177
+ @mixed.with_indifferent_access.dup.stringify_keys!.should == @strings
178
+ end
179
+ end
180
+
181
+ describe "deep_stringify_keys!" do
182
+ it "should return hash with indifferent access" do
183
+ @nested_symbols.with_indifferent_access.dup.deep_stringify_keys!.should.is_a MotionSupport::HashWithIndifferentAccess
184
+ end
185
+
186
+ it "should stringify keys (for deep_dupped instance)" do
187
+ @nested_symbols.with_indifferent_access.deep_dup.deep_stringify_keys!.should == @nested_strings
188
+ @nested_strings.with_indifferent_access.deep_dup.deep_stringify_keys!.should == @nested_strings
189
+ @nested_mixed.with_indifferent_access.deep_dup.deep_stringify_keys!.should == @nested_strings
190
+ end
191
+ end
192
+
193
+ describe "reading" do
194
+ it "should read string keys with symbol access" do
195
+ hash = HashWithIndifferentAccess.new
196
+ hash["a"] = 1
197
+ hash["b"] = true
198
+ hash["c"] = false
199
+ hash["d"] = nil
200
+
201
+ hash[:a].should == 1
202
+ hash[:b].should == true
203
+ hash[:c].should == false
204
+ hash[:d].should == nil
205
+ hash[:e].should == nil
206
+ end
207
+
208
+ it "should read string keys with symbol access and nonnil default" do
209
+ hash = HashWithIndifferentAccess.new(1)
210
+ hash["a"] = 1
211
+ hash["b"] = true
212
+ hash["c"] = false
213
+ hash["d"] = nil
214
+
215
+ hash[:a].should == 1
216
+ hash[:b].should == true
217
+ hash[:c].should == false
218
+ hash[:d].should == nil
219
+ hash[:e].should == 1
220
+ end
221
+
222
+ it "should return the same object that is stored" do
223
+ hash = HashWithIndifferentAccess.new {|h, k| h[k] = []}
224
+ hash[:a] << 1
225
+
226
+ hash[:a].should == [1]
227
+ end
228
+ end
229
+
230
+ describe "writing" do
231
+ it "should write with symbols and strings" do
232
+ hash = HashWithIndifferentAccess.new
233
+ hash[:a] = 1
234
+ hash['b'] = 2
235
+
236
+ hash['a'].should == 1
237
+ hash['b'].should == 2
238
+ hash[:a].should == 1
239
+ hash[:b].should == 2
240
+ end
241
+
242
+ it "should not symbolize or stringify numbers" do
243
+ hash = HashWithIndifferentAccess.new
244
+ hash[3] = 3
245
+
246
+ hash[3].should == 3
247
+ hash[:'3'].should == nil
248
+ hash['3'].should == nil
249
+ end
250
+
251
+ it "should store values" do
252
+ hash = HashWithIndifferentAccess.new
253
+ hash.store(:test1, 1)
254
+ hash.store('test1', 11)
255
+ hash[:test2] = 2
256
+ hash['test2'] = 22
257
+ expected = { "test1" => 11, "test2" => 22 }
258
+ hash.should == expected
259
+ end
260
+ end
261
+
262
+ describe "update" do
263
+ before do
264
+ @hash = HashWithIndifferentAccess.new
265
+ @hash[:a] = 'a'
266
+ @hash['b'] = 'b'
267
+ end
268
+
269
+ it "should update with string keys" do
270
+ updated_with_strings = @hash.update(@strings)
271
+ updated_with_strings[:a].should == 1
272
+ updated_with_strings['a'].should == 1
273
+ updated_with_strings['b'].should == 2
274
+
275
+ updated_with_strings.keys.size.should == 2
276
+ end
277
+
278
+ it "should update with symbol keys" do
279
+ updated_with_symbols = @hash.update(@symbols)
280
+ updated_with_symbols[:a].should == 1
281
+ updated_with_symbols['b'].should == 2
282
+ updated_with_symbols[:b].should == 2
283
+
284
+ updated_with_symbols.keys.size.should == 2
285
+ end
286
+
287
+ it "should update with mixed keys" do
288
+ updated_with_mixed = @hash.update(@mixed)
289
+ updated_with_mixed[:a].should == 1
290
+ updated_with_mixed['b'].should == 2
291
+
292
+ updated_with_mixed.keys.size.should == 2
293
+ end
294
+ end
295
+
296
+ describe "merge" do
297
+ describe "without block" do
298
+ before do
299
+ @hash = HashWithIndifferentAccess.new
300
+ @hash[:a] = 'failure'
301
+ @hash['b'] = 'failure'
302
+
303
+ @other = { 'a' => 1, :b => 2 }
304
+ end
305
+
306
+ it "should merge with mixed hash" do
307
+ merged = @hash.merge(@other)
308
+
309
+ merged.class.should == HashWithIndifferentAccess
310
+ merged[:a].should == 1
311
+ merged['b'].should == 2
312
+ end
313
+
314
+ it "should have the same effect inplace when updating" do
315
+ @hash.update(@other)
316
+
317
+ @hash[:a].should == 1
318
+ @hash['b'].should == 2
319
+ end
320
+ end
321
+
322
+ describe "with block" do
323
+ before do
324
+ @hash = HashWithIndifferentAccess.new
325
+ @hash[:a] = 1
326
+ @hash['b'] = 3
327
+ end
328
+
329
+ it "should merge with block" do
330
+ other = { 'a' => 4, :b => 2, 'c' => 10 }
331
+
332
+ merged = @hash.merge(other) { |key, old, new| old > new ? old : new }
333
+
334
+ merged.class.should == HashWithIndifferentAccess
335
+ merged[:a].should == 4
336
+ merged['b'].should == 3
337
+ merged[:c].should == 10
338
+ end
339
+
340
+ it "should merge with block one more time" do
341
+ other_indifferent = HashWithIndifferentAccess.new('a' => 9, :b => 2)
342
+
343
+ merged = @hash.merge(other_indifferent) { |key, old, new| old + new }
344
+
345
+ merged.class.should == HashWithIndifferentAccess
346
+ merged[:a].should == 10
347
+ merged[:b].should == 5
348
+ end
349
+ end
350
+ end
351
+
352
+ describe "reverse_merge" do
353
+ it "should reverse merge" do
354
+ hash = HashWithIndifferentAccess.new('some' => 'value', 'other' => 'value')
355
+ hash.reverse_merge!(:some => 'noclobber', :another => 'clobber')
356
+ hash[:some].should == 'value'
357
+ hash[:another].should == 'clobber'
358
+ end
359
+ end
360
+
361
+ describe "replace" do
362
+ before do
363
+ @hash = HashWithIndifferentAccess.new
364
+ @hash[:a] = 42
365
+
366
+ @replaced = @hash.replace(b: 12)
367
+ end
368
+
369
+ it "should replace with regular hash" do
370
+ @hash.key?('b').should == true
371
+ @hash.key?(:a).should == false
372
+ @hash[:b].should == 12
373
+ end
374
+
375
+ it "should be the same class" do
376
+ @replaced.class.should == HashWithIndifferentAccess
377
+ end
378
+
379
+ it "should be the same object" do
380
+ @hash.object_id.should == @replaced.object_id
381
+ end
382
+ end
383
+
384
+ describe "delete" do
385
+ before do
386
+ @hash = { :a => 'foo' }.with_indifferent_access
387
+ end
388
+
389
+ it "should delete with symbol keys" do
390
+ @hash.delete(:a).should == 'foo'
391
+ @hash.delete(:a).should == nil
392
+ end
393
+
394
+ it "should delete with string keys" do
395
+ @hash.delete('a').should == 'foo'
396
+ @hash.delete('a').should == nil
397
+ end
398
+ end
399
+
400
+ describe "to_hash" do
401
+ it "should return a hash with string keys" do
402
+ @mixed.with_indifferent_access.to_hash.should == @strings
403
+ end
404
+
405
+ it "should preserve the default value" do
406
+ mixed_with_default = @mixed.dup
407
+ mixed_with_default.default = '1234'
408
+ roundtrip = mixed_with_default.with_indifferent_access.to_hash
409
+ roundtrip.should == @strings
410
+ roundtrip.default.should == '1234'
411
+ end
412
+ end
413
+
414
+ describe "to_options" do
415
+ it "should preserve hash" do
416
+ h = HashWithIndifferentAccess.new
417
+ h['first'] = 1
418
+ h.to_options!
419
+ h['first'].should == 1
420
+ end
421
+ end
422
+
423
+ describe "nesting" do
424
+ it "should preserve hash subclasses in nested hashes" do
425
+ foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
426
+ foo["foo"].should.is_a MotionSupport::HashWithIndifferentAccess
427
+
428
+ foo = { "foo" => NonIndifferentHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
429
+ foo["foo"].should.is_a NonIndifferentHash
430
+
431
+ foo = { "foo" => IndifferentHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
432
+ foo["foo"].should.is_a IndifferentHash
433
+ end
434
+
435
+ it "should deep apply indifferent access" do
436
+ hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
437
+ hash[:urls][:url].first[:address].should == "1"
438
+ end
439
+
440
+ it "should preserve array subclass when value is array" do
441
+ array = SubclassingArray.new
442
+ array << { "address" => "1" }
443
+ hash = { "urls" => { "url" => array }}.with_indifferent_access
444
+ hash[:urls][:url].class.should == SubclassingArray
445
+ end
446
+
447
+ it "should preserve array class when hash value is frozen array" do
448
+ array = SubclassingArray.new
449
+ array << { "address" => "1" }
450
+ hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access
451
+ hash[:urls][:url].class.should == SubclassingArray
452
+ end
453
+
454
+ it "should allow indifferent access on sub hashes" do
455
+ h = {'user' => {'id' => 5}}.with_indifferent_access
456
+ ['user', :user].each { |user| [:id, 'id'].each { |id| h[user][id].should == 5 } }
457
+
458
+ h = {:user => {:id => 5}}.with_indifferent_access
459
+ ['user', :user].each { |user| [:id, 'id'].each { |id| h[user][id].should == 5 } }
460
+ end
461
+ end
462
+
463
+ describe "dup" do
464
+ it "should preserve default value" do
465
+ h = HashWithIndifferentAccess.new
466
+ h.default = '1234'
467
+ h.dup.default.should == h.default
468
+ end
469
+
470
+ it "should preserve class for subclasses" do
471
+ h = IndifferentHash.new
472
+ h.dup.class.should == h.class
473
+ end
474
+ end
475
+
476
+ describe "deep_merge" do
477
+ it "should deep merge" do
478
+ hash_1 = HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } })
479
+ hash_2 = HashWithIndifferentAccess.new({ :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } })
480
+ hash_3 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }
481
+ expected = { "a" => 1, "b" => "b", "c" => { "c1" => 2, "c2" => "c2", "c3" => { "d1" => "d1", "d2" => "d2" } } }
482
+ hash_1.deep_merge(hash_2).should == expected
483
+ hash_1.deep_merge(hash_3).should == expected
484
+
485
+ hash_1.deep_merge!(hash_2)
486
+ hash_1.should == expected
487
+ end
488
+ end
489
+
490
+ describe "slice" do
491
+ it "should slice with indiffent keys" do
492
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
493
+ expected = { :a => 'x', :b => 'y' }.with_indifferent_access
494
+
495
+ [['a', 'b'], [:a, :b]].each do |keys|
496
+ # Should return a new hash with only the given keys.
497
+ original.slice(*keys).should == expected
498
+ original.should.not == expected
499
+ end
500
+ end
501
+
502
+ it "should silce in place" do
503
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
504
+ expected = { :c => 10 }.with_indifferent_access
505
+
506
+ [['a', 'b'], [:a, :b]].each do |keys|
507
+ # Should replace the hash with only the given keys.
508
+ copy = original.dup
509
+ copy.slice!(*keys).should == expected
510
+ end
511
+ end
512
+
513
+ it "should slice sliced hash" do
514
+ original = {'login' => 'bender', 'password' => 'shiny', 'stuff' => 'foo'}
515
+ original = original.with_indifferent_access
516
+
517
+ slice = original.slice(:login, :password)
518
+
519
+ slice[:login].should == 'bender'
520
+ slice['login'].should == 'bender'
521
+ end
522
+ end
523
+
524
+ describe "extract!" do
525
+ it "should extract values with indifferent keys" do
526
+ original = {:a => 1, 'b' => 2, :c => 3, 'd' => 4}.with_indifferent_access
527
+ expected = {:a => 1, :b => 2}.with_indifferent_access
528
+ remaining = {:c => 3, :d => 4}.with_indifferent_access
529
+
530
+ [['a', 'b'], [:a, :b]].each do |keys|
531
+ copy = original.dup
532
+ copy.extract!(*keys).should == expected
533
+ copy.should == remaining
534
+ end
535
+ end
536
+ end
537
+
538
+ describe "default value" do
539
+ it "should use the default value for unknown key" do
540
+ hash_wia = HashWithIndifferentAccess.new(3)
541
+ hash_wia[:new_key].should == 3
542
+ end
543
+
544
+ it "should use default value if no key is supplied" do
545
+ hash_wia = HashWithIndifferentAccess.new(3)
546
+ hash_wia.default.should == 3
547
+ end
548
+
549
+ it "should nil if no default value is supplied" do
550
+ hash_wia = HashWithIndifferentAccess.new
551
+ hash_wia.default.should.be.nil
552
+ end
553
+
554
+ it "should copy the default value when converting to hash with indifferent access" do
555
+ hash = Hash.new(3)
556
+ hash_wia = hash.with_indifferent_access
557
+ hash_wia.default.should == 3
558
+ end
559
+ end
560
+
561
+ describe "fetch" do
562
+ it "should fetch with indifferent access" do
563
+ @strings = @strings.with_indifferent_access
564
+
565
+ @strings.fetch('a').should == 1
566
+ @strings.fetch(:a.to_s).should == 1
567
+ @strings.fetch(:a).should == 1
568
+ end
569
+ end
570
+
571
+ describe "values_at" do
572
+ it "should return values for multiple keys" do
573
+ @strings = @strings.with_indifferent_access
574
+ @symbols = @symbols.with_indifferent_access
575
+ @mixed = @mixed.with_indifferent_access
576
+
577
+ @strings.values_at('a', 'b').should == [1, 2]
578
+ @strings.values_at(:a, :b).should == [1, 2]
579
+ @symbols.values_at('a', 'b').should == [1, 2]
580
+ @symbols.values_at(:a, :b).should == [1, 2]
581
+ @mixed.values_at('a', 'b').should == [1, 2]
582
+ @mixed.values_at(:a, :b).should == [1, 2]
583
+ end
584
+ end
585
+
586
+ describe "misc methods" do
587
+ it "should work as expected" do
588
+ @strings = @strings.with_indifferent_access
589
+ @symbols = @symbols.with_indifferent_access
590
+ @mixed = @mixed.with_indifferent_access
591
+
592
+ hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed }
593
+ method_map = { :'[]' => 1, :fetch => 1, :values_at => [1],
594
+ :has_key? => true, :include? => true, :key? => true,
595
+ :member? => true }
596
+
597
+ hashes.each do |name, hash|
598
+ method_map.sort_by { |m| m.to_s }.each do |meth, expected|
599
+ hash.__send__(meth, 'a').should == expected
600
+ hash.__send__(meth, :a).should == expected
601
+ end
602
+ end
603
+ end
604
+ end
605
+ end