gorillib 0.0.8 → 0.1.0

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 (64) hide show
  1. data/CHANGELOG.textile +6 -0
  2. data/README.textile +34 -11
  3. data/VERSION +1 -1
  4. data/gorillib.gemspec +63 -5
  5. data/lib/gorillib/enumerable/sum.rb +2 -2
  6. data/lib/gorillib/hash/compact.rb +2 -29
  7. data/lib/gorillib/hash/deep_compact.rb +2 -12
  8. data/lib/gorillib/hash/deep_dup.rb +4 -0
  9. data/lib/gorillib/hash/deep_merge.rb +2 -14
  10. data/lib/gorillib/hash/indifferent_access.rb +207 -0
  11. data/lib/gorillib/hash/keys.rb +2 -40
  12. data/lib/gorillib/hash/reverse_merge.rb +2 -24
  13. data/lib/gorillib/hash/slice.rb +2 -51
  14. data/lib/gorillib/hash/tree_merge.rb +4 -0
  15. data/lib/gorillib/hashlike.rb +824 -0
  16. data/lib/gorillib/hashlike/compact.rb +60 -0
  17. data/lib/gorillib/hashlike/deep_compact.rb +18 -0
  18. data/lib/gorillib/hashlike/deep_dup.rb +15 -0
  19. data/lib/gorillib/hashlike/deep_merge.rb +20 -0
  20. data/lib/gorillib/hashlike/hashlike_via_accessors.rb +169 -0
  21. data/lib/gorillib/hashlike/keys.rb +59 -0
  22. data/lib/gorillib/hashlike/reverse_merge.rb +31 -0
  23. data/lib/gorillib/hashlike/slice.rb +67 -0
  24. data/lib/gorillib/hashlike/tree_merge.rb +76 -0
  25. data/lib/gorillib/metaprogramming/mattr_accessor.rb +1 -1
  26. data/lib/gorillib/receiver.rb +315 -0
  27. data/lib/gorillib/receiver/active_model_shim.rb +19 -0
  28. data/lib/gorillib/receiver/acts_as_hash.rb +191 -0
  29. data/lib/gorillib/receiver/acts_as_loadable.rb +42 -0
  30. data/lib/gorillib/receiver/tree_diff.rb +74 -0
  31. data/lib/gorillib/receiver/validations.rb +30 -0
  32. data/lib/gorillib/struct/acts_as_hash.rb +108 -0
  33. data/lib/gorillib/struct/hashlike_iteration.rb +0 -0
  34. data/notes/fancy_hashes_and_receivers.textile +120 -0
  35. data/notes/hash_rdocs.textile +97 -0
  36. data/spec/hash/deep_merge_spec.rb +0 -2
  37. data/spec/hash/indifferent_access_spec.rb +391 -0
  38. data/spec/hash/slice_spec.rb +35 -12
  39. data/spec/hashlike/behave_same_as_hash_spec.rb +105 -0
  40. data/spec/hashlike/hashlike_behavior_spec.rb +824 -0
  41. data/spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb +37 -0
  42. data/spec/hashlike/hashlike_via_accessors_spec.rb +262 -0
  43. data/spec/hashlike_spec.rb +302 -0
  44. data/spec/metaprogramming/aliasing_spec.rb +3 -0
  45. data/spec/metaprogramming/cattr_accessor_spec.rb +2 -0
  46. data/spec/metaprogramming/class_attribute_spec.rb +2 -0
  47. data/spec/metaprogramming/delegation_spec.rb +2 -0
  48. data/spec/metaprogramming/mattr_accessor_spec.rb +2 -0
  49. data/spec/metaprogramming/singleton_class_spec.rb +3 -0
  50. data/spec/receiver/acts_as_hash_spec.rb +286 -0
  51. data/spec/receiver_spec.rb +478 -0
  52. data/spec/spec_helper.rb +11 -6
  53. data/spec/string/truncate_spec.rb +1 -0
  54. data/spec/struct/acts_as_hash_fuzz_spec.rb +67 -0
  55. data/spec/struct/acts_as_hash_spec.rb +426 -0
  56. data/spec/support/hashlike_fuzzing_helper.rb +127 -0
  57. data/spec/support/hashlike_helper.rb +75 -0
  58. data/spec/support/hashlike_struct_helper.rb +37 -0
  59. data/spec/support/hashlike_via_delegation.rb +30 -0
  60. data/spec/support/matchers/be_array_eql.rb +12 -0
  61. data/spec/support/matchers/be_hash_eql.rb +14 -0
  62. data/spec/support/matchers/enumerate_method.rb +10 -0
  63. data/spec/support/matchers/evaluate_to_true.rb +5 -0
  64. metadata +62 -4
@@ -2,16 +2,21 @@ require 'rubygems' unless defined?(Gem)
2
2
  require 'spork'
3
3
  require 'rspec'
4
4
 
5
- Spork.prefork do
6
- # You'll need to restart for changes to configuration or code from libraries loaded here
5
+ GORILLIB_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__),'..'))
6
+ def GORILLIB_ROOT_DIR *paths
7
+ File.join(::GORILLIB_ROOT_DIR, *paths)
8
+ end
7
9
 
8
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+ Spork.prefork do # Must restart for changes to config / code from libraries loaded here
11
+ $LOAD_PATH.unshift(GORILLIB_ROOT_DIR('lib'))
12
+ $LOAD_PATH.unshift(GORILLIB_ROOT_DIR('spec/support'))
13
+ Dir[GORILLIB_ROOT_DIR('spec/support/matchers/*.rb')].each {|f| require f}
10
14
 
11
15
  RSpec.configure do |config|
12
16
  end
13
17
  end
14
18
 
15
- Spork.each_run do
16
- # This code will be run each time you run your specs.
19
+ Spork.each_run do # This code will be run each time you run your specs.
20
+ RSpec.configure do |config|
21
+ end
17
22
  end
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__)+'/../spec_helper'
2
+ require GORILLIB_ROOT_DIR('spec/support/kcode_test_helper')
2
3
  require 'gorillib/string/truncate'
3
4
 
4
5
  describe String do
@@ -0,0 +1,67 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hashlike'
3
+ require 'gorillib/struct/acts_as_hash'
4
+ require 'gorillib/hash/indifferent_access'
5
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_fuzzing_helper')
6
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_helper')
7
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_struct_helper')
8
+
9
+ #
10
+ # Don't test the built-in Struct methods.
11
+ #
12
+ # Also, all the enumerable methods behave differently -- they build off each
13
+ # (which iterates like an array), not each_pair (which iterates like a hash)
14
+ #
15
+ STRUCT_HASHLIKE_METHODS_TO_SKIP = [:each, :flatten, :clear, :values_at] +
16
+ Enumerable.public_instance_methods.map(&:to_sym) +
17
+ HashlikeHelper::HASH_METHODS_MISSING_FROM_VERSION
18
+
19
+ include HashlikeFuzzingHelper
20
+
21
+ describe "Hash vs Gorillib::Struct::ActsAsHash" do
22
+ before do
23
+ @total = 0
24
+ @hsh = HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT.dup
25
+ @hshlike = StructUsingHashlike.new.merge(HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
26
+ end
27
+
28
+ ( HashlikeHelper::METHODS_TO_TEST - STRUCT_HASHLIKE_METHODS_TO_SKIP ).each do |method_to_test|
29
+ describe "##{method_to_test}" do
30
+
31
+ (HashlikeFuzzingHelper::INPUTS_FOR_ALL_HASHLIKES).each do |input|
32
+ next if HashlikeFuzzingHelper::SPECIAL_CASES_FOR_HASHLIKE_STRUCT[method_to_test].include?(input)
33
+
34
+ it "on #{input.inspect}" do
35
+ behaves_the_same(@hsh, @hshlike, method_to_test, input)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "Gorillib::HashWithIndifferentSymbolKeys vs Gorillib::Struct::ActsAsHash" do
43
+ before do
44
+ @total = 0
45
+ @hsh = Gorillib::HashWithIndifferentSymbolKeys.new_from_hash_copying_default(
46
+ HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
47
+ @hshlike = StructUsingHashlike.new.merge(
48
+ HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
49
+ end
50
+
51
+ ( HashlikeHelper::METHODS_TO_TEST - STRUCT_HASHLIKE_METHODS_TO_SKIP
52
+ ).each do |method_to_test|
53
+ describe "##{method_to_test}" do
54
+
55
+ ( HashlikeFuzzingHelper::INPUTS_WHEN_INDIFFERENT_ACCESS +
56
+ HashlikeFuzzingHelper::INPUTS_FOR_ALL_HASHLIKES
57
+ ).each do |input|
58
+ next if HashlikeFuzzingHelper::SPECIAL_CASES_FOR_HASHLIKE_STRUCT[method_to_test].include?(input)
59
+
60
+ it "on #{input.inspect}" do
61
+ behaves_the_same(@hsh, @hshlike, method_to_test, input)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,426 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hashlike'
3
+ require 'gorillib/struct/acts_as_hash'
4
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_via_delegation')
5
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_helper')
6
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_fuzzing_helper')
7
+ require GORILLIB_ROOT_DIR('spec/support/hashlike_struct_helper')
8
+ require GORILLIB_ROOT_DIR('spec/hashlike/hashlike_behavior_spec')
9
+
10
+
11
+
12
+
13
+
14
+ describe Gorillib::Struct::ActsAsHash do
15
+
16
+ before do
17
+ @hshlike = StructUsingHashlike.new.merge(HashlikeHelper::BASE_HSH.dup)
18
+ @empty_hshlike = StructUsingHashlike.new
19
+ @hshlike_with_array_vals = StructUsingHashlike.new.merge(HashlikeHelper::BASE_HSH_WITH_ARRAY_VALS.dup)
20
+ #
21
+ @hshlike_subklass = Class.new(StructUsingHashlike)
22
+ @hshlike_subklass_inst = @hshlike_subklass.new.merge(HashlikeHelper::BASE_HSH.dup)
23
+ end
24
+
25
+
26
+ # ===========================================================================
27
+ #
28
+ # Fundamental behavior
29
+
30
+ describe '#[] and #[]= and #store' do
31
+ it_should_behave_like :hashlike_store_and_retrieve
32
+ it_should_behave_like :references_string_and_symbol_keys_equivalently, ArgumentError
33
+ it 'reject unknown keys' do
34
+ lambda{ @hshlike[:fnord] = 69 }.should raise_error NameError, /no member 'fnord' in struct/
35
+ lambda{ @hshlike[:fnord] }.should raise_error NameError, /no member 'fnord' in struct/
36
+ @hshlike.delete(:fnord).should be_nil
37
+ end
38
+ it 'accepts defined but unset keys' do
39
+ @hshlike[:new_key].should be_nil
40
+ @hshlike[:new_key] = 69
41
+ @hshlike[:new_key].should == 69
42
+ end
43
+ it 'does not allow nil, Object, and other non-stringy keys' do
44
+ lambda{ @hshlike[300] = :i_haz_num }.should raise_error(IndexError, /offset 300 too large for struct/)
45
+ lambda{ @hshlike[nil] = :i_haz_nil }.should raise_error(TypeError, "no implicit conversion from nil to integer")
46
+ obj = Object.new
47
+ lambda{ @hshlike[obj] = :i_haz_obj }.should raise_error(TypeError, "can't convert Object into Integer")
48
+ def obj.to_sym() :c ; end
49
+ lambda{ @hshlike[obj] = :i_haz_obj }.should raise_error(TypeError, "can't convert Object into Integer")
50
+ end
51
+ end
52
+
53
+ describe '#delete' do
54
+ it 'removes the key/value association and returns the value' do
55
+ @hshlike.delete(:a).should == 100
56
+ @hshlike.delete(:is_missing).should be_nil
57
+ @hshlike.delete(:false_val).should == false
58
+ @hshlike.should be_hash_eql({ :b => 200, :c => 300, :nil_val => nil })
59
+ end
60
+ describe 'with optional code block' do
61
+ it 'returns the value of executing the block (passing in the key)' do
62
+ set_in_block = nil
63
+ ret_val = @hshlike.delete(:is_missing){|k| set_in_block = "got: #{k}" ; "hello!" }
64
+ set_in_block.should == "got: is_missing"
65
+ ret_val.should == "hello!"
66
+ end
67
+ end
68
+ it 'will have a nil value but will still include? key after deleting' do
69
+ @hshlike.should include(:a)
70
+ @hshlike.delete(:a)
71
+ @hshlike.should include(:a)
72
+ @hshlike[:a].should be_nil
73
+ end
74
+ end
75
+
76
+ describe '#keys' do
77
+ it 'lists keys, even where values are nil' do
78
+ @hshlike.keys.should be_array_eql([:a, :b, :c, :nil_val, :false_val, :new_key])
79
+ @hshlike[:nil_val].should be_nil
80
+ end
81
+ it 'is the full list of members, even when nothing has been set' do
82
+ @empty_hshlike.keys.should be_array_eql([:a, :b, :c, :nil_val, :false_val, :new_key])
83
+ end
84
+ it 'is the symbolized members list' do
85
+ @empty_hshlike.keys.map(&:to_s).should == @empty_hshlike.members.map(&:to_s)
86
+ end
87
+ end
88
+
89
+ # ===========================================================================
90
+ #
91
+ # Iteration
92
+
93
+ describe '#each_pair' do
94
+ describe 'with block' do
95
+ it_should_behave_like :each_pair_on_stringlike_fixed_keys, :each_pair
96
+ end
97
+ it_should_behave_like :with_no_block_returns_enumerator, :each_pair
98
+ end
99
+
100
+ describe '#each' do
101
+ describe 'with block' do
102
+ it 'calls block once for each *val* in hsh !like array not hash!' do
103
+ seen_arg1 = []
104
+ seen_arg2 = []
105
+ @hshlike.each{|arg1,arg2| seen_arg1 << arg1 ; seen_arg2 << arg2 }
106
+ seen_arg1.should be_array_eql([100, 200, 300, nil, false, nil])
107
+ seen_arg2.should be_array_eql([nil, nil, nil, nil, nil, nil])
108
+ end
109
+ it 'with arity 1, returns keys only' do
110
+ seen_args = []
111
+ @hshlike.each{|arg| seen_args << arg }
112
+ seen_args.should be_array_eql([100, 200, 300, nil, false, nil])
113
+ end
114
+ it 'handles array keys' do
115
+ seen_args = []
116
+ @hshlike_with_array_vals.each{|arg1, arg2, arg3| seen_args << [arg1, arg2, arg3] }
117
+ seen_args.should be_array_eql([[100, 111, nil], [200, nil, nil], [1, [2, 3, [4, 5, 6]], nil], [nil, nil, nil], [nil, nil, nil], [nil, nil, nil]])
118
+ seen_args = []
119
+ @hshlike_with_array_vals.each{|(arg1, arg2), arg3| seen_args << [arg1, arg2, arg3] }
120
+ seen_args.should be_array_eql([[100, nil, 111], [200, nil, nil], [1, nil, [2, 3, [4, 5, 6]]], [nil, nil, nil], [nil, nil, nil], [nil, nil, nil]])
121
+ end
122
+ it 'returns self' do
123
+ ret_val = @hshlike.each{|k,v| 3 }
124
+ ret_val.should equal(@hshlike)
125
+ end
126
+ end
127
+ it_should_behave_like :with_no_block_returns_enumerator, :each
128
+ end
129
+
130
+ describe '#each_key' do
131
+ describe 'with block' do
132
+ it_should_behave_like :each_key_on_stringlike_fixed_keys
133
+ end
134
+ it_should_behave_like :with_no_block_returns_enumerator, :each_key
135
+ end
136
+
137
+ describe '#each_value' do
138
+ describe 'with block' do
139
+ it_should_behave_like :each_value_on_stringlike_fixed_keys
140
+ end
141
+ it_should_behave_like :with_no_block_returns_enumerator, :each_value
142
+ end
143
+
144
+ # ===========================================================================
145
+ #
146
+ # Retrieval and Membership
147
+
148
+ describe '#values' do
149
+ it 'returns a new array populated with the values from hsh even when they were never set' do
150
+ @hshlike.values.should be_array_eql([100, 200, 300, nil, false, nil])
151
+ end
152
+ end
153
+
154
+ describe '#values_at' do
155
+ it 'takes positional, not symbol args' do
156
+ @hshlike.values_at(1, 0, 3, 5).should == [200, 100, nil, nil]
157
+ @hshlike.values_at(1, 1, 5, 3, 2, 5).should == [200, 200, nil, nil, 300, nil]
158
+ end
159
+ end
160
+
161
+ describe '#values_of' do
162
+ it_should_behave_like :hashlike_values_at_or_of, :values_of
163
+ end
164
+
165
+ describe '#length' do
166
+ it 'returns the number of key/value pairs in the hashlike' do
167
+ @hshlike.length.should == 6
168
+ @hshlike.length.should == @hshlike.members.length
169
+ @hshlike.delete(:a)
170
+ @hshlike.delete(:b)
171
+ @hshlike.length.should == 6
172
+ end
173
+ it 'is always the length of #members, regardless of contents' do
174
+ @empty_hshlike.length.should == 6
175
+ end
176
+ end
177
+
178
+ describe '#size' do
179
+ it 'returns the number of key/value pairs in the hashlike' do
180
+ @hshlike.size.should == 6
181
+ @hshlike.size.should == @hshlike.members.size
182
+ @hshlike.delete(:a)
183
+ @hshlike.delete(:b)
184
+ @hshlike.size.should == 6
185
+ end
186
+ it 'is always the length of #members, regardless of contents' do
187
+ @empty_hshlike.size.should == 6
188
+ end
189
+ end
190
+
191
+ describe '#has_key?' do
192
+ it_should_behave_like :hashlike_has_key_predefined_always_present, :has_key?
193
+ it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :has_key?
194
+ end
195
+
196
+ describe '#include?' do
197
+ it_should_behave_like :hashlike_has_key_predefined_always_present, :include?
198
+ it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :include?
199
+ end
200
+
201
+ describe '#key?' do
202
+ it_should_behave_like :hashlike_has_key_predefined_always_present, :key?
203
+ it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :key?
204
+ end
205
+
206
+ describe '#member?' do
207
+ it_should_behave_like :hashlike_has_key_predefined_always_present, :member?
208
+ it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :member?
209
+ end
210
+
211
+ describe '#has_value?' do
212
+ it_should_behave_like :hashlike_has_value?, :has_value?
213
+ end
214
+
215
+ describe '#value?' do
216
+ it_should_behave_like :hashlike_has_value?, :value?
217
+ end
218
+
219
+ describe '#fetch' do
220
+ it 'returns a value from the hashlike for the given key' do
221
+ @hshlike.fetch(:a).should == 100
222
+ @hshlike.fetch(:c).should == 300
223
+ @hshlike.fetch(:nil_val).should == nil
224
+ end
225
+ describe 'on a missing key' do
226
+ it 'with no other arguments, raises a +KeyError+ exception' do
227
+ lambda{ @hshlike.fetch(:is_missing) }.should raise_error(KeyError, 'key not found: :is_missing')
228
+ end
229
+ it 'if block given, runs the block with the given key and returns its value' do
230
+ set_in_block = nil
231
+ ret_val = @hshlike.fetch(:is_missing){|k| set_in_block = "got: #{k}" ; "hello!" }
232
+ ret_val.should == "hello!"
233
+ set_in_block.should == "got: is_missing"
234
+ end
235
+ it 'if default given, returns the default arg' do
236
+ ret_val = @hshlike.fetch(:is_missing, :returned_as_default)
237
+ ret_val.should == :returned_as_default
238
+ end
239
+ it 'if block and default are both given, issues a warning and runs the block' do
240
+ set_in_block = nil
241
+ ret_val = @hshlike.fetch(:is_missing, :spurious_default){|k| set_in_block = "got: #{k}" ; "hello!" }
242
+ ret_val.should == "hello!"
243
+ set_in_block.should == "got: is_missing"
244
+ end
245
+ end
246
+ it 'something something convert_key'
247
+ end
248
+
249
+ describe '#key' do
250
+ it_should_behave_like :hashlike_key
251
+ end
252
+
253
+ describe '#assoc' do
254
+ it_should_behave_like :hashlike_assoc
255
+ end
256
+
257
+ describe '#rassoc' do
258
+ it_should_behave_like :hashlike_rassoc
259
+ end
260
+
261
+ describe '#empty?' do
262
+ it 'returns true if the hashlike contains only nil values, false otherwise' do
263
+ @hshlike.empty?.should == false
264
+ @empty_hshlike.empty?.should == true
265
+ @empty_hshlike[:a] = false
266
+ @empty_hshlike.empty?.should == false
267
+ end
268
+ end
269
+
270
+ # ===========================================================================
271
+ #
272
+ # Update, merge!, merge
273
+
274
+
275
+ describe 'update' do
276
+ it_should_behave_like :merging_method, :update
277
+ it_should_behave_like :merging_method_with_struct_keys, :update
278
+ it_should_behave_like :merging_method_inplace, :update
279
+ end
280
+
281
+ describe '#merge!' do
282
+ it_should_behave_like :merging_method, :merge!
283
+ it_should_behave_like :merging_method_with_struct_keys, :merge!
284
+ it_should_behave_like :merging_method_inplace, :merge!
285
+ end
286
+
287
+ describe '#merge' do
288
+ it_should_behave_like :merging_method, :merge
289
+ it_should_behave_like :merging_method_with_struct_keys, :merge
290
+ it_should_behave_like :merging_method_returning_new, :merge
291
+ end
292
+
293
+ # ===========================================================================
294
+ #
295
+ # Filters
296
+
297
+ shared_examples_for :hashlike_filter_fixed_keys do |method_to_test|
298
+ it 'passes every key-value pair to block' do
299
+ seen_args = []
300
+ ret_val = @hshlike.send(method_to_test){|key,val| seen_args << [key, val] ; val && (val.to_i > 150) }
301
+ #
302
+ seen_args.should be_array_eql([[:a, 100], [:b, 200], [:c, 300], [:nil_val, nil], [:false_val, false], [:new_key, nil]])
303
+ end
304
+ it 'adapts to the arity of the block' do
305
+ seen_args = []
306
+ ret_val = @hshlike.send(method_to_test){|arg| seen_args << [arg] ; @hshlike[arg] && (@hshlike[arg].to_i > 150) }
307
+ #
308
+ seen_args.should be_array_eql([[:a], [:b], [:c], [:nil_val], [:false_val], [:new_key]])
309
+ end
310
+ describe 'with no block' do
311
+ it('returns an enumerator'){ @hshlike.send(method_to_test).should enumerate_method(@hshlike, method_to_test) }
312
+ end
313
+ end
314
+
315
+ describe '#reject!' do
316
+ it_should_behave_like :hashlike_filter_fixed_keys, :reject!
317
+ it_should_behave_like :rejection_filter, :reject!
318
+ it_should_behave_like :filter_modifies_self_returns_nil_if_unchanged, :reject!, false
319
+ end
320
+
321
+ describe '#select!' do
322
+ it_should_behave_like :hashlike_filter_fixed_keys, :select!
323
+ it_should_behave_like :selection_filter, :select!
324
+ it_should_behave_like :filter_modifies_self_returns_nil_if_unchanged, :select!, true
325
+ end
326
+
327
+ describe '#delete_if' do
328
+ it_should_behave_like :hashlike_filter_fixed_keys, :delete_if
329
+ it_should_behave_like :rejection_filter, :delete_if
330
+ it_should_behave_like :filter_modifies_self_returns_self, :delete_if, false
331
+ end
332
+
333
+ describe '#keep_if' do
334
+ it_should_behave_like :hashlike_filter_fixed_keys, :keep_if
335
+ it_should_behave_like :selection_filter, :keep_if
336
+ it_should_behave_like :filter_modifies_self_returns_self, :keep_if, true
337
+ end
338
+
339
+ # describe '#reject' do
340
+ # it_should_behave_like :hashlike_filter_fixed_keys, :select
341
+ # it_should_behave_like :selection_filter, :select
342
+ # it_should_behave_like :filter_does_not_modify_self_returns_same_class, :reject, false
343
+ # end
344
+ #
345
+ # describe '#select' do
346
+ # it_should_behave_like :hashlike_filter_fixed_keys, :select
347
+ # it_should_behave_like :selection_filter, :select
348
+ # it_should_behave_like :filter_does_not_modify_self_returns_same_class, :select, true
349
+ # end
350
+
351
+ describe '#clear' do
352
+ it_should_behave_like :hashlike_clear
353
+ end
354
+
355
+ # ===========================================================================
356
+ #
357
+ # Conversion
358
+
359
+ describe '#to_hash' do
360
+ it 'returns a new Hash with each key set to its associated value' do
361
+ ret_val = @hshlike.to_hash
362
+ ret_val.should be_an_instance_of(Hash)
363
+ ret_val.should == {:a=>100, :b=>200, :c=>300, :nil_val=>nil, :false_val=>false, :new_key=>nil}
364
+ end
365
+ end
366
+
367
+ if (RUBY_VERSION >= '1.9')
368
+ describe '#invert' do
369
+ it 'returns a new Hash using the values as keys, and the keys as values' do
370
+ ret_val = @hshlike.invert
371
+ ret_val.should == { 100 => :a, 200 => :b, 300 => :c, nil => :new_key, false => :false_val }
372
+ end
373
+ it 'with duplicate values, the result will contain only one of them as a key' do
374
+ @hshlike[:a] = 999
375
+ @hshlike[:new_key] = 999
376
+ @hshlike.invert.should == { 999 => :new_key, 200 => :b, 300 => :c, nil => :nil_val, false => :false_val }
377
+ end
378
+ it 'returns a Hash, not a self.class' do
379
+ ret_val = @hshlike.invert
380
+ ret_val.should be_an_instance_of(Hash)
381
+ end
382
+ end
383
+
384
+ describe '#flatten' do
385
+ it 'with no arg returns a one-dimensional flattening' do
386
+ ret_val = @hshlike_with_array_vals.flatten
387
+ ret_val.should == [ :a, [100, 111], :b, 200, :c, [1, [2, 3, [4, 5, 6]]], :nil_val, nil, :false_val, nil, :new_key, nil ]
388
+ end
389
+ it 'with no arg is same as level = 1' do
390
+ @hshlike_with_array_vals.flatten(1).should == @hshlike_with_array_vals.flatten
391
+ end
392
+ it 'with level == nil, returns a complete flattening' do
393
+ ret_val = @hshlike_with_array_vals.flatten(nil)
394
+ ret_val.should == [ :a, 100, 111, :b, 200, :c, 1, 2, 3, 4, 5, 6, :nil_val, nil, :false_val, nil, :new_key, nil ]
395
+ end
396
+ it 'with an arg, flattens to that level (0)' do
397
+ ret_val = @hshlike_with_array_vals.flatten(0)
398
+ ret_val.should == [ [:a, [100, 111]], [:b, 200], [:c, [1, [2, 3, [4, 5, 6]]]], [:nil_val, nil], [:false_val, nil], [:new_key, nil]]
399
+ end
400
+ it 'with an arg, flattens to that level (3)' do
401
+ ret_val = @hshlike_with_array_vals.flatten(3)
402
+ ret_val.should == [ :a, 100, 111, :b, 200, :c, 1, 2, 3, [4, 5, 6], :nil_val, nil, :false_val, nil, :new_key, nil ]
403
+ end
404
+ it 'with an arg, flattens to that level (4)' do
405
+ ret_val = @hshlike_with_array_vals.flatten(4)
406
+ ret_val.should == [ :a, 100, 111, :b, 200, :c, 1, 2, 3, 4, 5, 6, :nil_val, nil, :false_val, nil, :new_key, nil ]
407
+ ret_val.should == @hshlike_with_array_vals.flatten(999)
408
+ end
409
+ end
410
+ end
411
+
412
+ # ===========================================================================
413
+ #
414
+ # Sanity check
415
+
416
+ it 'built test objects correctly' do
417
+ @hshlike_subklass .should < @hshlike.class
418
+ @hshlike_subklass .should_not == @hshlike.class
419
+ @hshlike_subklass_inst .should be_a(StructUsingHashlike)
420
+ @hshlike_subklass_inst .should be_a(@hshlike_subklass)
421
+ @hshlike_subklass_inst .should_not be_an_instance_of(StructUsingHashlike)
422
+ @hshlike .should_not be_a(@hshlike_subklass)
423
+ @hshlike .should be_an_instance_of(StructUsingHashlike)
424
+ end
425
+
426
+ end