gorillib 0.1.11 → 0.4.0pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +1 -2
  3. data/.yardopts +9 -0
  4. data/{CHANGELOG.textile → CHANGELOG.md} +35 -9
  5. data/Gemfile +21 -14
  6. data/Guardfile +19 -0
  7. data/{LICENSE.textile → LICENSE.md} +43 -29
  8. data/README.md +47 -52
  9. data/Rakefile +31 -30
  10. data/TODO.md +32 -0
  11. data/VERSION +1 -1
  12. data/examples/builder/ironfan.rb +133 -0
  13. data/examples/model/simple.rb +17 -0
  14. data/gorillib.gemspec +106 -86
  15. data/lib/alt/kernel/call_stack.rb +56 -0
  16. data/lib/gorillib/array/wrap.rb +53 -0
  17. data/lib/gorillib/base.rb +3 -3
  18. data/lib/gorillib/builder/field.rb +5 -0
  19. data/lib/gorillib/builder.rb +260 -0
  20. data/lib/gorillib/collection/has_collection.rb +31 -0
  21. data/lib/gorillib/collection.rb +129 -0
  22. data/lib/gorillib/configurable.rb +28 -0
  23. data/lib/gorillib/datetime/{flat.rb → to_flat.rb} +0 -0
  24. data/lib/gorillib/exception/confidence.rb +17 -0
  25. data/lib/gorillib/exception/raisers.rb +78 -0
  26. data/lib/gorillib/hash/mash.rb +202 -0
  27. data/lib/gorillib/hashlike/slice.rb +53 -19
  28. data/lib/gorillib/hashlike.rb +5 -3
  29. data/lib/gorillib/io/system_helpers.rb +30 -0
  30. data/lib/gorillib/logger/log.rb +18 -0
  31. data/lib/gorillib/metaprogramming/concern.rb +124 -0
  32. data/lib/gorillib/model/active_model_conversion.rb +68 -0
  33. data/lib/gorillib/model/active_model_naming.rb +87 -0
  34. data/lib/gorillib/model/active_model_shim.rb +33 -0
  35. data/lib/gorillib/model/base.rb +341 -0
  36. data/lib/gorillib/model/defaults.rb +71 -0
  37. data/lib/gorillib/model/errors.rb +14 -0
  38. data/lib/gorillib/model/factories.rb +372 -0
  39. data/lib/gorillib/model/field.rb +146 -0
  40. data/lib/gorillib/model/named_schema.rb +53 -0
  41. data/lib/gorillib/{struct/hashlike_iteration.rb → model/overlay.rb} +0 -0
  42. data/lib/gorillib/model/record_schema.rb +9 -0
  43. data/lib/gorillib/model/serialization.rb +23 -0
  44. data/lib/gorillib/model/validate.rb +22 -0
  45. data/lib/gorillib/model.rb +23 -0
  46. data/lib/gorillib/pathname.rb +78 -0
  47. data/lib/gorillib/{serialization.rb → serialization/to_wire.rb} +0 -0
  48. data/lib/gorillib/some.rb +11 -9
  49. data/lib/gorillib/string/constantize.rb +21 -14
  50. data/lib/gorillib/string/inflections.rb +6 -76
  51. data/lib/gorillib/string/inflector.rb +192 -0
  52. data/lib/gorillib/string/simple_inflector.rb +267 -0
  53. data/lib/gorillib/type/extended.rb +52 -0
  54. data/lib/gorillib/utils/capture_output.rb +28 -0
  55. data/lib/gorillib/utils/console.rb +131 -0
  56. data/lib/gorillib/utils/nuke_constants.rb +9 -0
  57. data/lib/gorillib/utils/stub_module.rb +33 -0
  58. data/spec/examples/builder/ironfan_spec.rb +37 -0
  59. data/spec/extlib/hash_spec.rb +64 -0
  60. data/spec/extlib/mash_spec.rb +312 -0
  61. data/spec/{array → gorillib/array}/compact_blank_spec.rb +2 -2
  62. data/spec/{array → gorillib/array}/extract_options_spec.rb +2 -2
  63. data/spec/gorillib/builder_spec.rb +187 -0
  64. data/spec/gorillib/collection_spec.rb +20 -0
  65. data/spec/gorillib/configurable_spec.rb +62 -0
  66. data/spec/{datetime → gorillib/datetime}/parse_spec.rb +3 -3
  67. data/spec/{datetime/flat_spec.rb → gorillib/datetime/to_flat_spec.rb} +4 -4
  68. data/spec/{enumerable → gorillib/enumerable}/sum_spec.rb +5 -5
  69. data/spec/gorillib/exception/raisers_spec.rb +60 -0
  70. data/spec/{hash → gorillib/hash}/compact_spec.rb +2 -2
  71. data/spec/{hash → gorillib/hash}/deep_compact_spec.rb +3 -3
  72. data/spec/{hash → gorillib/hash}/deep_merge_spec.rb +2 -2
  73. data/spec/{hash → gorillib/hash}/keys_spec.rb +2 -2
  74. data/spec/{hash → gorillib/hash}/reverse_merge_spec.rb +2 -2
  75. data/spec/{hash → gorillib/hash}/slice_spec.rb +2 -2
  76. data/spec/{hash → gorillib/hash}/zip_spec.rb +2 -2
  77. data/spec/{hashlike → gorillib/hashlike}/behave_same_as_hash_spec.rb +6 -3
  78. data/spec/{hashlike → gorillib/hashlike}/deep_hash_spec.rb +2 -2
  79. data/spec/{hashlike → gorillib/hashlike}/hashlike_behavior_spec.rb +32 -30
  80. data/spec/{hashlike → gorillib/hashlike}/hashlike_via_accessors_spec.rb +3 -3
  81. data/spec/{hashlike_spec.rb → gorillib/hashlike_spec.rb} +3 -3
  82. data/spec/{logger → gorillib/logger}/log_spec.rb +2 -2
  83. data/spec/{metaprogramming → gorillib/metaprogramming}/aliasing_spec.rb +3 -3
  84. data/spec/{metaprogramming → gorillib/metaprogramming}/class_attribute_spec.rb +3 -3
  85. data/spec/{metaprogramming → gorillib/metaprogramming}/delegation_spec.rb +3 -3
  86. data/spec/{metaprogramming → gorillib/metaprogramming}/singleton_class_spec.rb +3 -3
  87. data/spec/gorillib/model/record/defaults_spec.rb +108 -0
  88. data/spec/gorillib/model/record/factories_spec.rb +321 -0
  89. data/spec/gorillib/model/record/overlay_spec.rb +46 -0
  90. data/spec/gorillib/model/serialization_spec.rb +48 -0
  91. data/spec/gorillib/model_spec.rb +281 -0
  92. data/spec/{numeric → gorillib/numeric}/clamp_spec.rb +2 -2
  93. data/spec/{object → gorillib/object}/blank_spec.rb +2 -2
  94. data/spec/{object → gorillib/object}/try_dup_spec.rb +2 -2
  95. data/spec/{object → gorillib/object}/try_spec.rb +3 -2
  96. data/spec/gorillib/pathname_spec.rb +114 -0
  97. data/spec/{string → gorillib/string}/constantize_spec.rb +2 -2
  98. data/spec/{string → gorillib/string}/human_spec.rb +2 -2
  99. data/spec/{string → gorillib/string}/inflections_spec.rb +4 -3
  100. data/spec/{string → gorillib/string}/inflector_test_cases.rb +0 -0
  101. data/spec/{string → gorillib/string}/truncate_spec.rb +4 -10
  102. data/spec/gorillib/type/extended_spec.rb +120 -0
  103. data/spec/gorillib/utils/capture_output_spec.rb +71 -0
  104. data/spec/spec_helper.rb +8 -11
  105. data/spec/support/gorillib_test_helpers.rb +66 -0
  106. data/spec/support/hashlike_fuzzing_helper.rb +31 -33
  107. data/spec/support/hashlike_helper.rb +3 -3
  108. data/spec/support/model_test_helpers.rb +81 -0
  109. data/spec/support/shared_examples/included_module.rb +20 -0
  110. metadata +177 -158
  111. data/lib/gorillib/array/average.rb +0 -13
  112. data/lib/gorillib/array/sorted_median.rb +0 -11
  113. data/lib/gorillib/array/sorted_percentile.rb +0 -11
  114. data/lib/gorillib/array/sorted_sample.rb +0 -12
  115. data/lib/gorillib/dsl_object.rb +0 -64
  116. data/lib/gorillib/hash/indifferent_access.rb +0 -207
  117. data/lib/gorillib/hash/tree_merge.rb +0 -4
  118. data/lib/gorillib/hashlike/tree_merge.rb +0 -49
  119. data/lib/gorillib/metaprogramming/cattr_accessor.rb +0 -79
  120. data/lib/gorillib/metaprogramming/mattr_accessor.rb +0 -61
  121. data/lib/gorillib/receiver/active_model_shim.rb +0 -32
  122. data/lib/gorillib/receiver/acts_as_hash.rb +0 -195
  123. data/lib/gorillib/receiver/acts_as_loadable.rb +0 -42
  124. data/lib/gorillib/receiver/locale/en.yml +0 -27
  125. data/lib/gorillib/receiver/tree_diff.rb +0 -74
  126. data/lib/gorillib/receiver/validations.rb +0 -30
  127. data/lib/gorillib/receiver.rb +0 -402
  128. data/lib/gorillib/receiver_model.rb +0 -21
  129. data/lib/gorillib/struct/acts_as_hash.rb +0 -108
  130. data/notes/fancy_hashes_and_receivers.textile +0 -120
  131. data/notes/hash_rdocs.textile +0 -97
  132. data/spec/array/average_spec.rb +0 -24
  133. data/spec/array/sorted_median_spec.rb +0 -18
  134. data/spec/array/sorted_percentile_spec.rb +0 -24
  135. data/spec/array/sorted_sample_spec.rb +0 -28
  136. data/spec/dsl_object_spec.rb +0 -99
  137. data/spec/hash/indifferent_access_spec.rb +0 -391
  138. data/spec/metaprogramming/cattr_accessor_spec.rb +0 -43
  139. data/spec/metaprogramming/mattr_accessor_spec.rb +0 -45
  140. data/spec/receiver/acts_as_hash_spec.rb +0 -295
  141. data/spec/receiver_spec.rb +0 -551
  142. data/spec/struct/acts_as_hash_fuzz_spec.rb +0 -71
  143. data/spec/struct/acts_as_hash_spec.rb +0 -422
@@ -1,551 +0,0 @@
1
- require File.expand_path('spec_helper', File.dirname(__FILE__))
2
- require 'gorillib/metaprogramming/class_attribute'
3
- require 'gorillib/object/blank'
4
- require 'time'
5
- require 'date'
6
- require 'gorillib/receiver'
7
- require 'gorillib/array/extract_options'
8
-
9
- class Wide
10
- include Receiver
11
- rcvr_accessor :my_int, Integer
12
- end
13
-
14
- require 'gorillib/receiver/acts_as_hash'
15
- class StreetAddress
16
- include Receiver
17
- include Receiver::ActsAsHash
18
- rcvr_accessor :num, Integer
19
- rcvr_accessor :street, String
20
- rcvr_accessor :city, String
21
- rcvr_accessor :state, String
22
- rcvr_accessor :zip_code, Integer
23
- end
24
-
25
- class Vcard
26
- include Receiver
27
- include Receiver::ActsAsHash
28
- rcvr_accessor :name, String
29
- rcvr_accessor :home_address, StreetAddress
30
- rcvr_accessor :work_address, StreetAddress
31
- rcvr_accessor :phone, String
32
- end
33
-
34
- class RecursiveReceiver < Wide
35
- include Receiver
36
- rcvr_accessor :a, Integer
37
- rcvr_accessor :b, String
38
- rcvr_accessor :wide_rcvr_a, Wide
39
- rcvr_accessor :rec_field, RecursiveReceiver
40
- rcvr_accessor :wide_rcvr_b, Wide
41
- rcvr_accessor :c, String
42
- end
43
-
44
- describe Receiver do
45
- before do
46
- @klass = Class.new(Wide)
47
- end
48
-
49
- it 'tracks an order for the rcvrs' do
50
- @klass.rcvr_accessor :a, Integer
51
- @klass.rcvr_reader :b, Integer
52
- @klass.rcvr_writer :c, Integer
53
- @klass.rcvr :d, Integer
54
- @klass.receiver_attr_names.should == [:my_int, :a, :b, :c, :d]
55
- end
56
-
57
- describe '.receive' do
58
- it 'creates a new object and returns it' do
59
- obj = @klass.new
60
- @klass.should_receive(:new).and_return(obj)
61
- ret = @klass.receive({})
62
- ret.should equal(obj)
63
- end
64
-
65
- it 'invokes receive! on the new object' do
66
- obj = @klass.new
67
- @klass.should_receive(:new).and_return(obj)
68
- obj.should_receive(:receive!).with({})
69
- ret = @klass.receive({})
70
- end
71
-
72
- it 'passes extra args to the constructor' do
73
- obj = @klass.new
74
- @klass.should_receive(:new).with(:a, :b).and_return(obj)
75
- obj.should_receive(:receive!).with({})
76
- ret = @klass.receive(:a, :b, {})
77
- end
78
-
79
- it 'accepts an empty arg set (as if it got an empty hash)' do
80
- obj = mock
81
- @klass.should_receive(:new).and_return(obj)
82
- obj.should_receive(:receive!).with({})
83
- @klass.receive()
84
- end
85
-
86
- it 'accepts an empty hash' do
87
- obj = mock
88
- @klass.should_receive(:new).and_return(obj)
89
- obj.should_receive(:receive!).with({})
90
- @klass.receive({})
91
- end
92
-
93
- it 'uses the *last* arg as the hsh to receive' do
94
- obj = mock
95
- hsh_to_receive = { :a => :b }
96
- hsh_for_constructor = { :c => :d }
97
- @klass.should_receive(:new).with(hsh_for_constructor).and_return(obj)
98
- obj.should_receive(:receive!).with(hsh_to_receive)
99
- @klass.receive(hsh_for_constructor, hsh_to_receive)
100
- end
101
- end
102
-
103
- ADDRESS_TUPLE = ['Homer J Simpson', 742, 'Evergreen Terr', 'Springfield', 'AZ', 12345, 100, 'Industrial Way', 'Springfield', 'WY', 98765, '800-BITE-ME']
104
- ADDRESS_HASH = {
105
- :name => 'Homer J Simpson',
106
- :home_address => { :num => 742, :street => 'Evergreen Terr', :city => 'Springfield', :state => 'AZ', :zip_code => 12345 },
107
- :work_address => { :num => 100, :street => 'Industrial Way', :city => 'Springfield', :state => 'WY', :zip_code => 98765 },
108
- :phone => '800-BITE-ME'}
109
-
110
- describe '.consume_tuple' do
111
- it 'receives a tuple, assigning to rcvrs in order' do
112
- obj = Vcard.consume_tuple(ADDRESS_TUPLE.dup)
113
- obj.to_hash.should == ADDRESS_HASH
114
- end
115
-
116
- it 'allows empty tuple'
117
-
118
- it '?breaks? on too-long tuple'
119
- end
120
-
121
- describe '#to_tuple' do
122
- it 'flattens' do
123
- obj = Vcard.receive(ADDRESS_HASH)
124
- obj.to_tuple.should == ADDRESS_TUPLE
125
- end
126
- end
127
-
128
- describe '.tuple_keys' do
129
- it 'for a simple receiver, produces attrs in order' do
130
- StreetAddress.tuple_keys.should == [:num, :street, :city, :state, :zip_code]
131
- end
132
-
133
- it 'for a complex receiver, in-order traverses the tree' do
134
- Vcard.tuple_keys.should == [:name, :num, :street, :city, :state, :zip_code, :num, :street, :city, :state, :zip_code, :phone]
135
- end
136
-
137
- it 'does not recurse endlessly' do
138
- RecursiveReceiver.tuple_keys.should == [:my_int, :a, :b, :my_int, RecursiveReceiver, :my_int, :c]
139
- end
140
- end
141
-
142
- describe '.receive_foo' do
143
- it 'injects a superclass, so I can call super() in receive_foo'
144
- end
145
-
146
- describe '.rcvr' do
147
-
148
- it 'creates the receive_{whatever} method' do
149
- @klass.rcvr_accessor :a, Integer, :foo => :bar_a
150
- obj = @klass.new
151
- obj.should respond_to(:receive_a)
152
- end
153
-
154
- it 'stores the name, type and extra info into receiver_attrs, and the name (in order) into receiver_attr_names' do
155
- @klass.rcvr_accessor :a, Integer, :foo => :bar_a
156
- @klass.rcvr_reader :b, Integer, :foo => :bar_b
157
- @klass.rcvr :c, Integer, :foo => :bar_c
158
- @klass.receiver_attr_names.should == [:my_int, :a, :b, :c]
159
- @klass.receiver_attrs.should == {
160
- :my_int => {:type => Integer, :name => :my_int},
161
- :a => {:type => Integer, :name => :a, :foo => :bar_a},
162
- :b => {:type => Integer, :name => :b, :foo => :bar_b},
163
- :c => {:type => Integer, :name => :c, :foo => :bar_c},
164
- }
165
- end
166
-
167
- it 'does not replace the class attributes in-place, so that inheritance works' do
168
- old_receiver_attrs = @klass.receiver_attrs
169
- old_receiver_attr_names = @klass.receiver_attr_names
170
- @klass.rcvr_accessor :a, Integer, :foo => :bar_a
171
- old_receiver_attrs.should_not equal(@klass.receiver_attrs)
172
- old_receiver_attr_names.should_not equal(@klass.receiver_attr_names)
173
- end
174
-
175
- it 'accepts a type alias but uses the aliased class' do
176
- @klass.rcvr_accessor :my_symbol, :symbol
177
- @klass.rcvr_accessor :my_bytes, :bytes
178
- @klass.receiver_attrs[:my_symbol][:type].should == Symbol
179
- @klass.receiver_attrs[:my_bytes ][:type].should == String
180
- end
181
-
182
- it 'does not accept an unknown type' do
183
- lambda{ @klass.rcvr_accessor :my_symbol, :oxnard }.should raise_error(ArgumentError, "Can\'t handle type oxnard: is it a Class or one of the TYPE_ALIASES?")
184
- end
185
- end
186
-
187
- describe '.rcvr_accessor, .rcvr_reader, .rcvr_writer' do
188
- it 'accepts rcvr, rcvr_accessor, rcvr_reader, rcvr_writer' do
189
- @klass.rcvr_accessor :a, Integer
190
- @klass.rcvr_reader :b, Integer
191
- @klass.rcvr_writer :c, Integer
192
- @klass.rcvr :d, Integer
193
- obj = @klass.new
194
- obj.should respond_to(:a)
195
- obj.should respond_to(:a=)
196
- obj.should respond_to(:b)
197
- obj.should_not respond_to(:b=)
198
- obj.should_not respond_to(:c)
199
- obj.should respond_to(:c=)
200
- obj.should_not respond_to(:d)
201
- obj.should_not respond_to(:d=)
202
- end
203
-
204
- it 'delegates to rcvr' do
205
- @klass.should_receive(:rcvr).with(:a, Integer, {:foo => :bar}).ordered
206
- @klass.should_receive(:rcvr).with(:b, Integer, {:foo => :bar}).ordered
207
- @klass.should_receive(:rcvr).with(:c, Integer, {:foo => :bar}).ordered
208
- @klass.should_receive(:rcvr).with(:d, Integer, {:foo => :bar}).ordered
209
- @klass.rcvr_accessor :a, Integer, :foo => :bar
210
- @klass.rcvr_reader :b, Integer, :foo => :bar
211
- @klass.rcvr_writer :c, Integer, :foo => :bar
212
- @klass.rcvr :d, Integer, :foo => :bar
213
- end
214
-
215
- it 'does not modify parent class' do
216
- @klass.rcvr_accessor :a, Integer
217
- @klass.rcvr :d, Integer
218
- obj = Wide.new
219
- obj.should_not respond_to(:a)
220
- obj.should_not respond_to(:a=)
221
- Wide.receiver_attr_names.should == [:my_int]
222
- Wide.receiver_attrs.should == {:my_int => {:type => Integer, :name => :my_int}}
223
- end
224
- end
225
-
226
- describe 'default values' do
227
- it 'rcvr accepts a default for an attribute' do
228
- @klass.rcvr_reader :will_get_a_value, Integer, :default => 12
229
- @klass.rcvr_reader :has_a_default, Integer, :default => 5
230
- obj = @klass.receive(:my_int => 3, :will_get_a_value => 9)
231
- obj.my_int.should == 3
232
- obj.has_a_default.should == 5
233
- obj.will_get_a_value.should == 9
234
- end
235
-
236
- it 'does not use default if value is set-but-nil' do
237
- @klass.rcvr_reader :has_a_default, Integer, :default => 5
238
- obj = @klass.receive(:my_int => 3, :has_a_default => nil)
239
- obj.has_a_default.should be_nil
240
- end
241
- end
242
-
243
- describe 'required attributes' do
244
- it 'rcvr accepts required attributes'
245
- end
246
-
247
- describe 'typed collections' do
248
- it 'sets a type for an array with :of => Type' do
249
- @klass.rcvr_accessor :array_of_symbol, Array, :of => Symbol
250
- obj = @klass.receive(:array_of_symbol => [:a, 'b', 'c'])
251
- obj.array_of_symbol.should == [:a, :b, :c]
252
- end
253
-
254
- it 'accepts nil if value is nil' do
255
- @klass.rcvr_accessor :array_of_symbol, Array, :of => Symbol
256
- obj = @klass.receive(:array_of_symbol => nil)
257
- obj.array_of_symbol.should == nil
258
- end
259
-
260
- it 'accepts complex class as :of => Type' do
261
- class Foo ; include Receiver ; rcvr_accessor(:foo, Integer) ; end
262
- @klass.rcvr_accessor :array_of_obj, Array, :of => Foo
263
- obj = @klass.receive( :array_of_obj => [ {:foo => 3}, {:foo => 5} ] )
264
- obj.array_of_obj.first.foo.should == 3
265
- obj.array_of_obj.last.foo.should == 5
266
- end
267
-
268
- it 'sets a type for a hash with :of => Type' do
269
- @klass.rcvr_accessor :hash_of_symbol, Hash, :of => Symbol
270
- obj = @klass.receive(:hash_of_symbol => { :a => 'val_a', 'b' => :val_b , 'c' => 'val_c' })
271
- obj.hash_of_symbol.should == { :a => :val_a, 'b' => :val_b , 'c' => :val_c }
272
- end
273
- end
274
-
275
- describe '.rcvr_remaining' do
276
- it 'creates a dummy receiver for the extra params' do
277
- @klass.should_receive(:rcvr_reader).with(:bob, Hash, {:foo => :bar})
278
- @klass.rcvr_remaining :bob, :foo => :bar
279
- end
280
- it 'does not get params that go with defined attrs (even if there is no writer)' do
281
- @klass.rcvr_remaining :bob
282
- hsh = {:my_int => 3, :foo => :bar, :width => 5}
283
- obj = @klass.receive(hsh)
284
- obj.bob.should == {:foo => :bar, :width => 5}
285
- hsh.should == {:my_int => 3, :foo => :bar, :width => 5}
286
- end
287
- it 'does not get params whose key starts with "_"' do
288
- @klass.rcvr_remaining :bob
289
- hsh = {:my_int => 3, :foo => :bar, :width => 5, :_ignored => 9}
290
- obj = @klass.receive(hsh)
291
- obj.bob.should == {:foo => :bar, :width => 5}
292
- end
293
- it 'stores them, replacing a previous value' do
294
- @klass.rcvr_remaining :bob
295
- obj = @klass.new
296
- obj.instance_variable_set("@bob", {:foo => 9, :width => 333, :extra => :will_be_gone})
297
- obj.receive!({ :my_int => 3, :foo => :bar, :width => 5 })
298
- obj.bob.should == {:foo => :bar, :width => 5}
299
- end
300
- end
301
-
302
- describe '.after_receive, #run_after_receivers' do
303
- it 'calls each block in order' do
304
- @klass.after_receive{|hsh| hsh.i_am_calling_you_first }
305
- @klass.after_receive{|hsh| hsh.i_am_calling_you_second }
306
- @klass.after_receive{|hsh| hsh.i_am_calling_you_third }
307
- hsh = {:my_int => 3}
308
- hsh.should_receive(:i_am_calling_you_first).ordered
309
- hsh.should_receive(:i_am_calling_you_second).ordered
310
- hsh.should_receive(:i_am_calling_you_third).ordered
311
- @klass.receive(hsh)
312
- end
313
-
314
- it 'calls the block with the full receive hash' do
315
- @klass.after_receive{|hsh| hsh.i_am_calling_you }
316
- hsh = {}
317
- hsh.should_receive(:i_am_calling_you)
318
- @klass.receive(hsh)
319
- end
320
- end
321
-
322
- describe '#unset' do
323
- it 'nukes any existing instance_variable' do
324
- obj = @klass.new
325
- obj.my_int = 3
326
- obj.instance_variable_get('@my_int').should == 3
327
- obj.send(:unset!, :my_int)
328
- obj.instance_variable_get('@my_int').should be_nil
329
- obj.instance_variables.should == []
330
- end
331
-
332
- it 'succeeds even if instance_variable never set' do
333
- obj = @klass.new
334
- obj.send(:unset!, :my_int)
335
- obj.instance_variable_get('@my_int').should be_nil
336
- obj.instance_variables.should == []
337
- end
338
-
339
- end
340
-
341
- describe 'attr_set?' do
342
- it 'is set if the corresponding instance_variable exists' do
343
- obj = @klass.new
344
- obj.attr_set?(:my_int).should == false
345
- obj.instance_variable_set('@my_int', 3)
346
- obj.attr_set?(:my_int).should == true
347
- end
348
-
349
- it 'can be set but nil or false' do
350
- @klass.rcvr_accessor :bool_field, Boolean
351
- @klass.rcvr_accessor :str_field, String
352
- obj = @klass.new
353
- obj.attr_set?(:bool_field).should == false
354
- obj.attr_set?(:str_field).should == false
355
- obj.instance_variable_set('@bool_field', false)
356
- obj.instance_variable_set('@str_field', nil)
357
- obj.attr_set?(:bool_field).should == true
358
- obj.attr_set?(:str_field).should == true
359
- end
360
- end
361
-
362
- describe '#receive!' do
363
- before do
364
- @obj = @klass.new
365
- end
366
- it 'accepts things that quack like a hash: have [] and has_key?' do
367
- foo = mock
368
- def foo.[](*_) 3 end ; def foo.has_key?(*_) true end
369
- @obj.receive!(foo)
370
- @obj.my_int.should == 3
371
- end
372
- it 'only accepts things that quack like a hash' do
373
- lambda{ @obj.receive!(3) }.should raise_error ArgumentError, "Can't receive (it isn't hashlike): {3}"
374
- end
375
- it 'lets me call receive! with no args so I can trigger the defaults and after_receive hooks' do
376
- @obj.should_receive(:impose_defaults!).with({}).ordered
377
- @obj.should_receive(:run_after_receivers).with({}).ordered
378
- @obj.receive!
379
- end
380
-
381
- it 'receives symbol key' do
382
- @obj.receive! :my_int => 4
383
- @obj.my_int.should == 4
384
- end
385
- it 'receives string key' do
386
- @obj.receive! :my_int => 5
387
- @obj.my_int.should == 5
388
- end
389
- it 'with symbol and string key in given hash, takes symbol key only' do
390
- @obj.receive! :my_int => 7, 'my_int' => 6
391
- @obj.my_int.should == 7
392
- end
393
- it 'only accepts things that are receivers' do
394
- @klass.class_eval do attr_accessor :bob ; end
395
- @obj.receive! :my_int => 7, :bob => 12
396
- @obj.should_not_receive(:bob=)
397
- @obj.bob.should be_nil
398
- end
399
- it 'ignores extra keys' do
400
- @obj.receive! :my_int => 7, :bob => 12
401
- @obj.instance_variable_get('@bob').should be_nil
402
- end
403
- it 'delegates to receive_{whatever}' do
404
- @obj.should_receive(:receive_my_int).with(7)
405
- @obj.receive! :my_int => 7, :bob => 12
406
- end
407
- it 'imposes defaults and triggers after_receivers after hash has been sucked in' do
408
- @obj.should_receive(:receive_my_int).with(7).ordered
409
- @obj.should_receive(:impose_defaults!).with(:my_int => 7, :bob => 12).ordered
410
- @obj.should_receive(:run_after_receivers).with(:my_int => 7, :bob => 12).ordered
411
- @obj.receive! :my_int => 7, :bob => 12
412
- end
413
- it 'returns self, to allow chaining' do
414
- @obj.receive!(:my_int => 7, :bob => 12).should equal(@obj)
415
- end
416
-
417
- it 'receives even if there is no setter' do
418
- @klass.rcvr_reader :a, Integer
419
- @klass.rcvr :b, Integer
420
- obj = @klass.receive :my_int => 3, :a => 5, :b => 7
421
- obj.should_not respond_to(:a=)
422
- obj.should_not respond_to(:b=)
423
- obj.my_int.should == 3
424
- obj.a.should == 5
425
- obj.instance_variable_get("@b").should == 7
426
- end
427
- end
428
-
429
- describe "receiving type" do
430
- RECEIVABLES = [Symbol, String, Integer, Float, Time, Date, Array, Hash, Boolean, NilClass, Object]
431
- ALIASES = [:symbol, :string, :int, :integer, :long, :time, :date, :float, :double, :hash, :map, :array, :null, :boolean, :bytes]
432
- it "has specs for every type" do
433
- (Receiver::RECEIVER_BODIES.keys - RECEIVABLES).should be_empty
434
- end
435
- it "has specs for every alias" do
436
- (Receiver::TYPE_ALIASES.keys - ALIASES).should == []
437
- end
438
- RECEIVABLES.each do |receivable|
439
- it "#{receivable} has a receiver_body" do
440
- Receiver::RECEIVER_BODIES.should have_key(receivable)
441
- end
442
- end
443
- (RECEIVABLES - [String]).each do |receivable|
444
- it "#{receivable} accepts nil as nil" do
445
- @klass.rcvr_accessor :nil_field, receivable
446
- obj = @klass.receive(:nil_field => nil)
447
- obj.nil_field.should be_nil
448
- end
449
- end
450
- [String].each do |receivable|
451
- it "#{receivable} accepts nil as empty string" do
452
- @klass.rcvr_accessor :nil_field, receivable
453
- obj = @klass.receive(:nil_field => nil)
454
- obj.nil_field.should == ""
455
- end
456
- end
457
-
458
- it "lets me use an anonymous class as a received type" do
459
- @klass_2 = Class.new(Wide)
460
- @klass_2.rcvr_accessor :maw, Integer
461
- @klass.rcvr_accessor :k2, @klass_2
462
- obj = @klass.receive({ :my_int => 3, :k2 => { :maw => 2 }})
463
- obj.k2.maw.should == 2
464
- end
465
-
466
- it 'keeps values across a receive!' do
467
- @klass.rcvr_accessor :repeated, Integer
468
- @klass.rcvr_accessor :just_second, Integer
469
- obj = @klass.receive( :my_int => 1, :repeated => 3)
470
- [obj.my_int, obj.repeated, obj.just_second].should == [1, 3, nil]
471
- obj.receive!(:repeated => 20, :just_second => 30)
472
- [obj.my_int, obj.repeated, obj.just_second].should == [1, 20, 30]
473
- end
474
-
475
- # ---------------------------------------------------------------------------
476
-
477
- it 'core class .receive method' do
478
- Symbol.receive('hi').should == :hi
479
- Integer.receive(3.4).should == 3
480
- Float.receive("4.5").should == 4.5
481
- String.receive(4.5).should == "4.5"
482
- Time.receive('1985-11-05T04:03:02Z').should == Time.parse('1985-11-05T04:03:02Z')
483
- Date.receive('1985-11-05T04:03:02Z').should == Date.parse('1985-11-05')
484
- Array.receive('hi').should == ['hi']
485
- Hash.receive({:hi => :there}).should == {:hi => :there}
486
- Boolean.receive("false").should == false
487
- NilClass.receive(nil).should == nil
488
- Object.receive(:fnord).should == :fnord
489
- end
490
-
491
- # ---------------------------------------------------------------------------
492
-
493
- def self.it_correctly_converts(type, orig, desired)
494
- it "for #{type} converts #{orig.inspect} to #{desired.inspect}" do
495
- field = "#{type}_field".to_sym
496
- @klass.rcvr_accessor field, type
497
- obj = @klass.receive( field => orig )
498
- obj.send(field).should == desired
499
- end
500
- end
501
-
502
- describe 'type coercion' do
503
- [
504
- [Symbol, 'foo', :foo], [Symbol, :foo, :foo], [Symbol, nil, nil], [Symbol, '', nil],
505
- [Integer, '5', 5], [Integer, 5, 5], [Integer, nil, nil], [Integer, '', nil],
506
- [Integer, '5', 5], [Integer, 5, 5], [Integer, nil, nil], [Integer, '', nil],
507
- [Float, '5.2', 5.2], [Float, 5.2, 5.2], [Float, nil, nil], [Float, '', nil],
508
- [String, 'foo', 'foo'], [String, :foo, 'foo'], [String, nil, ""], [String, '', ""],
509
- [String, 5.2, "5.2"], [String, [1], "[1]"], [String, 1, "1"],
510
- [Time, '1985-11-05T04:03:02Z', Time.parse('1985-11-05T04:03:02Z')],
511
- [Time, '1985-11-05T04:03:02+06:00', Time.parse('1985-11-04T22:03:02Z')],
512
- [Time, Time.parse('1985-11-05T04:03:02Z'), Time.parse('1985-11-05T04:03:02Z')],
513
- [Date, Time.parse('1985-11-05T04:03:02Z'), Date.parse('1985-11-05')],
514
- [Date, '1985-11-05T04:03:02Z', Date.parse('1985-11-05')],
515
- [Date, '1985-11-05T04:03:02+06:00', Date.parse('1985-11-05')],
516
- [Time, nil, nil], [Time, '', nil], [Time, 'blah', nil],
517
- [Date, nil, nil], [Date, '', nil], [Date, 'blah', nil],
518
- [Array, ['this', 'that', 'thother'], ['this', 'that', 'thother'] ],
519
- [Array, ['this,that,thother'], ['this,that,thother'] ],
520
- [Array, 'this,that,thother', ['this,that,thother'] ],
521
- [Array, 'alone', ['alone'] ],
522
- [Array, '', [] ],
523
- [Array, nil, nil ],
524
- [Hash, {:hi => 1}, {:hi => 1}], [Hash, nil, nil], [Hash, "", {}], [Hash, [], {}], [Hash, {}, {}],
525
- [:boolean, '0', true], [:boolean, 0, true], [:boolean, '', false], [:boolean, [], true], [:boolean, nil, nil],
526
- [:boolean, '1', true], [:boolean, 1, true], [:boolean, '5', true], [:boolean, 'true', true],
527
- [NilClass, nil, nil],
528
- [Object, {:foo => [1]}, {:foo => [1]} ], [Object, nil, nil], [Object, 1, 1],
529
- ].each do |type, orig, desired|
530
- it_correctly_converts type, orig, desired
531
- end
532
-
533
- describe 'controversially' do
534
- [
535
- [Hash, ['does no type checking'], ['does no type checking'] ],
536
- [Hash, 'does no type checking', 'does no type checking' ],
537
- ].each do |type, orig, desired|
538
- it_correctly_converts type, orig, desired
539
- end
540
- end
541
-
542
- describe 'NilClass' do
543
- it 'only accepts nil' do
544
- @klass.rcvr_accessor :nil_field, NilClass
545
- lambda{ @klass.receive( :nil_field => 'hello' ) }.should raise_error(ArgumentError, "This field must be nil, but [hello] was given")
546
- end
547
- end
548
- end
549
-
550
- end
551
- end
@@ -1,71 +0,0 @@
1
- require File.expand_path('../spec_helper', File.dirname(__FILE__))
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
- describe Gorillib::Struct::ActsAsHash do
20
- if ENV['FULL_SPECS']
21
- include HashlikeFuzzingHelper
22
-
23
- describe "vs Hash" do
24
- before do
25
- @total = 0
26
- @hsh = HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT.dup
27
- @hshlike = StructUsingHashlike.new.merge(HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
28
- end
29
-
30
- ( HashlikeHelper::METHODS_TO_TEST - STRUCT_HASHLIKE_METHODS_TO_SKIP ).each do |method_to_test|
31
- describe "##{method_to_test}" do
32
-
33
- (HashlikeFuzzingHelper::INPUTS_FOR_ALL_HASHLIKES).each do |input|
34
- next if HashlikeFuzzingHelper::SPECIAL_CASES_FOR_HASHLIKE_STRUCT[method_to_test].include?(input)
35
-
36
- it "on #{input.inspect}" do
37
- behaves_the_same(@hsh, @hshlike, method_to_test, input)
38
- end
39
- end
40
- end
41
- end
42
- end
43
-
44
- describe "vs Gorillib::HashWithIndifferentSymbolKeys" do
45
- before do
46
- @total = 0
47
- @hsh = Gorillib::HashWithIndifferentSymbolKeys.new_from_hash_copying_default(
48
- HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
49
- @hshlike = StructUsingHashlike.new.merge(
50
- HashlikeHelper::HASH_TO_TEST_HASHLIKE_STRUCT)
51
- end
52
-
53
- ( HashlikeHelper::METHODS_TO_TEST - STRUCT_HASHLIKE_METHODS_TO_SKIP
54
- ).each do |method_to_test|
55
- describe "##{method_to_test}" do
56
-
57
- ( HashlikeFuzzingHelper::INPUTS_WHEN_INDIFFERENT_ACCESS +
58
- HashlikeFuzzingHelper::INPUTS_FOR_ALL_HASHLIKES
59
- ).each do |input|
60
- next if HashlikeFuzzingHelper::SPECIAL_CASES_FOR_HASHLIKE_STRUCT[method_to_test].include?(input)
61
-
62
- it "on #{input.inspect}" do
63
- behaves_the_same(@hsh, @hshlike, method_to_test, input)
64
- end
65
-
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end