has_many_booleans 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +74 -0
- data/Rakefile +46 -0
- data/install.rb +4 -0
- data/lib/has_many_booleans.rb +335 -0
- data/lib/has_many_booleans/simple_bitset.rb +64 -0
- data/rails/init.rb +1 -0
- data/test/database.yml +6 -0
- data/test/debug.log +710 -0
- data/test/has_many_booleans_plugin.sqlite3 +0 -0
- data/test/has_many_booleans_test.rb +396 -0
- data/test/schema.rb +36 -0
- data/test/simple_bitset_test.rb +22 -0
- data/test/test_helper.rb +43 -0
- data/uninstall.rb +1 -0
- metadata +75 -0
Binary file
|
@@ -0,0 +1,396 @@
|
|
1
|
+
# has_many_booleans (c) 2010 Jan Lelis, released under the MIT license
|
2
|
+
# available at <http://github.com/janlelis/has_many_booleans>
|
3
|
+
# more info at <http://rbjl.net/22>
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
6
|
+
|
7
|
+
class HasManyBooleansTest < ActiveSupport::TestCase
|
8
|
+
load_schema
|
9
|
+
|
10
|
+
# # #
|
11
|
+
# create all kinds of model classes
|
12
|
+
#
|
13
|
+
class Default < ActiveRecord::Base
|
14
|
+
has_many_booleans :name, :password, :admin,
|
15
|
+
:true => [:name, :password],
|
16
|
+
:append => 'bla'
|
17
|
+
end
|
18
|
+
|
19
|
+
class ManyOption < ActiveRecord::Base
|
20
|
+
has_many_booleans :a, :b, :admin, :name, :password,
|
21
|
+
:true => [ :b],
|
22
|
+
:suffixes => %w| 1 2 3 1 2 ? ! = . k l |,
|
23
|
+
:append => '145',
|
24
|
+
:self => true,
|
25
|
+
:lazy => false
|
26
|
+
end
|
27
|
+
|
28
|
+
class NoOption < ActiveRecord::Base
|
29
|
+
has_many_booleans :name, :password, :admin
|
30
|
+
end
|
31
|
+
|
32
|
+
class Hmb < ActiveRecord::Base
|
33
|
+
hmb :name, :password, :admin, :append => 'blubb'
|
34
|
+
end
|
35
|
+
|
36
|
+
class BooleansAsHash < ActiveRecord::Base
|
37
|
+
has_many_booleans({ :name => 22,
|
38
|
+
:password => 5,
|
39
|
+
:admin => 7 },
|
40
|
+
:append => 'bla')
|
41
|
+
end
|
42
|
+
|
43
|
+
class Append < ActiveRecord::Base
|
44
|
+
has_many_booleans :name, :password, :admin, :append => 'bla'
|
45
|
+
end
|
46
|
+
|
47
|
+
class AppendNil < ActiveRecord::Base
|
48
|
+
has_many_booleans :name, :password, :admin, :append => nil
|
49
|
+
end
|
50
|
+
|
51
|
+
class Field < ActiveRecord::Base
|
52
|
+
has_many_booleans :name, :password, :admin, :field => 'bools'
|
53
|
+
end
|
54
|
+
|
55
|
+
class SuffixNone < ActiveRecord::Base
|
56
|
+
has_many_booleans :name, :password, :admin, :suffixes => nil
|
57
|
+
end
|
58
|
+
|
59
|
+
class SuffixEqualOnly < ActiveRecord::Base
|
60
|
+
has_many_booleans :name, :password, :admin, :suffixes => ['=']
|
61
|
+
end
|
62
|
+
|
63
|
+
class SuffixQuestionOnly < ActiveRecord::Base
|
64
|
+
has_many_booleans :name, :password, :admin, :suffixes => ['?']
|
65
|
+
end
|
66
|
+
|
67
|
+
class SuffixExclamationOnly < ActiveRecord::Base
|
68
|
+
has_many_booleans :name, :password, :admin, :suffixes => ['!']
|
69
|
+
end
|
70
|
+
|
71
|
+
class Self < ActiveRecord::Base
|
72
|
+
has_many_booleans :name, :password, :admin, :self => true
|
73
|
+
end
|
74
|
+
|
75
|
+
class SelfAppendNil < ActiveRecord::Base
|
76
|
+
has_many_booleans :name, :password, :admin, :self => true, :append => nil
|
77
|
+
end
|
78
|
+
|
79
|
+
class SelfName < ActiveRecord::Base
|
80
|
+
has_many_booleans :name, :password, :admin, :self => 'active_', :self_value => true
|
81
|
+
end
|
82
|
+
|
83
|
+
class ValidateTest < ActiveRecord::Base
|
84
|
+
has_many_booleans :name, :password, :admin
|
85
|
+
|
86
|
+
validates_true :name
|
87
|
+
validates_false :password
|
88
|
+
end
|
89
|
+
|
90
|
+
class ArCallback < ActiveRecord::Base
|
91
|
+
has_many_booleans :name, :password, :admin
|
92
|
+
|
93
|
+
def after_initialize
|
94
|
+
self.name = "Yukihiro"
|
95
|
+
end
|
96
|
+
|
97
|
+
def before_save
|
98
|
+
self.name = 'matz'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class LazyFalse < ActiveRecord::Base
|
103
|
+
has_many_booleans :name, :password, :admin, :lazy => false
|
104
|
+
end
|
105
|
+
|
106
|
+
class FalseValue < ActiveRecord::Base
|
107
|
+
has_many_booleans :name, :password, :admin, :false_values => ["super", 'toll', 3]
|
108
|
+
end
|
109
|
+
|
110
|
+
class Scope < ActiveRecord::Base
|
111
|
+
has_many_booleans :name, :password, :admin, :self => true
|
112
|
+
end
|
113
|
+
|
114
|
+
# # #
|
115
|
+
# instances helpers
|
116
|
+
#
|
117
|
+
def create_instances
|
118
|
+
@instances = {
|
119
|
+
:default => Default.new,
|
120
|
+
:many_option => ManyOption.new,
|
121
|
+
:no_option => NoOption.new,
|
122
|
+
:booleans_as_hash => BooleansAsHash.new,
|
123
|
+
:hmb => Hmb.new,
|
124
|
+
:append => Append.new,
|
125
|
+
:append_nil => AppendNil.new,
|
126
|
+
:field => Field.new,
|
127
|
+
:suffix_none => SuffixNone.new,
|
128
|
+
:suffix_question_only => SuffixQuestionOnly.new,
|
129
|
+
:suffix_equal_only => SuffixEqualOnly.new,
|
130
|
+
:suffix_exclamation_only => SuffixExclamationOnly.new,
|
131
|
+
:self => Self.new,
|
132
|
+
:self_name => SelfName.new,
|
133
|
+
:ar_callback => ArCallback.new,
|
134
|
+
:lazy_false => LazyFalse.new,
|
135
|
+
:false_value => FalseValue.new,
|
136
|
+
}
|
137
|
+
@booleans_options = Hash[ @instances.map{|k,v| [k, v.class.booleans_options]} ]
|
138
|
+
end
|
139
|
+
|
140
|
+
def create_instance(which, *params)
|
141
|
+
@a = which.new *params
|
142
|
+
@o = which.booleans_options
|
143
|
+
end
|
144
|
+
|
145
|
+
def loop_instances(with_assign = false)
|
146
|
+
cur_actions = @instances.each
|
147
|
+
cur_booleans_options = @booleans_options.each
|
148
|
+
|
149
|
+
loop{
|
150
|
+
@n, @a = cur_actions.next # name, instances
|
151
|
+
@o = cur_booleans_options.next[1] # booleans_options
|
152
|
+
next if with_assign &&( !@o[:suffixes].include?('=') || !@o[:append] || @o[:append].empty?) # or name does not work (existing method overwrite protection)
|
153
|
+
yield
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
# helper for often called methods
|
158
|
+
def snd(attr_name, suffix = '', value = nil)
|
159
|
+
if suffix == '='
|
160
|
+
@a.send( "#{attr_name}#{@o[:append] || ''}#{suffix}", value)
|
161
|
+
else
|
162
|
+
@a.send "#{attr_name}#{@o[:append] || ''}#{suffix}"
|
163
|
+
end
|
164
|
+
# rescue => e
|
165
|
+
# p "#{e} -- #{@a} -- #{@o}"
|
166
|
+
end
|
167
|
+
|
168
|
+
# # #
|
169
|
+
# weak test of setup
|
170
|
+
#
|
171
|
+
test 'create_instances' do
|
172
|
+
assert_nothing_raised{
|
173
|
+
assert_kind_of @a.class, @a
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
177
|
+
# # #
|
178
|
+
# class methods
|
179
|
+
#
|
180
|
+
test 'booleans_options get parsed the right way' do
|
181
|
+
create_instance ManyOption
|
182
|
+
assert_equal @o[:append], '_145'
|
183
|
+
assert_equal @o[:true], [:b]
|
184
|
+
assert_equal (@o[:suffixes]||[]).sort, %w| ! = ? |
|
185
|
+
end
|
186
|
+
|
187
|
+
# # #
|
188
|
+
# general behaivour
|
189
|
+
#
|
190
|
+
test 'methods exist' do
|
191
|
+
create_instances and loop_instances do
|
192
|
+
assert_nothing_raised { snd :name }
|
193
|
+
assert_raise( NoMethodError ) { snd :dont_know_this_attr }
|
194
|
+
assert_raise( NoMethodError ) { @a.send :name_ru903gfjh209gh3209p23 }
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
test 'different instances' do
|
199
|
+
create_instance NoOption
|
200
|
+
a = @a
|
201
|
+
snd :name, '=', true
|
202
|
+
create_instance NoOption
|
203
|
+
assert a.name_activated
|
204
|
+
assert_not snd :name
|
205
|
+
|
206
|
+
create_instance SelfName
|
207
|
+
a = @a
|
208
|
+
a.active_ = false
|
209
|
+
create_instance SelfName
|
210
|
+
assert @a.active_
|
211
|
+
assert_not a.active_
|
212
|
+
end
|
213
|
+
|
214
|
+
test 'set and unset (with =)' do
|
215
|
+
create_instances and loop_instances(true) do
|
216
|
+
( snd :name, '=', false )#, "#{@a.class},#{p :O;snd :name, '=', false}"
|
217
|
+
assert_not snd :name
|
218
|
+
snd :name, '=', true
|
219
|
+
assert snd :name
|
220
|
+
|
221
|
+
snd :password, '=', false
|
222
|
+
assert_not snd :password
|
223
|
+
snd :password, '=', true
|
224
|
+
assert snd :password
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
test 'save and load (with =)' do
|
229
|
+
create_instances and loop_instances(true) do
|
230
|
+
[:name, :password].each{ |what|
|
231
|
+
snd what, '=', false
|
232
|
+
assert @a.save
|
233
|
+
tmp = @a.class
|
234
|
+
|
235
|
+
assert_instance_of @a = @a.class.last, tmp
|
236
|
+
assert_not snd what
|
237
|
+
|
238
|
+
snd what, '=', true
|
239
|
+
assert @a.save
|
240
|
+
tmp = @a.class
|
241
|
+
|
242
|
+
assert_instance_of @a = @a.class.last, tmp
|
243
|
+
assert snd what
|
244
|
+
}
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
test 'right default values' do
|
249
|
+
create_instance Default
|
250
|
+
assert snd :name
|
251
|
+
assert snd :password
|
252
|
+
assert_not snd :admin
|
253
|
+
end
|
254
|
+
|
255
|
+
test "dont overwrite existing attrs" do
|
256
|
+
create_instance AppendNil
|
257
|
+
@a.name = 'Yukihiro'
|
258
|
+
assert @a.save
|
259
|
+
@a = AppendNil.last
|
260
|
+
assert_equal @a.name, 'Yukihiro'
|
261
|
+
end
|
262
|
+
|
263
|
+
test 'ar callbacks work' do
|
264
|
+
create_instance ArCallback
|
265
|
+
assert_equal @a.name, 'Yukihiro'
|
266
|
+
assert @a.valid?
|
267
|
+
@a.save
|
268
|
+
assert_equal @a.name, 'matz'
|
269
|
+
end
|
270
|
+
|
271
|
+
# # #
|
272
|
+
# booleans_options
|
273
|
+
#
|
274
|
+
test 'suffixes' do
|
275
|
+
create_instance SuffixNone
|
276
|
+
assert_nothing_raised { snd :name }
|
277
|
+
assert_raise( NoMethodError ) { snd :name, '?' }
|
278
|
+
assert_raise( NoMethodError ) { snd :name, '!' }
|
279
|
+
assert_raise( NoMethodError ) { snd :name, '=' }
|
280
|
+
assert_raise( NoMethodError ) { snd :name, '=', 9999 }
|
281
|
+
|
282
|
+
create_instance SuffixQuestionOnly
|
283
|
+
assert_nothing_raised { snd :name }
|
284
|
+
assert_nothing_raised { snd :name, '?' }
|
285
|
+
assert_raise( NoMethodError ) { snd :name, '!' }
|
286
|
+
assert_raise( NoMethodError ) { snd :name, '=' }
|
287
|
+
assert_raise( NoMethodError ) { snd :name, '=', 9999 }
|
288
|
+
|
289
|
+
create_instance SuffixExclamationOnly
|
290
|
+
assert_nothing_raised { snd :name }
|
291
|
+
assert_raise( NoMethodError ) { snd :name, '?' }
|
292
|
+
assert_nothing_raised { snd :name, '!' }
|
293
|
+
assert_raise( NoMethodError ) { snd :name, '=' }
|
294
|
+
assert_raise( NoMethodError ) { snd :name, '=', 9999 }
|
295
|
+
|
296
|
+
create_instance SuffixEqualOnly
|
297
|
+
assert_nothing_raised { snd :name }
|
298
|
+
assert_raise( NoMethodError ) { snd :name, '?' }
|
299
|
+
assert_raise( NoMethodError ) { snd :name, '!' }
|
300
|
+
assert_nothing_raised { snd :name, '=' }
|
301
|
+
assert_nothing_raised { snd :name, '=', 9999 }
|
302
|
+
end
|
303
|
+
|
304
|
+
test 'self' do
|
305
|
+
create_instance Default
|
306
|
+
assert_raise( NoMethodError ) { @a.send @o[:append] }
|
307
|
+
|
308
|
+
create_instance Self
|
309
|
+
assert_nothing_raised { @a.send @o[:append][1..-1] }
|
310
|
+
assert_equal @a.send( @o[:append][1..-1] ), false
|
311
|
+
@a.send( @o[:append][1..-1] + '=', 324 )
|
312
|
+
assert_equal @a.send( @o[:append][1..-1] ), true
|
313
|
+
|
314
|
+
assert_raise( RuntimeError ) {
|
315
|
+
create_instance SelfAppendNil
|
316
|
+
}
|
317
|
+
|
318
|
+
create_instance SelfName
|
319
|
+
assert_nothing_raised { @a.send @o[:self] }
|
320
|
+
assert_equal @a.send( @o[:self] ), true
|
321
|
+
end
|
322
|
+
|
323
|
+
test "lazyness (with assign)" do
|
324
|
+
create_instances and loop_instances(true) do
|
325
|
+
remember = @a.send( @o[:field] )
|
326
|
+
snd( :name, '=', !snd(:name) )
|
327
|
+
if @o[:lazy] # normal setting
|
328
|
+
assert_equal remember, @a.send( @o[:field] )
|
329
|
+
else
|
330
|
+
assert_not_equal remember, @a.send( @o[:field] )
|
331
|
+
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
test "false_values (with assign)" do
|
337
|
+
create_instance FalseValue
|
338
|
+
|
339
|
+
snd :name, '=', true
|
340
|
+
snd :name, '=', 'super'
|
341
|
+
assert_not snd :name
|
342
|
+
snd :name, '=', 3
|
343
|
+
assert_not snd :name
|
344
|
+
snd :name, '=', 99
|
345
|
+
assert snd :name
|
346
|
+
end
|
347
|
+
|
348
|
+
# scopes
|
349
|
+
test 'scopes' do
|
350
|
+
# create dummy data
|
351
|
+
create_instance Scope #1
|
352
|
+
@a.save
|
353
|
+
create_instance Scope #2
|
354
|
+
@a.activated!
|
355
|
+
@a.password_activated!
|
356
|
+
@a.save
|
357
|
+
create_instance Scope #3
|
358
|
+
@a.activated!
|
359
|
+
@a.save
|
360
|
+
create_instance Scope #4
|
361
|
+
@a.password_activated!
|
362
|
+
@a.save
|
363
|
+
create_instance Scope #5
|
364
|
+
@a.name_activated!
|
365
|
+
@a.save
|
366
|
+
|
367
|
+
# test queries
|
368
|
+
assert_equal Scope.true(:name), [Scope.find(5)]
|
369
|
+
assert_equal Scope.false, Scope.find(1, 4, 5)
|
370
|
+
assert_equal Scope.true(:name, :password), Scope.find(2, 4, 5)
|
371
|
+
assert_equal Scope.true(:name).true(:password), []
|
372
|
+
end
|
373
|
+
|
374
|
+
# validations
|
375
|
+
test 'validates_true' do
|
376
|
+
create_instance ValidateTest
|
377
|
+
|
378
|
+
snd :password, '=', false
|
379
|
+
snd :name, '=', false
|
380
|
+
assert_not @a.save, @a.errors.full_messages
|
381
|
+
snd :name, '=', true
|
382
|
+
assert @a.save, @a.errors.full_messages
|
383
|
+
end
|
384
|
+
|
385
|
+
test 'validates_false' do
|
386
|
+
create_instance ValidateTest
|
387
|
+
|
388
|
+
snd :name, '=', true
|
389
|
+
snd :password, '=', true
|
390
|
+
assert_not @a.save, @a.errors.full_messages
|
391
|
+
snd :password, '=', false
|
392
|
+
assert @a.save, @a.errors.full_messages
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
data/test/schema.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
%w|
|
3
|
+
appends
|
4
|
+
append_nils
|
5
|
+
defaults
|
6
|
+
many_options
|
7
|
+
no_options
|
8
|
+
hmbs
|
9
|
+
suffix_nones
|
10
|
+
suffix_question_onlies
|
11
|
+
suffix_equal_onlies
|
12
|
+
suffix_exclamation_onlies
|
13
|
+
selves
|
14
|
+
self_append_nils
|
15
|
+
self_names
|
16
|
+
ar_callbacks
|
17
|
+
lazy_falses
|
18
|
+
booleans_as_hashes
|
19
|
+
single_hashes
|
20
|
+
validate_tests
|
21
|
+
false_values
|
22
|
+
scopes
|
23
|
+
|.each do |table_name|
|
24
|
+
create_table table_name, :force => true do |t|
|
25
|
+
t.string :name
|
26
|
+
t.integer :booleans
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table 'fields', :force => true do |t|
|
31
|
+
t.string :name
|
32
|
+
t.integer :bools
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class SimpleBitsetTest < ActiveSupport::TestCase
|
4
|
+
test 'to_bra' do
|
5
|
+
assert_equal 0.to_bra, []
|
6
|
+
assert_equal 1.to_bra, [0]
|
7
|
+
assert_equal 2.to_bra, [1]
|
8
|
+
assert_equal 3.to_bra, [0,1]
|
9
|
+
assert_equal 4.to_bra, [2]
|
10
|
+
assert_equal 999999999999999999.to_bra, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 22, 24, 25, 26, 29, 31, 32, 33, 36, 37, 39, 41, 42, 44, 45, 47, 53, 54, 55, 56, 58, 59]
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'to_bri' do
|
14
|
+
assert_equal 0, [].to_bri
|
15
|
+
assert_equal 1, [0].to_bri
|
16
|
+
assert_equal 2, [1].to_bri
|
17
|
+
assert_equal 3, [0,1].to_bri
|
18
|
+
assert_equal 4, [2].to_bri
|
19
|
+
assert_equal 999999999999999999, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 22, 24, 25, 26, 29, 31, 32, 33, 36, 37, 39, 41, 42, 44, 45, 47, 53, 54, 55, 56, 58, 59].to_bri
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|