flag_shih_tzu 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/.gitignore +1 -0
- data/CHANGELOG +17 -0
- data/README.rdoc +35 -4
- data/flag_shih_tzu.gemspec +1 -0
- data/lib/flag_shih_tzu.rb +43 -17
- data/lib/flag_shih_tzu/version.rb +1 -1
- data/test/flag_shih_tzu_test.rb +40 -0
- data/test/schema.rb +6 -0
- metadata +3 -1
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
CHANGED
data/CHANGELOG
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Version 0.3.0 - NOV.05.2012 - first version maintained by Peter Boling
|
2
|
+
|
3
|
+
* ClassWithHasFlags.set_#{flag_name}_sql # Returns the sql string for setting a flag for use in customized SQL
|
4
|
+
* ClassWithHasFlags.unset_#{flag_name}_sql # Returns the sql string for unsetting a flag for use in customized SQL
|
5
|
+
* ClassWithHasFlags.flag_columns # Returns the column_names used by FlagShihTzu as bit fields
|
6
|
+
* has_flags :strict => true # DuplicateFlagColumnException raised when a single DB column is declared as a flag column twice
|
7
|
+
* Less verbosity for expected conditions when the DB connection for the class is unavailable.
|
8
|
+
* Tests for additional features, but does not change any behavior of 0.2.3 / 0.2.4 by default.
|
9
|
+
* Easily migrate from 0.2.3 / 0.2.4. Goal is no code changes required. Minor version bump to encourage caution.
|
10
|
+
|
11
|
+
Version 0.2.4 - NOV.05.2012 - released last few changes from XING master
|
12
|
+
|
13
|
+
* Fix deprecation warning for set_table_name
|
14
|
+
* Optional bang methods
|
15
|
+
* Complete Ruby 1.9(\.[^1]) and Rails 3.2.X compatibility
|
16
|
+
|
17
|
+
Version 0.2.3 - last version maintained by XING AG
|
data/README.rdoc
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
== Change of Ownership and 0.3.0 Release Notes
|
2
|
+
|
3
|
+
FlagShihTzu was originally a {XING AG}[http://www.xing.com/] project. {Peter Boling}[http://peterboling.com] was a long time contributor and watcher of the project.
|
4
|
+
In September 2012 XING transferred ownership of the project to Peter Boling. Peter Boling had been maintaining a
|
5
|
+
fork with extended capabilities. These additional features become a part of the 0.3 line. The 0.2 line of the gem will
|
6
|
+
remain true to XING's original. The 0.3 line aims to maintain complete parity and compatibility with XING's original as
|
7
|
+
well. I will continue to monitor other forks for original ideas and improvements. Pull requests are welcome, but please
|
8
|
+
rebase your work onto the current master to make integration easier.
|
9
|
+
|
10
|
+
Some new things in the 0.3 line:
|
11
|
+
|
12
|
+
* ClassWithHasFlags.set_#{flag_name}_sql # Returns the sql string for setting a flag for use in customized SQL
|
13
|
+
* ClassWithHasFlags.unset_#{flag_name}_sql # Returns the sql string for unsetting a flag for use in customized SQL
|
14
|
+
* ClassWithHasFlags.flag_columns # Returns the column_names used by FlagShihTzu as bit fields
|
15
|
+
* has_flags :strict => true # DuplicateFlagColumnException raised when a single DB column is declared as a flag column twice
|
16
|
+
* Less verbosity for expected conditions when the DB connection for the class is unavailable.
|
17
|
+
* Tests for additional features, but does not change any behavior of 0.2 versions by default.
|
18
|
+
* Easily migrate from 0.2 versions. No code changes required.
|
19
|
+
|
1
20
|
=FlagShihTzu
|
2
21
|
|
3
22
|
Bit fields for ActiveRecord
|
@@ -28,7 +47,7 @@ http://en.wikipedia.org/wiki/Shih_Tzu
|
|
28
47
|
|
29
48
|
==Build status
|
30
49
|
|
31
|
-
{<img src="https://secure.travis-ci.org/
|
50
|
+
{<img src="https://secure.travis-ci.org/pboling/flag_shih_tzu.png" />}[http://travis-ci.org/pboling/flag_shih_tzu]
|
32
51
|
|
33
52
|
|
34
53
|
==Prerequisites
|
@@ -163,7 +182,14 @@ on Spaceship:
|
|
163
182
|
Spaceship#electrolytes=
|
164
183
|
Spaceship#electrolytes_changed?
|
165
184
|
|
166
|
-
|
185
|
+
===Generated class methods
|
186
|
+
|
187
|
+
Calling +has_flags+ as shown above creates the following class methods
|
188
|
+
on Spaceship:
|
189
|
+
|
190
|
+
Spaceship.flag_columns # [:features, :crew]
|
191
|
+
|
192
|
+
Optionally, you can set the <tt>:bang_methods</tt> option to true to enable the bang methods:
|
167
193
|
|
168
194
|
Spaceship#electrolytes!
|
169
195
|
Spaceship#not_electrolytes!
|
@@ -290,15 +316,19 @@ specify which config from <tt>test/database.yml</tt> to use, e.g.:
|
|
290
316
|
|
291
317
|
==Authors
|
292
318
|
|
319
|
+
{Peter Boling}[http://github.com/pboling],
|
293
320
|
{Patryk Peszko}[http://github.com/ppeszko],
|
294
321
|
{Sebastian Roebke}[http://github.com/boosty],
|
295
322
|
{David Anderson}[http://github.com/alpinegizmo],
|
296
323
|
{Tim Payton}[http://github.com/dizzy42]
|
297
324
|
and a helpful group of
|
298
|
-
{contributors}[https://github.com/
|
325
|
+
{contributors}[https://github.com/pboling/flag_shih_tzu/contributors].
|
299
326
|
Thanks!
|
300
327
|
|
301
|
-
|
328
|
+
Find out more about Peter Boling's work
|
329
|
+
{PeterBoling.com}[http://peterboling.com/].
|
330
|
+
|
331
|
+
Find out more about XING
|
302
332
|
{Devblog}[http://devblog.xing.com/].
|
303
333
|
|
304
334
|
|
@@ -306,6 +336,7 @@ Please find out more about our work in our
|
|
306
336
|
|
307
337
|
The MIT License
|
308
338
|
|
339
|
+
Copyright (c) 2012 {Peter Boling}[http://www.peterboling.com/]
|
309
340
|
Copyright (c) 2011 {XING AG}[http://www.xing.com/]
|
310
341
|
|
311
342
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
data/flag_shih_tzu.gemspec
CHANGED
data/lib/flag_shih_tzu.rb
CHANGED
@@ -10,13 +10,15 @@ module FlagShihTzu
|
|
10
10
|
|
11
11
|
def self.included(base)
|
12
12
|
base.extend(ClassMethods)
|
13
|
-
base.class_attribute :flag_options
|
14
|
-
base.class_attribute :flag_mapping
|
13
|
+
base.class_attribute :flag_options unless defined?(base.flag_options)
|
14
|
+
base.class_attribute :flag_mapping unless defined?(base.flag_mapping)
|
15
|
+
base.class_attribute :flag_columns unless defined?(base.flag_columns)
|
15
16
|
end
|
16
17
|
|
17
18
|
class IncorrectFlagColumnException < Exception; end
|
18
19
|
class NoSuchFlagQueryModeException < Exception; end
|
19
20
|
class NoSuchFlagException < Exception; end
|
21
|
+
class DuplicateFlagColumnException < Exception; end
|
20
22
|
|
21
23
|
module ClassMethods
|
22
24
|
def has_flags(*args)
|
@@ -24,7 +26,8 @@ module FlagShihTzu
|
|
24
26
|
opts = {
|
25
27
|
:named_scopes => true,
|
26
28
|
:column => DEFAULT_COLUMN_NAME,
|
27
|
-
:flag_query_mode => :in_list
|
29
|
+
:flag_query_mode => :in_list,
|
30
|
+
:strict => false
|
28
31
|
}.update(opts)
|
29
32
|
colmn = opts[:column].to_s
|
30
33
|
|
@@ -36,8 +39,14 @@ module FlagShihTzu
|
|
36
39
|
|
37
40
|
# the mappings are stored in this class level hash and apply per-column
|
38
41
|
self.flag_mapping ||= {}
|
42
|
+
#If we already have an instance of the same column in the flag_mapping, then there is a double definition on a column
|
43
|
+
raise DuplicateFlagColumnException if opts[:strict] && !self.flag_mapping[colmn].nil?
|
39
44
|
self.flag_mapping[colmn] ||= {}
|
40
45
|
|
46
|
+
# keep track of which flag columns are defined on this class
|
47
|
+
self.flag_columns ||= []
|
48
|
+
self.flag_columns << colmn
|
49
|
+
|
41
50
|
flag_hash.each do |flag_key, flag_name|
|
42
51
|
raise ArgumentError, "has_flags: flag keys should be positive integers, and #{flag_key} is not" unless is_valid_flag_key(flag_key)
|
43
52
|
raise ArgumentError, "has_flags: flag names should be symbols, and #{flag_name} is not" unless is_valid_flag_name(flag_name)
|
@@ -75,6 +84,14 @@ module FlagShihTzu
|
|
75
84
|
def self.not_#{flag_name}_condition
|
76
85
|
sql_condition_for_flag(:#{flag_name}, '#{colmn}', false)
|
77
86
|
end
|
87
|
+
|
88
|
+
def self.set_#{flag_name}_sql
|
89
|
+
sql_set_for_flag(:#{flag_name}, '#{colmn}', true)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.unset_#{flag_name}_sql
|
93
|
+
sql_set_for_flag(:#{flag_name}, '#{colmn}', false)
|
94
|
+
end
|
78
95
|
EVAL
|
79
96
|
|
80
97
|
# Define bancg methods when requested
|
@@ -121,39 +138,42 @@ module FlagShihTzu
|
|
121
138
|
return options, add_options
|
122
139
|
end
|
123
140
|
|
124
|
-
def check_flag_column(colmn,
|
141
|
+
def check_flag_column(colmn, custom_table_name = self.table_name)
|
125
142
|
# If you aren't using ActiveRecord (eg. you are outside rails) then do not fail here
|
126
143
|
# If you are using ActiveRecord then you only want to check for the table if the table exists so it won't fail pre-migration
|
127
144
|
has_ar = !!defined?(ActiveRecord) && self.respond_to?(:descends_from_active_record?)
|
128
145
|
# Supposedly Rails 2.3 takes care of this, but this precaution is needed for backwards compatibility
|
129
|
-
has_table = has_ar ? connection.tables.include?(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
146
|
+
has_table = has_ar ? ActiveRecord::Base.connection.tables.include?(custom_table_name) : true
|
147
|
+
|
148
|
+
if has_table
|
149
|
+
found_column = columns.find {|column| column.name == colmn}
|
150
|
+
#If you have not yet run the migration that adds the 'flags' column then we don't want to fail, because we need to be able to run the migration
|
151
|
+
#If the column is there but is of the wrong type, then we must fail, because flag_shih_tzu will not work
|
152
|
+
if found_column.nil?
|
153
|
+
logger.warn("Error: Column '#{colmn}' doesn't exist on table '#{custom_table_name}'. Did you forget to run migrations?") and return false
|
154
|
+
elsif found_column.type != :integer
|
155
|
+
raise IncorrectFlagColumnException.new("Table '#{custom_table_name}' must have an integer column named '#{colmn}' in order to use FlagShihTzu.") and return false
|
139
156
|
end
|
157
|
+
else
|
158
|
+
# ActiveRecord gem probably hasn't loaded yet?
|
159
|
+
logger.warn("FlagShihTzu#has_flags: Table '#{custom_table_name}' doesn't exist. Have all migrations been run?") and return false
|
140
160
|
end
|
141
161
|
|
142
162
|
true
|
143
163
|
end
|
144
164
|
|
145
|
-
def sql_condition_for_flag(flag, colmn, enabled = true,
|
165
|
+
def sql_condition_for_flag(flag, colmn, enabled = true, custom_table_name = self.table_name)
|
146
166
|
check_flag(flag, colmn)
|
147
167
|
|
148
168
|
if flag_options[colmn][:flag_query_mode] == :bit_operator
|
149
169
|
# use & bit operator directly in the SQL query.
|
150
170
|
# This has the drawback of not using an index on the flags colum.
|
151
|
-
"(#{
|
171
|
+
"(#{custom_table_name}.#{colmn} & #{flag_mapping[colmn][flag]} = #{enabled ? flag_mapping[colmn][flag] : 0})"
|
152
172
|
elsif flag_options[colmn][:flag_query_mode] == :in_list
|
153
173
|
# use IN() operator in the SQL query.
|
154
174
|
# This has the drawback of becoming a big query when you have lots of flags.
|
155
175
|
neg = enabled ? "" : "not "
|
156
|
-
"(#{
|
176
|
+
"(#{custom_table_name}.#{colmn} #{neg}in (#{sql_in_for_flag(flag, colmn).join(',')}))"
|
157
177
|
else
|
158
178
|
raise NoSuchFlagQueryModeException
|
159
179
|
end
|
@@ -165,6 +185,12 @@ module FlagShihTzu
|
|
165
185
|
num = 2 ** flag_mapping[flag_options[colmn][:column]].length
|
166
186
|
(1..num).select {|i| i & val == val}
|
167
187
|
end
|
188
|
+
|
189
|
+
def sql_set_for_flag(flag, colmn, enabled = true, custom_table_name = self.table_name)
|
190
|
+
check_flag(flag, colmn)
|
191
|
+
|
192
|
+
"#{custom_table_name}.#{colmn} = #{custom_table_name}.#{colmn} #{enabled ? "| " : "& ~" }#{flag_mapping[colmn][flag]}"
|
193
|
+
end
|
168
194
|
|
169
195
|
def is_valid_flag_key(flag_key)
|
170
196
|
flag_key > 0 && flag_key == flag_key.to_i
|
data/test/flag_shih_tzu_test.rb
CHANGED
@@ -45,6 +45,15 @@ class SpaceshipWith2CustomFlagsColumn < ActiveRecord::Base
|
|
45
45
|
has_flags({ 1 => :jeanlucpicard, 2 => :dajanatroj }, :column => 'commanders')
|
46
46
|
end
|
47
47
|
|
48
|
+
class SpaceshipWith3CustomFlagsColumn < ActiveRecord::Base
|
49
|
+
self.table_name = 'spaceships_with_3_custom_flags_column'
|
50
|
+
include FlagShihTzu
|
51
|
+
|
52
|
+
has_flags({ 1 => :warpdrive, 2 => :hyperspace }, :column => 'engines')
|
53
|
+
has_flags({ 1 => :photon, 2 => :laser, 3 => :ion_cannon, 4 => :particle_beam }, :column => 'weapons')
|
54
|
+
has_flags({ 1 => :power, 2 => :anti_ax_routine }, :column => 'hal3000')
|
55
|
+
end
|
56
|
+
|
48
57
|
class SpaceshipWithBitOperatorQueryMode < ActiveRecord::Base
|
49
58
|
self.table_name = 'spaceships'
|
50
59
|
include FlagShihTzu
|
@@ -117,6 +126,21 @@ class FlagShihTzuClassMethodsTest < Test::Unit::TestCase
|
|
117
126
|
end
|
118
127
|
end
|
119
128
|
|
129
|
+
def test_has_flags_should_raise_an_exception_when_flag_name_method_defined_by_flagshitzu_if_strict
|
130
|
+
assert_raises FlagShihTzu::DuplicateFlagColumnException do
|
131
|
+
eval(<<-EOF
|
132
|
+
class SpaceshipWithAlreadyUsedMethodByFlagshitzuStrict < ActiveRecord::Base
|
133
|
+
self.table_name = 'spaceships_with_2_custom_flags_column'
|
134
|
+
include FlagShihTzu
|
135
|
+
|
136
|
+
has_flags({ 1 => :jeanluckpicard }, :column => 'bits', :strict => true)
|
137
|
+
has_flags({ 1 => :jeanluckpicard }, :column => 'bits', :strict => true)
|
138
|
+
end
|
139
|
+
EOF
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
120
144
|
def test_has_flags_should_not_raise_an_exception_when_flag_name_method_defined_by_flagshitzu
|
121
145
|
assert_nothing_raised ArgumentError do
|
122
146
|
eval(<<-EOF
|
@@ -553,4 +577,20 @@ class FlagShihTzuDerivedClassTest < Test::Unit::TestCase
|
|
553
577
|
spaceship.not_warpdrive!
|
554
578
|
assert !spaceship.warpdrive
|
555
579
|
end
|
580
|
+
|
581
|
+
def test_should_return_a_sql_set_method_for_flag
|
582
|
+
assert_equal "spaceships.flags = spaceships.flags | 1", Spaceship.send( :sql_set_for_flag, :warpdrive, 'flags', true)
|
583
|
+
assert_equal "spaceships.flags = spaceships.flags & ~1", Spaceship.send( :sql_set_for_flag, :warpdrive, 'flags', false)
|
584
|
+
end
|
585
|
+
|
586
|
+
end
|
587
|
+
|
588
|
+
class FlagShihTzuClassMethodsTest < Test::Unit::TestCase
|
589
|
+
|
590
|
+
def test_should_track_columns_used_by_FlagShihTzu
|
591
|
+
assert_equal Spaceship.flag_columns, ['flags']
|
592
|
+
assert_equal SpaceshipWith2CustomFlagsColumn.flag_columns, ['bits', 'commanders']
|
593
|
+
assert_equal SpaceshipWith3CustomFlagsColumn.flag_columns, ['engines', 'weapons', 'hal3000']
|
594
|
+
end
|
595
|
+
|
556
596
|
end
|
data/test/schema.rb
CHANGED
@@ -14,6 +14,12 @@ ActiveRecord::Schema.define(:version => 0) do
|
|
14
14
|
t.integer :commanders, :null => false, :default => 0
|
15
15
|
end
|
16
16
|
|
17
|
+
create_table :spaceships_with_3_custom_flags_column, :force => true do |t|
|
18
|
+
t.integer :engines, :null => false, :default => 0
|
19
|
+
t.integer :weapons, :null => false, :default => 0
|
20
|
+
t.integer :hal3000, :null => false, :default => 0
|
21
|
+
end
|
22
|
+
|
17
23
|
create_table :spaceships_without_flags_column, :force => true do |t|
|
18
24
|
end
|
19
25
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flag_shih_tzu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -110,8 +110,10 @@ executables: []
|
|
110
110
|
extensions: []
|
111
111
|
extra_rdoc_files: []
|
112
112
|
files:
|
113
|
+
- .DS_Store
|
113
114
|
- .gitignore
|
114
115
|
- .travis.yml
|
116
|
+
- CHANGELOG
|
115
117
|
- Gemfile
|
116
118
|
- README.rdoc
|
117
119
|
- Rakefile
|