gorillib 0.5.0 → 0.5.2
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.
- data/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -16
- data/Rakefile +2 -74
- data/away/aliasing_spec.rb +180 -0
- data/away/confidence.rb +17 -0
- data/away/stub_module.rb +33 -0
- data/gorillib.gemspec +31 -246
- data/lib/gorillib/collection/model_collection.rb +1 -0
- data/lib/gorillib/data_munging.rb +0 -1
- data/lib/gorillib/hashlike/slice.rb +2 -0
- data/lib/gorillib/model/field.rb +2 -2
- data/lib/gorillib/model/serialization.rb +9 -4
- data/lib/gorillib/model/serialization/csv.rb +1 -0
- data/lib/gorillib/model/serialization/lines.rb +2 -0
- data/lib/gorillib/model/serialization/tsv.rb +1 -0
- data/lib/gorillib/pathname.rb +1 -1
- data/lib/gorillib/pathname/utils.rb +6 -0
- data/lib/gorillib/string/inflector.rb +1 -1
- data/lib/gorillib/system.rb +1 -0
- data/lib/gorillib/system/runner.rb +36 -0
- data/lib/gorillib/type/ip_address.rb +2 -2
- data/lib/gorillib/version.rb +3 -0
- data/old/lib/gorillib/hash/indifferent_access.rb +207 -0
- data/old/lib/gorillib/hash/tree_merge.rb +4 -0
- data/old/lib/gorillib/hashlike/tree_merge.rb +49 -0
- data/old/lib/gorillib/metaprogramming/cattr_accessor.rb +79 -0
- data/old/lib/gorillib/metaprogramming/mattr_accessor.rb +61 -0
- data/old/lib/gorillib/receiver.rb +402 -0
- data/old/lib/gorillib/receiver/active_model_shim.rb +32 -0
- data/old/lib/gorillib/receiver/acts_as_hash.rb +195 -0
- data/old/lib/gorillib/receiver/acts_as_loadable.rb +42 -0
- data/old/lib/gorillib/receiver/locale/en.yml +27 -0
- data/old/lib/gorillib/receiver/tree_diff.rb +74 -0
- data/old/lib/gorillib/receiver/validations.rb +30 -0
- data/old/lib/gorillib/receiver_model.rb +21 -0
- data/old/lib/gorillib/struct/acts_as_hash.rb +108 -0
- data/old/lib/gorillib/struct/hashlike_iteration.rb +0 -0
- data/old/spec/gorillib/hash/indifferent_access_spec.rb +391 -0
- data/old/spec/gorillib/metaprogramming/cattr_accessor_spec.rb +43 -0
- data/old/spec/gorillib/metaprogramming/mattr_accessor_spec.rb +45 -0
- data/old/spec/gorillib/receiver/receiver/acts_as_hash_spec.rb +295 -0
- data/old/spec/gorillib/receiver_spec.rb +551 -0
- data/old/spec/gorillib/struct/acts_as_hash_fuzz_spec.rb +71 -0
- data/old/spec/gorillib/struct/acts_as_hash_spec.rb +422 -0
- data/spec/gorillib/array/compact_blank_spec.rb +2 -2
- data/spec/gorillib/collection_spec.rb +6 -6
- data/spec/gorillib/factories_spec.rb +2 -2
- data/spec/gorillib/hashlike_spec.rb +2 -1
- data/spec/gorillib/model/defaults_spec.rb +3 -3
- data/spec/gorillib/model/serialization/csv_spec.rb +35 -0
- data/spec/gorillib/model/serialization/tsv_spec.rb +20 -4
- data/spec/gorillib/model/serialization_spec.rb +3 -3
- data/spec/spec_helper.rb +6 -1
- data/spec/support/factory_test_helpers.rb +2 -2
- data/spec/support/gorillib_test_helpers.rb +4 -4
- data/spec/support/hashlike_fuzzing_helper.rb +1 -15
- data/spec/support/hashlike_helper.rb +5 -1
- data/spec/support/model_test_helpers.rb +12 -1
- metadata +192 -168
- data/notes/HOWTO.md +0 -22
- data/notes/bucket.md +0 -155
- data/notes/builder.md +0 -170
- data/notes/collection.md +0 -81
- data/notes/factories.md +0 -86
- data/notes/model-overlay.md +0 -209
- data/notes/model.md +0 -135
- data/notes/structured-data-classes.md +0 -127
@@ -0,0 +1,295 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
require 'gorillib/receiver'
|
3
|
+
require 'gorillib/metaprogramming/class_attribute'
|
4
|
+
require 'gorillib/hashlike'
|
5
|
+
require 'gorillib/receiver/acts_as_hash'
|
6
|
+
require GORILLIB_ROOT_DIR('spec/support/hashlike_helper')
|
7
|
+
require GORILLIB_ROOT_DIR('spec/support/hashlike_via_delegation')
|
8
|
+
require GORILLIB_ROOT_DIR('spec/hashlike/hashlike_behavior_spec')
|
9
|
+
|
10
|
+
class SimpleReceiver
|
11
|
+
include Receiver
|
12
|
+
include Receiver::ActsAsHash
|
13
|
+
#
|
14
|
+
rcvr_accessor :a, Integer
|
15
|
+
rcvr_accessor :b, Integer
|
16
|
+
rcvr_accessor :c, Integer
|
17
|
+
rcvr_accessor :nil_val, NilClass
|
18
|
+
rcvr_accessor :false_val, Boolean
|
19
|
+
rcvr_accessor :new_key, String
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Receiver do
|
23
|
+
|
24
|
+
before do
|
25
|
+
@hshlike = SimpleReceiver.new.merge(HashlikeHelper::HASH_TO_TEST_HL_V_A.dup)
|
26
|
+
@empty_hshlike = SimpleReceiver.new
|
27
|
+
@hshlike_with_array_vals = SimpleReceiver.new.merge(HashlikeHelper::BASE_HSH_WITH_ARRAY_VALS.dup)
|
28
|
+
#
|
29
|
+
@hshlike_subklass = Class.new(SimpleReceiver)
|
30
|
+
@hshlike_subklass_inst = @hshlike_subklass.new.merge(HashlikeHelper::BASE_HSH.dup)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# ===========================================================================
|
35
|
+
#
|
36
|
+
# Fundamental behavior
|
37
|
+
|
38
|
+
describe '#[] and #[]= and #store' do
|
39
|
+
it_should_behave_like :hashlike_store_and_retrieve
|
40
|
+
it_should_behave_like :references_string_and_symbol_keys_equivalently
|
41
|
+
|
42
|
+
it 'reject unknown keys' do
|
43
|
+
lambda{ @hshlike[:fnord] = 69 }.should raise_error NoMethodError, /undefined method `fnord=' for/
|
44
|
+
lambda{ @hshlike[:fnord] }.should raise_error NoMethodError, /undefined method `fnord' for/
|
45
|
+
@hshlike.delete(:fnord).should be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'accepts defined but unset keys' do
|
49
|
+
@hshlike[:new_key].should be_nil
|
50
|
+
@hshlike[:new_key] = 69
|
51
|
+
@hshlike[:new_key].should == 69
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not allow nil, Object, or other non-stringy keys' do
|
55
|
+
lambda{ @hshlike[300] = :i_haz_num }.should raise_error(ArgumentError, "Keys for SimpleReceiver must be symbols, strings or respond to #to_sym")
|
56
|
+
lambda{ @hshlike[nil] = :i_haz_nil }.should raise_error(ArgumentError, "Keys for SimpleReceiver must be symbols, strings or respond to #to_sym")
|
57
|
+
obj = Object.new
|
58
|
+
lambda{ @hshlike[obj] = :i_haz_obj }.should raise_error(ArgumentError, "Keys for SimpleReceiver must be symbols, strings or respond to #to_sym")
|
59
|
+
def obj.to_sym() :c ; end
|
60
|
+
@hshlike[obj] = :i_haz_obj
|
61
|
+
@hshlike[obj].should == :i_haz_obj
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'defines the right accessor methods' do
|
65
|
+
@hshlike_subklass.rcvr_writer :write_only_attr, String
|
66
|
+
@hshlike_subklass.rcvr_reader :read_only_attr, String
|
67
|
+
@hshlike_subklass.rcvr :internal_attr, String
|
68
|
+
@hshlike_subklass.class_eval{ attr_accessor :not_a_receiver }
|
69
|
+
[ :receive_write_only_attr, :write_only_attr=,
|
70
|
+
:receive_read_only_attr, :read_only_attr,
|
71
|
+
:receive_internal_attr,
|
72
|
+
:not_a_receiver, :not_a_receiver= ].each{ |attr| @hshlike_subklass.should be_method_defined(attr) }
|
73
|
+
[ :write_only_attr, :read_only_attr=,
|
74
|
+
:internal_attr, :internal_attr=,
|
75
|
+
:receive_not_a_receiver ].each{ |attr| @hshlike_subklass.should_not be_method_defined(attr) }
|
76
|
+
@hshlike_subklass.receiver_attr_names.should == [:a, :b, :c, :nil_val, :false_val, :new_key, :write_only_attr, :read_only_attr, :internal_attr]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#delete' do
|
81
|
+
it_should_behave_like :hashlike_delete
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#keys' do
|
85
|
+
it_should_behave_like :hashlike_keys
|
86
|
+
end
|
87
|
+
|
88
|
+
# ===========================================================================
|
89
|
+
#
|
90
|
+
# Iteration
|
91
|
+
|
92
|
+
describe '#each_pair' do
|
93
|
+
describe 'with block' do
|
94
|
+
it_should_behave_like :each_pair_on_stringlike_keys, :each_pair
|
95
|
+
end
|
96
|
+
it_should_behave_like :with_no_block_returns_enumerator, :each_pair
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#each' do
|
100
|
+
describe 'with block' do
|
101
|
+
it_should_behave_like :each_pair_on_stringlike_keys, :each
|
102
|
+
end
|
103
|
+
it_should_behave_like :with_no_block_returns_enumerator, :each
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#each_key' do
|
107
|
+
describe 'with block' do
|
108
|
+
it_should_behave_like :each_key_on_stringlike_keys
|
109
|
+
end
|
110
|
+
it_should_behave_like :with_no_block_returns_enumerator, :each_key
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#each_value' do
|
114
|
+
describe 'with block' do
|
115
|
+
it_should_behave_like :each_value_on_stringlike_keys
|
116
|
+
end
|
117
|
+
it_should_behave_like :with_no_block_returns_enumerator, :each_value
|
118
|
+
end
|
119
|
+
|
120
|
+
# ===========================================================================
|
121
|
+
#
|
122
|
+
# Retrieval and Membership
|
123
|
+
|
124
|
+
describe '#values' do
|
125
|
+
it_should_behave_like :hashlike_values
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#values_at' do
|
129
|
+
it_should_behave_like :hashlike_values_at_or_of, :values_at
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#values_of' do
|
133
|
+
it_should_behave_like :hashlike_values_at_or_of, :values_of
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#length' do
|
137
|
+
it_should_behave_like :hashlike_length, :length
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#size' do
|
141
|
+
it_should_behave_like :hashlike_length, :size
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#has_key?' do
|
145
|
+
it_should_behave_like :hashlike_has_key?, :has_key?
|
146
|
+
it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :has_key?
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#include?' do
|
150
|
+
it_should_behave_like :hashlike_has_key?, :include?
|
151
|
+
it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :include?
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#key?' do
|
155
|
+
it_should_behave_like :hashlike_has_key?, :key?
|
156
|
+
it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :key?
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#member?' do
|
160
|
+
it_should_behave_like :hashlike_has_key?, :member?
|
161
|
+
it_should_behave_like :hashlike_has_key_string_and_symbol_equivalent, :member?
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#has_value?' do
|
165
|
+
it_should_behave_like :hashlike_has_value?, :has_value?
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#value?' do
|
169
|
+
it_should_behave_like :hashlike_has_value?, :value?
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#fetch' do
|
173
|
+
it_should_behave_like :hashlike_fetch
|
174
|
+
end
|
175
|
+
|
176
|
+
describe '#key' do
|
177
|
+
it_should_behave_like :hashlike_key
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#assoc' do
|
181
|
+
it_should_behave_like :hashlike_assoc
|
182
|
+
end
|
183
|
+
|
184
|
+
describe '#rassoc' do
|
185
|
+
it_should_behave_like :hashlike_rassoc
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#empty?' do
|
189
|
+
it_should_behave_like :hashlike_empty?
|
190
|
+
end
|
191
|
+
|
192
|
+
# ===========================================================================
|
193
|
+
#
|
194
|
+
# Update, merge!, merge
|
195
|
+
|
196
|
+
describe 'update' do
|
197
|
+
it_should_behave_like :merging_method, :update
|
198
|
+
it_should_behave_like :merging_method_with_normal_keys, :update
|
199
|
+
it_should_behave_like :merging_method_inplace, :update
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#merge!' do
|
203
|
+
it_should_behave_like :merging_method, :merge!
|
204
|
+
it_should_behave_like :merging_method_with_normal_keys, :merge!
|
205
|
+
it_should_behave_like :merging_method_inplace, :merge!
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '#merge' do
|
209
|
+
it_should_behave_like :merging_method, :merge
|
210
|
+
it_should_behave_like :merging_method_with_normal_keys, :merge
|
211
|
+
it_should_behave_like :merging_method_returning_new, :merge
|
212
|
+
end
|
213
|
+
|
214
|
+
# ===========================================================================
|
215
|
+
#
|
216
|
+
# Filters
|
217
|
+
|
218
|
+
describe '#reject!' do
|
219
|
+
it_should_behave_like :hashlike_filter, :reject!
|
220
|
+
it_should_behave_like :rejection_filter, :reject!
|
221
|
+
it_should_behave_like :filter_modifies_self_returns_nil_if_unchanged, :reject!, false
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '#select!' do
|
225
|
+
it_should_behave_like :hashlike_filter, :select!
|
226
|
+
it_should_behave_like :selection_filter, :select!
|
227
|
+
it_should_behave_like :filter_modifies_self_returns_nil_if_unchanged, :select!, true
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#delete_if' do
|
231
|
+
it_should_behave_like :hashlike_filter, :delete_if
|
232
|
+
it_should_behave_like :rejection_filter, :delete_if
|
233
|
+
it_should_behave_like :filter_modifies_self_returns_self, :delete_if, false
|
234
|
+
end
|
235
|
+
|
236
|
+
describe '#keep_if' do
|
237
|
+
it_should_behave_like :hashlike_filter, :keep_if
|
238
|
+
it_should_behave_like :selection_filter, :keep_if
|
239
|
+
it_should_behave_like :filter_modifies_self_returns_self, :keep_if, true
|
240
|
+
end
|
241
|
+
|
242
|
+
describe '#reject' do
|
243
|
+
it_should_behave_like :hashlike_filter, :select
|
244
|
+
it_should_behave_like :selection_filter, :select
|
245
|
+
it_should_behave_like :filter_does_not_modify_self_returns_same_class, :reject, false
|
246
|
+
end
|
247
|
+
|
248
|
+
describe '#select' do
|
249
|
+
it_should_behave_like :hashlike_filter, :select
|
250
|
+
it_should_behave_like :selection_filter, :select
|
251
|
+
it_should_behave_like :filter_does_not_modify_self_returns_same_class, :select, true
|
252
|
+
end
|
253
|
+
|
254
|
+
describe '#clear' do
|
255
|
+
it_should_behave_like :hashlike_clear
|
256
|
+
end
|
257
|
+
|
258
|
+
# ===========================================================================
|
259
|
+
#
|
260
|
+
# Conversion
|
261
|
+
|
262
|
+
describe '#to_hash' do
|
263
|
+
it_should_behave_like :hashlike_to_hash
|
264
|
+
|
265
|
+
it 'should recurse' do
|
266
|
+
@hshlike_subklass.rcvr_accessor :k2, SimpleReceiver
|
267
|
+
hsh = HashlikeHelper::HASH_TO_TEST_HL_V_A.merge(:k2 => {:a => 3, :new_key => 'hi' })
|
268
|
+
obj = @hshlike_subklass.receive(hsh)
|
269
|
+
obj.to_hash.should == {:a=>100, :b=>200, :c=>300, :nil_val=>nil, :false_val=>false, :k2=>{:a=>3, :new_key=>"hi"} }
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#invert' do
|
274
|
+
it_should_behave_like :hashlike_invert
|
275
|
+
end
|
276
|
+
|
277
|
+
describe '#flatten' do
|
278
|
+
it_should_behave_like :hashlike_flatten
|
279
|
+
end
|
280
|
+
|
281
|
+
# ===========================================================================
|
282
|
+
#
|
283
|
+
# Sanity check
|
284
|
+
|
285
|
+
it 'built test objects correctly' do
|
286
|
+
@hshlike_subklass .should < @hshlike.class
|
287
|
+
@hshlike_subklass .should_not == @hshlike.class
|
288
|
+
@hshlike_subklass_inst .should be_a(SimpleReceiver)
|
289
|
+
@hshlike_subklass_inst .should be_a(@hshlike_subklass)
|
290
|
+
@hshlike_subklass_inst .should_not be_an_instance_of(SimpleReceiver)
|
291
|
+
@hshlike .should_not be_a(@hshlike_subklass)
|
292
|
+
@hshlike .should be_an_instance_of(SimpleReceiver)
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
@@ -0,0 +1,551 @@
|
|
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
|