flag_shih_tzu 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|