motion_blender-support 0.2.7

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 (182) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +4 -0
  5. data/HACKS.md +7 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +359 -0
  8. data/Rakefile +14 -0
  9. data/app/app_delegate.rb +5 -0
  10. data/examples/Inflector/.gitignore +16 -0
  11. data/examples/Inflector/Gemfile +5 -0
  12. data/examples/Inflector/Rakefile +13 -0
  13. data/examples/Inflector/app/app_delegate.rb +8 -0
  14. data/examples/Inflector/app/inflections.rb +5 -0
  15. data/examples/Inflector/app/inflector_view_controller.rb +109 -0
  16. data/examples/Inflector/app/words_view_controller.rb +101 -0
  17. data/examples/Inflector/resources/Default-568h@2x.png +0 -0
  18. data/examples/Inflector/spec/main_spec.rb +9 -0
  19. data/lib/motion-support/callbacks.rb +8 -0
  20. data/lib/motion-support/concern.rb +4 -0
  21. data/lib/motion-support/core_ext/array.rb +10 -0
  22. data/lib/motion-support/core_ext/class.rb +5 -0
  23. data/lib/motion-support/core_ext/hash.rb +13 -0
  24. data/lib/motion-support/core_ext/integer.rb +6 -0
  25. data/lib/motion-support/core_ext/module.rb +11 -0
  26. data/lib/motion-support/core_ext/numeric.rb +6 -0
  27. data/lib/motion-support/core_ext/object.rb +12 -0
  28. data/lib/motion-support/core_ext/range.rb +5 -0
  29. data/lib/motion-support/core_ext/string.rb +13 -0
  30. data/lib/motion-support/core_ext/time.rb +16 -0
  31. data/lib/motion-support/core_ext.rb +13 -0
  32. data/lib/motion-support/inflector.rb +8 -0
  33. data/lib/motion-support.rb +81 -0
  34. data/motion/_stdlib/array.rb +13 -0
  35. data/motion/_stdlib/cgi.rb +22 -0
  36. data/motion/_stdlib/date.rb +81 -0
  37. data/motion/_stdlib/enumerable.rb +9 -0
  38. data/motion/_stdlib/time.rb +19 -0
  39. data/motion/callbacks.rb +511 -0
  40. data/motion/concern.rb +122 -0
  41. data/motion/core_ext/array/access.rb +28 -0
  42. data/motion/core_ext/array/conversions.rb +86 -0
  43. data/motion/core_ext/array/extract_options.rb +11 -0
  44. data/motion/core_ext/array/grouping.rb +99 -0
  45. data/motion/core_ext/array/prepend_and_append.rb +7 -0
  46. data/motion/core_ext/array/wrap.rb +45 -0
  47. data/motion/core_ext/array.rb +19 -0
  48. data/motion/core_ext/class/attribute.rb +119 -0
  49. data/motion/core_ext/class/attribute_accessors.rb +168 -0
  50. data/motion/core_ext/date/acts_like.rb +8 -0
  51. data/motion/core_ext/date/calculations.rb +117 -0
  52. data/motion/core_ext/date/conversions.rb +56 -0
  53. data/motion/core_ext/date_and_time/calculations.rb +232 -0
  54. data/motion/core_ext/enumerable.rb +90 -0
  55. data/motion/core_ext/hash/deep_delete_if.rb +23 -0
  56. data/motion/core_ext/hash/deep_merge.rb +27 -0
  57. data/motion/core_ext/hash/except.rb +15 -0
  58. data/motion/core_ext/hash/indifferent_access.rb +19 -0
  59. data/motion/core_ext/hash/keys.rb +150 -0
  60. data/motion/core_ext/hash/reverse_merge.rb +22 -0
  61. data/motion/core_ext/hash/slice.rb +40 -0
  62. data/motion/core_ext/integer/inflections.rb +27 -0
  63. data/motion/core_ext/integer/multiple.rb +10 -0
  64. data/motion/core_ext/integer/time.rb +41 -0
  65. data/motion/core_ext/kernel/singleton_class.rb +6 -0
  66. data/motion/core_ext/metaclass.rb +8 -0
  67. data/motion/core_ext/module/aliasing.rb +69 -0
  68. data/motion/core_ext/module/anonymous.rb +19 -0
  69. data/motion/core_ext/module/attr_internal.rb +38 -0
  70. data/motion/core_ext/module/attribute_accessors.rb +64 -0
  71. data/motion/core_ext/module/delegation.rb +175 -0
  72. data/motion/core_ext/module/introspection.rb +60 -0
  73. data/motion/core_ext/module/reachable.rb +5 -0
  74. data/motion/core_ext/module/remove_method.rb +12 -0
  75. data/motion/core_ext/ns_dictionary.rb +14 -0
  76. data/motion/core_ext/ns_string.rb +14 -0
  77. data/motion/core_ext/numeric/bytes.rb +44 -0
  78. data/motion/core_ext/numeric/conversions.rb +49 -0
  79. data/motion/core_ext/numeric/time.rb +75 -0
  80. data/motion/core_ext/object/acts_like.rb +10 -0
  81. data/motion/core_ext/object/blank.rb +105 -0
  82. data/motion/core_ext/object/deep_dup.rb +44 -0
  83. data/motion/core_ext/object/duplicable.rb +87 -0
  84. data/motion/core_ext/object/inclusion.rb +15 -0
  85. data/motion/core_ext/object/instance_variables.rb +28 -0
  86. data/motion/core_ext/object/to_param.rb +58 -0
  87. data/motion/core_ext/object/to_query.rb +26 -0
  88. data/motion/core_ext/object/try.rb +78 -0
  89. data/motion/core_ext/range/include_range.rb +23 -0
  90. data/motion/core_ext/range/overlaps.rb +8 -0
  91. data/motion/core_ext/regexp.rb +5 -0
  92. data/motion/core_ext/string/access.rb +104 -0
  93. data/motion/core_ext/string/behavior.rb +6 -0
  94. data/motion/core_ext/string/exclude.rb +11 -0
  95. data/motion/core_ext/string/filters.rb +55 -0
  96. data/motion/core_ext/string/indent.rb +43 -0
  97. data/motion/core_ext/string/inflections.rb +178 -0
  98. data/motion/core_ext/string/starts_ends_with.rb +4 -0
  99. data/motion/core_ext/string/strip.rb +24 -0
  100. data/motion/core_ext/time/acts_like.rb +8 -0
  101. data/motion/core_ext/time/calculations.rb +215 -0
  102. data/motion/core_ext/time/conversions.rb +52 -0
  103. data/motion/descendants_tracker.rb +50 -0
  104. data/motion/duration.rb +104 -0
  105. data/motion/hash_with_indifferent_access.rb +253 -0
  106. data/motion/inflections.rb +67 -0
  107. data/motion/inflector/inflections.rb +203 -0
  108. data/motion/inflector/methods.rb +321 -0
  109. data/motion/logger.rb +47 -0
  110. data/motion/number_helper.rb +54 -0
  111. data/motion/version.rb +3 -0
  112. data/motion_blender-support.gemspec +21 -0
  113. data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
  114. data/spec/motion-support/_helpers/inflector_test_cases.rb +270 -0
  115. data/spec/motion-support/callback_spec.rb +702 -0
  116. data/spec/motion-support/concern_spec.rb +93 -0
  117. data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
  118. data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
  119. data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
  120. data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
  121. data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
  122. data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
  123. data/spec/motion-support/core_ext/array_spec.rb +16 -0
  124. data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
  125. data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
  126. data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
  127. data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
  128. data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
  129. data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
  130. data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
  131. data/spec/motion-support/core_ext/hash/deep_delete_if_spec.rb +19 -0
  132. data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
  133. data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
  134. data/spec/motion-support/core_ext/hash/key_spec.rb +236 -0
  135. data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
  136. data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
  137. data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
  138. data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
  139. data/spec/motion-support/core_ext/kernel/singleton_class_spec.rb +9 -0
  140. data/spec/motion-support/core_ext/metaclass_spec.rb +9 -0
  141. data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
  142. data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
  143. data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
  144. data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
  145. data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
  146. data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
  147. data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
  148. data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
  149. data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
  150. data/spec/motion-support/core_ext/numeric/conversions_spec.rb +40 -0
  151. data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
  152. data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
  153. data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
  154. data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
  155. data/spec/motion-support/core_ext/object/inclusion_spec.rb +34 -0
  156. data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
  157. data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
  158. data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
  159. data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
  160. data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
  161. data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
  162. data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
  163. data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
  164. data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
  165. data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
  166. data/spec/motion-support/core_ext/string/filter_spec.rb +49 -0
  167. data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
  168. data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
  169. data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
  170. data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
  171. data/spec/motion-support/core_ext/string_spec.rb +88 -0
  172. data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
  173. data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
  174. data/spec/motion-support/core_ext/time/conversion_spec.rb +53 -0
  175. data/spec/motion-support/descendants_tracker_spec.rb +58 -0
  176. data/spec/motion-support/duration_spec.rb +107 -0
  177. data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
  178. data/spec/motion-support/inflector_spec.rb +504 -0
  179. data/spec/motion-support/ns_dictionary_spec.rb +89 -0
  180. data/spec/motion-support/ns_string_spec.rb +182 -0
  181. data/spec/motion-support/number_helper_spec.rb +55 -0
  182. metadata +352 -0
@@ -0,0 +1,107 @@
1
+ describe "Duration" do
2
+ describe "threequals" do
3
+ it "should be a day" do
4
+ MotionSupport::Duration.should === 1.day
5
+ end
6
+
7
+ it "should not be an int" do
8
+ MotionSupport::Duration.should.not === 1.day.to_i
9
+ end
10
+
11
+ it "should not be a string" do
12
+ MotionSupport::Duration.should.not === 'foo'
13
+ end
14
+ end
15
+
16
+ describe "equals" do
17
+ it "should equal itself" do
18
+ 1.day.should == 1.day
19
+ end
20
+
21
+ it "should equal integer representation" do
22
+ 1.day.should == 1.day.to_i
23
+ end
24
+
25
+ it "should not equal string" do
26
+ 1.day.should.not == 'foo'
27
+ end
28
+ end
29
+
30
+ describe "inspect" do
31
+ it "should convert to string representation" do
32
+ 0.seconds.inspect.should == '0 seconds'
33
+ 1.month.inspect.should == '1 month'
34
+ (1.month + 1.day).inspect.should == '1 month and 1 day'
35
+ (6.months - 2.days).inspect.should == '6 months and -2 days'
36
+ 10.seconds.inspect.should == '10 seconds'
37
+ (10.years + 2.months + 1.day).inspect.should == '10 years, 2 months, and 1 day'
38
+ 1.week.inspect.should == '7 days'
39
+ 1.fortnight.inspect.should == '14 days'
40
+ end
41
+ end
42
+
43
+ describe "arithmetic" do
44
+ it "should not break when subtracting time from itself" do
45
+ lambda { Date.today - Date.today }.should.not.raise
46
+ end
47
+
48
+ it "should add with time" do
49
+ (1.second + 1).should == 1 + 1.second
50
+ end
51
+
52
+ def test_plus_with_time
53
+ assert_equal 1 + 1.second, 1.second + 1, "Duration + Numeric should == Numeric + Duration"
54
+ end
55
+
56
+ end
57
+
58
+ describe "fractions" do
59
+ describe "days" do
60
+ it "should support fractional days" do
61
+ 1.5.weeks.should == (86400 * 7) * 1.5
62
+ 1.7.weeks.should == (86400 * 7) * 1.7
63
+ end
64
+
65
+ it "should support since" do
66
+ t = 2.years.ago
67
+ 1.5.days.since(t).should == 36.hours.since(t)
68
+ end
69
+
70
+ it "should support ago" do
71
+ t = 2.years.ago
72
+ 1.5.days.ago(t).should == 36.hours.ago(t)
73
+ end
74
+ end
75
+
76
+ describe "weeks" do
77
+ it "should support fractional weeks" do
78
+ 1.5.days.should == 86400 * 1.5
79
+ 1.7.days.should == 86400 * 1.7
80
+ end
81
+
82
+ it "should support since" do
83
+ t = 2.years.ago
84
+ 1.5.weeks.since(t).should == (7 * 36).hours.since(t)
85
+ end
86
+
87
+ it "should support ago" do
88
+ t = 2.years.ago
89
+ 1.5.weeks.ago(t).should == (7 * 36).hours.ago(t)
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "delegation" do
95
+ it "should delegate with block" do
96
+ counter = 0
97
+ lambda { 1.minute.times { counter += 1 } }.should.not.raise
98
+ counter.should == 60
99
+ end
100
+ end
101
+
102
+ describe "to_json" do
103
+ it "should convert to json" do
104
+ 2.days.to_json.should == '172800'
105
+ end
106
+ end
107
+ end
@@ -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