flag_shih_tzu 0.3.13 → 0.3.14
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +24 -16
- data/CHANGELOG.md +29 -17
- data/Gemfile +3 -0
- data/README.md +131 -93
- data/REEK +62 -66
- data/Rakefile +1 -1
- data/bin/test.bash +58 -8
- data/flag_shih_tzu.gemspec +4 -4
- data/gemfiles/Gemfile.activerecord-2.3.x +14 -3
- data/gemfiles/Gemfile.activerecord-3.0.x +13 -3
- data/gemfiles/Gemfile.activerecord-3.1.x +13 -3
- data/gemfiles/Gemfile.activerecord-3.2.x +13 -3
- data/gemfiles/Gemfile.activerecord-4.0.x +8 -2
- data/gemfiles/Gemfile.activerecord-4.1.x +8 -3
- data/gemfiles/Gemfile.activerecord-4.2.x +11 -0
- data/lib/flag_shih_tzu.rb +303 -205
- data/lib/flag_shih_tzu/validators.rb +5 -2
- data/lib/flag_shih_tzu/version.rb +1 -1
- data/test/database.yml +1 -1
- data/test/flag_shih_tzu_test.rb +368 -193
- data/test/test_helper.rb +12 -6
- metadata +17 -17
data/REEK
CHANGED
@@ -1,70 +1,66 @@
|
|
1
|
-
lib/flag_shih_tzu.rb --
|
2
|
-
[
|
3
|
-
[
|
4
|
-
[
|
5
|
-
[
|
6
|
-
[
|
7
|
-
[
|
8
|
-
[
|
9
|
-
[
|
10
|
-
[
|
11
|
-
[
|
12
|
-
[
|
13
|
-
[
|
14
|
-
[
|
15
|
-
[
|
16
|
-
[
|
17
|
-
[
|
18
|
-
[
|
19
|
-
[
|
20
|
-
[
|
21
|
-
[
|
22
|
-
[
|
23
|
-
[
|
24
|
-
[
|
25
|
-
[
|
26
|
-
[
|
27
|
-
[
|
28
|
-
[
|
29
|
-
[
|
30
|
-
[
|
31
|
-
[
|
32
|
-
[
|
33
|
-
[
|
34
|
-
[
|
1
|
+
lib/flag_shih_tzu.rb -- 60 warnings:
|
2
|
+
[4]:FlagShihTzu has no descriptive comment (IrresponsibleModule)
|
3
|
+
[423, 431, 438, 445, 573]:FlagShihTzu takes parameters [colmn, flag] to 5 methods (DataClump)
|
4
|
+
[532]:FlagShihTzu#chained_flags_with_signature has approx 6 statements (TooManyStatements)
|
5
|
+
[566]:FlagShihTzu#collect_flags doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
6
|
+
[433, 435]:FlagShihTzu#disable_flag calls self.class 2 times (DuplicateMethodCall)
|
7
|
+
[432]:FlagShihTzu#disable_flag performs a nil-check (NilCheck)
|
8
|
+
[425, 427]:FlagShihTzu#enable_flag calls self.class 2 times (DuplicateMethodCall)
|
9
|
+
[424]:FlagShihTzu#enable_flag performs a nil-check (NilCheck)
|
10
|
+
[446]:FlagShihTzu#flag_disabled? performs a nil-check (NilCheck)
|
11
|
+
[439]:FlagShihTzu#flag_enabled? performs a nil-check (NilCheck)
|
12
|
+
[502, 511, 512, 514, 515]:FlagShihTzu#update_flag! calls self.class 5 times (DuplicateMethodCall)
|
13
|
+
[512, 515]:FlagShihTzu#update_flag! calls self.class.primary_key 2 times (DuplicateMethodCall)
|
14
|
+
[500]:FlagShihTzu#update_flag! has approx 6 statements (TooManyStatements)
|
15
|
+
[500]:FlagShihTzu#update_flag! has boolean parameter 'update_instance' (BooleanParameter)
|
16
|
+
[503]:FlagShihTzu#update_flag! is controlled by argument update_instance (ControlParameter)
|
17
|
+
[23]:FlagShihTzu::ClassMethods has no descriptive comment (IrresponsibleModule)
|
18
|
+
[244, 257, 367, 386, 391]:FlagShihTzu::ClassMethods takes parameters [colmn, flag] to 5 methods (DataClump)
|
19
|
+
[299, 301]:FlagShihTzu::ClassMethods#chained_flags_values calls flag.to_s 2 times (DuplicateMethodCall)
|
20
|
+
[295]:FlagShihTzu::ClassMethods#chained_flags_values has approx 10 statements (TooManyStatements)
|
21
|
+
[274, 276]:FlagShihTzu::ClassMethods#chained_flags_with calls chained_flags_condition(column, *args) 2 times (DuplicateMethodCall)
|
22
|
+
[249, 249]:FlagShihTzu::ClassMethods#check_flag calls flag_mapping[colmn] 2 times (DuplicateMethodCall)
|
23
|
+
[249]:FlagShihTzu::ClassMethods#check_flag performs a nil-check (NilCheck)
|
24
|
+
[330]:FlagShihTzu::ClassMethods#check_flag_column has approx 11 statements (TooManyStatements)
|
25
|
+
[346]:FlagShihTzu::ClassMethods#check_flag_column performs a nil-check (NilCheck)
|
26
|
+
[263]:FlagShihTzu::ClassMethods#determine_flag_colmn_for performs a nil-check (NilCheck)
|
27
|
+
[74, 80]:FlagShihTzu::ClassMethods#has_flags calls 1 << (flag_key - 1) 2 times (DuplicateMethodCall)
|
28
|
+
[35, 42]:FlagShihTzu::ClassMethods#has_flags calls caller.first 2 times (DuplicateMethodCall)
|
29
|
+
[139, 212, 220]:FlagShihTzu::ClassMethods#has_flags calls colmn.singularize 3 times (DuplicateMethodCall)
|
30
|
+
[74, 80]:FlagShihTzu::ClassMethods#has_flags calls flag_key - 1 2 times (DuplicateMethodCall)
|
31
|
+
[58, 74, 80]:FlagShihTzu::ClassMethods#has_flags calls flag_mapping[colmn] 3 times (DuplicateMethodCall)
|
32
|
+
[157, 228]:FlagShihTzu::ClassMethods#has_flags calls flag_options[colmn] 2 times (DuplicateMethodCall)
|
33
|
+
[34, 36, 38]:FlagShihTzu::ClassMethods#has_flags calls opts[:column] 3 times (DuplicateMethodCall)
|
34
|
+
[61, 62]:FlagShihTzu::ClassMethods#has_flags calls self.flag_columns 2 times (DuplicateMethodCall)
|
35
|
+
[52, 55]:FlagShihTzu::ClassMethods#has_flags calls self.flag_mapping 2 times (DuplicateMethodCall)
|
35
36
|
[24]:FlagShihTzu::ClassMethods#has_flags has approx 26 statements (TooManyStatements)
|
36
|
-
[
|
37
|
-
[
|
38
|
-
[
|
39
|
-
[
|
40
|
-
[
|
41
|
-
[
|
42
|
-
[
|
43
|
-
[
|
44
|
-
[
|
45
|
-
[
|
46
|
-
[
|
47
|
-
[
|
48
|
-
[
|
49
|
-
[
|
50
|
-
[
|
51
|
-
[
|
52
|
-
[
|
53
|
-
[
|
54
|
-
[
|
55
|
-
[
|
56
|
-
[
|
57
|
-
[
|
58
|
-
[303]:FlagShihTzu::ClassMethods#sql_set_for_flag has unused parameter 'custom_table_name' (UnusedParameters)
|
59
|
-
[305]:FlagShihTzu::ClassMethods#sql_set_for_flag is controlled by argument enabled (ControlParameter)
|
37
|
+
[55]:FlagShihTzu::ClassMethods#has_flags performs a nil-check (NilCheck)
|
38
|
+
[411]:FlagShihTzu::ClassMethods#named_scope_method doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
39
|
+
[315, 317]:FlagShihTzu::ClassMethods#parse_flag_options calls args.shift 2 times (DuplicateMethodCall)
|
40
|
+
[314]:FlagShihTzu::ClassMethods#parse_flag_options doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
41
|
+
[314]:FlagShihTzu::ClassMethods#parse_flag_options has approx 7 statements (TooManyStatements)
|
42
|
+
[257]:FlagShihTzu::ClassMethods#set_flag_sql has 4 parameters (LongParameterList)
|
43
|
+
[258]:FlagShihTzu::ClassMethods#set_flag_sql performs a nil-check (NilCheck)
|
44
|
+
[373, 373]:FlagShihTzu::ClassMethods#sql_condition_for_flag calls flag_mapping[colmn] 2 times (DuplicateMethodCall)
|
45
|
+
[373, 373]:FlagShihTzu::ClassMethods#sql_condition_for_flag calls flag_mapping[colmn][flag] 2 times (DuplicateMethodCall)
|
46
|
+
[370, 374]:FlagShihTzu::ClassMethods#sql_condition_for_flag calls flag_options[colmn] 2 times (DuplicateMethodCall)
|
47
|
+
[370, 374]:FlagShihTzu::ClassMethods#sql_condition_for_flag calls flag_options[colmn][:flag_query_mode] 2 times (DuplicateMethodCall)
|
48
|
+
[367]:FlagShihTzu::ClassMethods#sql_condition_for_flag has 4 parameters (LongParameterList)
|
49
|
+
[367]:FlagShihTzu::ClassMethods#sql_condition_for_flag has approx 7 statements (TooManyStatements)
|
50
|
+
[367]:FlagShihTzu::ClassMethods#sql_condition_for_flag has boolean parameter 'enabled' (BooleanParameter)
|
51
|
+
[373, 378]:FlagShihTzu::ClassMethods#sql_condition_for_flag is controlled by argument enabled (ControlParameter)
|
52
|
+
[391]:FlagShihTzu::ClassMethods#sql_set_for_flag has 4 parameters (LongParameterList)
|
53
|
+
[391]:FlagShihTzu::ClassMethods#sql_set_for_flag has boolean parameter 'enabled' (BooleanParameter)
|
54
|
+
[391]:FlagShihTzu::ClassMethods#sql_set_for_flag has unused parameter 'custom_table_name' (UnusedParameters)
|
55
|
+
[393]:FlagShihTzu::ClassMethods#sql_set_for_flag is controlled by argument enabled (ControlParameter)
|
56
|
+
[404]:FlagShihTzu::ClassMethods#valid_flag_column_name? doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
57
|
+
[396]:FlagShihTzu::ClassMethods#valid_flag_key? doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
58
|
+
[400]:FlagShihTzu::ClassMethods#valid_flag_name? doesn't depend on instance state (maybe move it to another class?) (UtilityFunction)
|
60
59
|
[21]:FlagShihTzu::DuplicateFlagColumnException has no descriptive comment (IrresponsibleModule)
|
61
|
-
[18]:FlagShihTzu::IncorrectFlagColumnException has no descriptive comment (IrresponsibleModule)
|
62
60
|
[20]:FlagShihTzu::NoSuchFlagException has no descriptive comment (IrresponsibleModule)
|
63
61
|
[19]:FlagShihTzu::NoSuchFlagQueryModeException has no descriptive comment (IrresponsibleModule)
|
64
|
-
lib/flag_shih_tzu/validators.rb --
|
65
|
-
[
|
66
|
-
[
|
67
|
-
[
|
68
|
-
|
69
|
-
lib/flag_shih_tzu/version.rb -- 0 warnings
|
70
|
-
66 total warnings
|
62
|
+
lib/flag_shih_tzu/validators.rb -- 3 warnings:
|
63
|
+
[29, 30]:ActiveModel::Validations::PresenceOfFlagsValidator#check_flag calls record.class 2 times (DuplicateMethodCall)
|
64
|
+
[29, 30]:ActiveModel::Validations::PresenceOfFlagsValidator#check_flag calls record.class.flag_columns 2 times (DuplicateMethodCall)
|
65
|
+
[29, 30]:ActiveModel::Validations::PresenceOfFlagsValidator#check_flag refers to record more than self (maybe move it to another class?) (FeatureEnvy)
|
66
|
+
63 total warnings
|
data/Rakefile
CHANGED
data/bin/test.bash
CHANGED
@@ -1,26 +1,76 @@
|
|
1
1
|
#!/bin/bash --login
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
gem_installed() {
|
4
|
+
num=$(gem list $1 | grep -e "^$1 " | wc -l)
|
5
|
+
if [ $num -eq "1" ]; then
|
6
|
+
echo "already installed $1"
|
7
|
+
else
|
8
|
+
gem install $1
|
9
|
+
fi
|
10
|
+
return 0
|
11
|
+
}
|
12
|
+
|
13
|
+
# First run the tests for all versions supported on Ruby 1.9.3
|
14
|
+
COMPATIBLE_VERSIONS=(2.3.x 3.0.x 3.1.x 3.2.x)
|
15
|
+
count=0
|
16
|
+
while [ "x${COMPATIBLE_VERSIONS[count]}" != "x" ]
|
17
|
+
do
|
18
|
+
version=${COMPATIBLE_VERSIONS[count]}
|
19
|
+
rvm use 1.9.3@flag_shih_tzu-$version --create
|
20
|
+
gem_installed "bundler"
|
21
|
+
BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle update --quiet
|
22
|
+
NOCOVER=true BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle exec rake test
|
23
|
+
count=$(( $count + 1 ))
|
24
|
+
done
|
25
|
+
|
26
|
+
# Then run the tests for all versions supported on Ruby 2.0.0
|
27
|
+
COMPATIBLE_VERSIONS=(3.0.x 3.1.x 3.2.x 4.0.x 4.1.x)
|
28
|
+
count=0
|
29
|
+
while [ "x${COMPATIBLE_VERSIONS[count]}" != "x" ]
|
30
|
+
do
|
31
|
+
version=${COMPATIBLE_VERSIONS[count]}
|
32
|
+
rvm use 2.0.0@flag_shih_tzu-$version --create
|
33
|
+
gem_installed "bundler"
|
34
|
+
BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle install --quiet
|
35
|
+
NOCOVER=true BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle exec rake test
|
36
|
+
count=$(( $count + 1 ))
|
37
|
+
done
|
38
|
+
|
39
|
+
# Then run the tests for all versions supported on Ruby 2.1.5
|
40
|
+
COMPATIBLE_VERSIONS=(3.2.x 4.0.x 4.1.x 4.2.x)
|
41
|
+
count=0
|
42
|
+
while [ "x${COMPATIBLE_VERSIONS[count]}" != "x" ]
|
43
|
+
do
|
44
|
+
version=${COMPATIBLE_VERSIONS[count]}
|
45
|
+
rvm use 2.1.5@flag_shih_tzu-$version --create
|
46
|
+
gem_installed "bundler"
|
47
|
+
BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle install --quiet
|
48
|
+
NOCOVER=true BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle exec rake test
|
49
|
+
count=$(( $count + 1 ))
|
50
|
+
done
|
51
|
+
|
52
|
+
# Then run the tests for all versions supported on Ruby 2.2.3
|
53
|
+
COMPATIBLE_VERSIONS=(3.2.x 4.0.x 4.1.x 4.2.x)
|
7
54
|
count=0
|
8
55
|
while [ "x${COMPATIBLE_VERSIONS[count]}" != "x" ]
|
9
56
|
do
|
10
57
|
version=${COMPATIBLE_VERSIONS[count]}
|
58
|
+
rvm use 2.2.3@flag_shih_tzu-$version --create
|
59
|
+
gem_installed "bundler"
|
11
60
|
BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle install --quiet
|
12
61
|
NOCOVER=true BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle exec rake test
|
13
62
|
count=$(( $count + 1 ))
|
14
63
|
done
|
15
64
|
|
16
|
-
# Then run the tests
|
17
|
-
|
18
|
-
|
19
|
-
COMPATIBLE_VERSIONS=(3.2.x 4.0.x 4.1.x)
|
65
|
+
# Then run the tests for all versions supported on jruby-9.0.1.0
|
66
|
+
# (which should be the same as the Ruby 2.2.3 compatibility set)
|
67
|
+
COMPATIBLE_VERSIONS=(3.2.x 4.0.x 4.1.x 4.2.x)
|
20
68
|
count=0
|
21
69
|
while [ "x${COMPATIBLE_VERSIONS[count]}" != "x" ]
|
22
70
|
do
|
23
71
|
version=${COMPATIBLE_VERSIONS[count]}
|
72
|
+
rvm use jruby-9.0.1.0@flag_shih_tzu-$version --create
|
73
|
+
gem_installed "bundler"
|
24
74
|
BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle install --quiet
|
25
75
|
NOCOVER=true BUNDLE_GEMFILE="gemfiles/Gemfile.activerecord-$version" bundle exec rake test
|
26
76
|
count=$(( $count + 1 ))
|
data/flag_shih_tzu.gemspec
CHANGED
@@ -26,10 +26,10 @@ ActiveRecord object.
|
|
26
26
|
s.add_development_dependency "activerecord", ">= 2.3.0"
|
27
27
|
|
28
28
|
s.add_development_dependency "bundler"
|
29
|
-
s.add_development_dependency "rdoc", ">= 2.4.2"
|
30
|
-
s.add_development_dependency(%q<reek>, [">= 1.2.8"])
|
31
|
-
s.add_development_dependency(%q<roodi>, [">= 2.1.0"])
|
32
29
|
s.add_development_dependency "rake"
|
30
|
+
s.add_development_dependency "rdoc", ">= 2.4.2"
|
31
|
+
s.add_development_dependency "reek", ">= 2.2.1" # Last version to support Ruby 1.9
|
32
|
+
s.add_development_dependency "roodi", ">= 5"
|
33
33
|
s.add_development_dependency "coveralls"
|
34
|
-
s.add_development_dependency "
|
34
|
+
s.add_development_dependency "test-unit"
|
35
35
|
end
|
@@ -1,6 +1,17 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem
|
6
|
-
|
5
|
+
gem "mime-types", "< 2.0.0", :platforms => [:ruby_18]
|
6
|
+
|
7
|
+
gem "activerecord", "~> 2.3.0"
|
8
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
10
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
11
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
12
|
+
gem "pg", :platforms => [:ruby_18]
|
13
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
14
|
+
|
15
|
+
gem "rake", "~> 0.9.6"
|
16
|
+
gem "reek", "~> 2.2.1"
|
17
|
+
gem "roodi", "~> 5.0.0"
|
@@ -1,6 +1,16 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem
|
6
|
-
|
5
|
+
gem "mime-types", "< 2.0.0", :platforms => [:ruby_18]
|
6
|
+
|
7
|
+
gem "activerecord", "~> 3.0.0"
|
8
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
10
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
11
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
12
|
+
gem "pg", :platforms => [:ruby_18]
|
13
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
14
|
+
|
15
|
+
gem "reek", "~> 2.2.1"
|
16
|
+
gem "roodi", "~> 5.0.0"
|
@@ -1,6 +1,16 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem
|
6
|
-
|
5
|
+
gem "mime-types", "< 2.0.0", :platforms => [:ruby_18]
|
6
|
+
|
7
|
+
gem "activerecord", "~> 3.1.0"
|
8
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
10
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
11
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
12
|
+
gem "pg", :platforms => [:ruby_18]
|
13
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
14
|
+
|
15
|
+
gem "reek", "~> 2.2.1"
|
16
|
+
gem "roodi", "~> 5.0.0"
|
@@ -1,6 +1,16 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem
|
6
|
-
|
5
|
+
gem "mime-types", "< 2.0.0", :platforms => [:ruby_18]
|
6
|
+
|
7
|
+
gem "activerecord", "~> 3.2.0"
|
8
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
10
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
11
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
12
|
+
gem "pg", :platforms => [:ruby_18]
|
13
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
14
|
+
|
15
|
+
gem "reek", "~> 2.2.1"
|
16
|
+
gem "roodi", "~> 5.0.0"
|
@@ -1,5 +1,11 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem "activerecord", "~>4.0.0"
|
5
|
+
gem "activerecord", "~> 4.0.0"
|
6
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
7
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
8
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
10
|
+
gem "pg", :platforms => [:ruby_18]
|
11
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
@@ -1,6 +1,11 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :path =>
|
3
|
+
gemspec :path => ".."
|
4
4
|
|
5
|
-
gem "activerecord", "~>4.1.0"
|
6
|
-
gem "
|
5
|
+
gem "activerecord", "~> 4.1.0"
|
6
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
7
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
8
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
10
|
+
gem "pg", :platforms => [:ruby_18]
|
11
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec :path => ".."
|
4
|
+
|
5
|
+
gem "activerecord", "~> 4.2.0"
|
6
|
+
gem "sqlite3", "~> 1.3", :platforms => [:ruby]
|
7
|
+
gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
|
8
|
+
gem "activerecord-mysql2-adapter", :platforms => [:ruby]
|
9
|
+
gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
|
10
|
+
gem "pg", :platforms => [:ruby_18]
|
11
|
+
gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
|
data/lib/flag_shih_tzu.rb
CHANGED
@@ -3,9 +3,9 @@ require "flag_shih_tzu/validators"
|
|
3
3
|
|
4
4
|
module FlagShihTzu
|
5
5
|
# taken from ActiveRecord::ConnectionAdapters::Column
|
6
|
-
TRUE_VALUES = [true, 1,
|
6
|
+
TRUE_VALUES = [true, 1, "1", "t", "T", "true", "TRUE"]
|
7
7
|
|
8
|
-
DEFAULT_COLUMN_NAME =
|
8
|
+
DEFAULT_COLUMN_NAME = "flags"
|
9
9
|
|
10
10
|
def self.included(base)
|
11
11
|
base.extend(ClassMethods)
|
@@ -14,6 +14,7 @@ module FlagShihTzu
|
|
14
14
|
base.class_attribute :flag_columns unless defined?(base.flag_columns)
|
15
15
|
end
|
16
16
|
|
17
|
+
# TODO: Inherit from StandardException
|
17
18
|
class IncorrectFlagColumnException < Exception; end
|
18
19
|
class NoSuchFlagQueryModeException < Exception; end
|
19
20
|
class NoSuchFlagException < Exception; end
|
@@ -22,53 +23,72 @@ module FlagShihTzu
|
|
22
23
|
module ClassMethods
|
23
24
|
def has_flags(*args)
|
24
25
|
flag_hash, opts = parse_flag_options(*args)
|
25
|
-
opts =
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
opts =
|
27
|
+
{
|
28
|
+
named_scopes: true,
|
29
|
+
column: DEFAULT_COLUMN_NAME,
|
30
|
+
flag_query_mode: :in_list, # or :bit_operator
|
31
|
+
strict: false,
|
32
|
+
check_for_column: true
|
33
|
+
}.update(opts)
|
34
|
+
if !valid_flag_column_name?(opts[:column])
|
35
|
+
warn %[FlagShihTzu says: Please use a String to designate column names! I see you here: #{caller.first}]
|
34
36
|
opts[:column] = opts[:column].to_s
|
35
37
|
end
|
36
38
|
colmn = opts[:column]
|
37
|
-
if opts[:check_for_column] && !check_flag_column(colmn)
|
38
|
-
warn
|
39
|
+
if opts[:check_for_column] && (active_record_class? && !check_flag_column(colmn))
|
40
|
+
warn(
|
41
|
+
%[FlagShihTzu says: Flag column #{colmn} appears to be missing!
|
42
|
+
To turn off this warning set check_for_column: false in has_flags definition here: #{caller.first}]
|
43
|
+
)
|
39
44
|
return
|
40
45
|
end
|
41
46
|
|
42
47
|
# options are stored in a class level hash and apply per-column
|
43
48
|
self.flag_options ||= {}
|
44
|
-
|
49
|
+
flag_options[colmn] = opts
|
45
50
|
|
46
51
|
# the mappings are stored in this class level hash and apply per-column
|
47
52
|
self.flag_mapping ||= {}
|
48
|
-
#If we already have an instance of the same column in the flag_mapping,
|
49
|
-
|
50
|
-
self.flag_mapping[colmn]
|
53
|
+
# If we already have an instance of the same column in the flag_mapping,
|
54
|
+
# then there is a double definition on a column
|
55
|
+
if opts[:strict] && !self.flag_mapping[colmn].nil?
|
56
|
+
raise DuplicateFlagColumnException
|
57
|
+
end
|
58
|
+
flag_mapping[colmn] ||= {}
|
51
59
|
|
52
60
|
# keep track of which flag columns are defined on this class
|
53
61
|
self.flag_columns ||= []
|
54
62
|
self.flag_columns << colmn
|
55
63
|
|
56
64
|
flag_hash.each do |flag_key, flag_name|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
65
|
+
unless valid_flag_key?(flag_key)
|
66
|
+
raise ArgumentError,
|
67
|
+
%[has_flags: flag keys should be positive integers, and #{flag_key} is not]
|
68
|
+
end
|
69
|
+
unless valid_flag_name?(flag_name)
|
70
|
+
raise ArgumentError,
|
71
|
+
%[has_flags: flag names should be symbols, and #{flag_name} is not]
|
72
|
+
end
|
73
|
+
# next if method already defined by flag_shih_tzu
|
74
|
+
next if flag_mapping[colmn][flag_name] & (1 << (flag_key - 1))
|
75
|
+
if method_defined?(flag_name)
|
76
|
+
raise ArgumentError,
|
77
|
+
%[has_flags: flag name #{flag_name} already defined, please choose different name]
|
78
|
+
end
|
61
79
|
|
62
80
|
flag_mapping[colmn][flag_name] = 1 << (flag_key - 1)
|
63
81
|
|
64
82
|
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
65
83
|
def #{flag_name}
|
66
|
-
flag_enabled?(:#{flag_name},
|
84
|
+
flag_enabled?(:#{flag_name}, "#{colmn}")
|
67
85
|
end
|
68
86
|
alias :#{flag_name}? :#{flag_name}
|
69
87
|
|
70
88
|
def #{flag_name}=(value)
|
71
|
-
FlagShihTzu::TRUE_VALUES.include?(value) ?
|
89
|
+
FlagShihTzu::TRUE_VALUES.include?(value) ?
|
90
|
+
enable_flag(:#{flag_name}, "#{colmn}") :
|
91
|
+
disable_flag(:#{flag_name}, "#{colmn}")
|
72
92
|
end
|
73
93
|
|
74
94
|
def not_#{flag_name}
|
@@ -77,75 +97,115 @@ module FlagShihTzu
|
|
77
97
|
alias :not_#{flag_name}? :not_#{flag_name}
|
78
98
|
|
79
99
|
def not_#{flag_name}=(value)
|
80
|
-
FlagShihTzu::TRUE_VALUES.include?(value) ?
|
100
|
+
FlagShihTzu::TRUE_VALUES.include?(value) ?
|
101
|
+
disable_flag(:#{flag_name}, "#{colmn}") :
|
102
|
+
enable_flag(:#{flag_name}, "#{colmn}")
|
81
103
|
end
|
82
104
|
|
83
105
|
def #{flag_name}_changed?
|
84
|
-
if colmn_changes = changes[
|
85
|
-
flag_bit = self.class.flag_mapping[
|
106
|
+
if colmn_changes = changes["#{colmn}"]
|
107
|
+
flag_bit = self.class.flag_mapping["#{colmn}"][:#{flag_name}]
|
86
108
|
(colmn_changes[0] & flag_bit) != (colmn_changes[1] & flag_bit)
|
87
109
|
else
|
88
110
|
false
|
89
111
|
end
|
90
112
|
end
|
91
113
|
|
92
|
-
|
93
|
-
sql_condition_for_flag(:#{flag_name}, '#{colmn}', true, options[:table_alias] || self.table_name)
|
94
|
-
end
|
114
|
+
EVAL
|
95
115
|
|
96
|
-
|
97
|
-
|
98
|
-
|
116
|
+
if active_record_class?
|
117
|
+
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
118
|
+
def self.#{flag_name}_condition(options = {})
|
119
|
+
sql_condition_for_flag(
|
120
|
+
:#{flag_name},
|
121
|
+
"#{colmn}",
|
122
|
+
true,
|
123
|
+
options[:table_alias] || table_name
|
124
|
+
)
|
125
|
+
end
|
99
126
|
|
100
|
-
|
101
|
-
|
102
|
-
|
127
|
+
def self.not_#{flag_name}_condition
|
128
|
+
sql_condition_for_flag(:#{flag_name}, "#{colmn}", false)
|
129
|
+
end
|
103
130
|
|
104
|
-
|
105
|
-
|
106
|
-
|
131
|
+
def self.set_#{flag_name}_sql
|
132
|
+
sql_set_for_flag(:#{flag_name}, "#{colmn}", true)
|
133
|
+
end
|
107
134
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
values_for_flag
|
135
|
+
def self.unset_#{flag_name}_sql
|
136
|
+
sql_set_for_flag(:#{flag_name}, "#{colmn}", false)
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.#{colmn.singularize}_values_for(*flag_names)
|
140
|
+
values = []
|
141
|
+
flag_names.each do |flag_name|
|
142
|
+
if respond_to?(flag_name)
|
143
|
+
values_for_flag = send(:sql_in_for_flag, flag_name, "#{colmn}")
|
144
|
+
values = if values.present?
|
145
|
+
values & values_for_flag
|
146
|
+
else
|
147
|
+
values_for_flag
|
148
|
+
end
|
117
149
|
end
|
118
150
|
end
|
151
|
+
|
152
|
+
values.sort
|
119
153
|
end
|
154
|
+
EVAL
|
120
155
|
|
121
|
-
|
156
|
+
# Define the named scopes if the user wants them and AR supports it
|
157
|
+
if flag_options[colmn][:named_scopes]
|
158
|
+
if ActiveRecord::VERSION::MAJOR == 2 && respond_to?(:named_scope)
|
159
|
+
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
160
|
+
named_scope :#{flag_name}, lambda {
|
161
|
+
{ conditions: #{flag_name}_condition }
|
162
|
+
}
|
163
|
+
named_scope :not_#{flag_name}, lambda {
|
164
|
+
{ conditions: not_#{flag_name}_condition }
|
165
|
+
}
|
166
|
+
EVAL
|
167
|
+
elsif respond_to?(:scope)
|
168
|
+
# Prevent deprecation notices on Rails 3
|
169
|
+
# when using +named_scope+ instead of +scope+.
|
170
|
+
# Prevent deprecation notices on Rails 4
|
171
|
+
# when using +conditions+ instead of +where+.
|
172
|
+
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
173
|
+
scope :#{flag_name}, lambda {
|
174
|
+
where(#{flag_name}_condition)
|
175
|
+
}
|
176
|
+
scope :not_#{flag_name}, lambda {
|
177
|
+
where(not_#{flag_name}_condition)
|
178
|
+
}
|
179
|
+
EVAL
|
180
|
+
end
|
122
181
|
end
|
123
|
-
|
182
|
+
|
183
|
+
end
|
124
184
|
|
125
185
|
if colmn != DEFAULT_COLUMN_NAME
|
126
186
|
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
127
187
|
|
128
188
|
def all_#{colmn}
|
129
|
-
all_flags(
|
189
|
+
all_flags("#{colmn}")
|
130
190
|
end
|
131
191
|
|
132
192
|
def selected_#{colmn}
|
133
|
-
selected_flags(
|
193
|
+
selected_flags("#{colmn}")
|
134
194
|
end
|
135
195
|
|
136
196
|
def select_all_#{colmn}
|
137
|
-
select_all_flags(
|
197
|
+
select_all_flags("#{colmn}")
|
138
198
|
end
|
139
199
|
|
140
200
|
def unselect_all_#{colmn}
|
141
|
-
unselect_all_flags(
|
201
|
+
unselect_all_flags("#{colmn}")
|
142
202
|
end
|
143
203
|
|
144
204
|
# useful for a form builder
|
145
205
|
def selected_#{colmn}=(chosen_flags)
|
146
|
-
unselect_all_flags(
|
206
|
+
unselect_all_flags("#{colmn}")
|
147
207
|
chosen_flags.each do |selected_flag|
|
148
|
-
enable_flag(selected_flag.to_sym,
|
208
|
+
enable_flag(selected_flag.to_sym, "#{colmn}") if selected_flag.present?
|
149
209
|
end
|
150
210
|
end
|
151
211
|
|
@@ -154,11 +214,11 @@ module FlagShihTzu
|
|
154
214
|
end
|
155
215
|
|
156
216
|
def chained_#{colmn}_with_signature(*args)
|
157
|
-
chained_flags_with_signature(
|
217
|
+
chained_flags_with_signature("#{colmn}", *args)
|
158
218
|
end
|
159
219
|
|
160
220
|
def as_#{colmn.singularize}_collection(*args)
|
161
|
-
as_flag_collection(
|
221
|
+
as_flag_collection("#{colmn}", *args)
|
162
222
|
end
|
163
223
|
|
164
224
|
EVAL
|
@@ -168,65 +228,57 @@ module FlagShihTzu
|
|
168
228
|
if flag_options[colmn][:bang_methods]
|
169
229
|
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
170
230
|
def #{flag_name}!
|
171
|
-
enable_flag(:#{flag_name},
|
231
|
+
enable_flag(:#{flag_name}, "#{colmn}")
|
172
232
|
end
|
173
233
|
|
174
234
|
def not_#{flag_name}!
|
175
|
-
disable_flag(:#{flag_name},
|
235
|
+
disable_flag(:#{flag_name}, "#{colmn}")
|
176
236
|
end
|
177
237
|
EVAL
|
178
238
|
end
|
179
239
|
|
180
|
-
# Define the named scopes if the user wants them and AR supports it
|
181
|
-
if flag_options[colmn][:named_scopes]
|
182
|
-
if ActiveRecord::VERSION::MAJOR == 2 && respond_to?(:named_scope)
|
183
|
-
# Prevent deprecation notices on Rails 3 when using +named_scope+ instead of +scope+.
|
184
|
-
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
185
|
-
named_scope :#{flag_name}, lambda { { :conditions => #{flag_name}_condition } }
|
186
|
-
named_scope :not_#{flag_name}, lambda { { :conditions => not_#{flag_name}_condition } }
|
187
|
-
EVAL
|
188
|
-
elsif respond_to?(:scope)
|
189
|
-
# Prevent deprecation notices on Rails 4 when using +conditions+ instead of +where+.
|
190
|
-
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
191
|
-
scope :#{flag_name}, lambda { where(#{flag_name}_condition) }
|
192
|
-
scope :not_#{flag_name}, lambda { where(not_#{flag_name}_condition) }
|
193
|
-
EVAL
|
194
|
-
end
|
195
|
-
end
|
196
240
|
end
|
197
241
|
|
198
242
|
end
|
199
243
|
|
200
244
|
def check_flag(flag, colmn)
|
201
|
-
|
202
|
-
|
245
|
+
unless colmn.is_a?(String)
|
246
|
+
raise ArgumentError,
|
247
|
+
%[Column name "#{colmn}" for flag "#{flag}" is not a string]
|
248
|
+
end
|
249
|
+
if flag_mapping[colmn].nil? || !flag_mapping[colmn].include?(flag)
|
250
|
+
raise ArgumentError,
|
251
|
+
%[Invalid flag "#{flag}"]
|
252
|
+
end
|
203
253
|
end
|
204
254
|
|
205
255
|
# Returns SQL statement to enable/disable flag.
|
206
256
|
# Automatically determines the correct column.
|
207
|
-
def set_flag_sql(flag, value, colmn = nil, custom_table_name =
|
257
|
+
def set_flag_sql(flag, value, colmn = nil, custom_table_name = table_name)
|
208
258
|
colmn = determine_flag_colmn_for(flag) if colmn.nil?
|
209
259
|
sql_set_for_flag(flag, colmn, value, custom_table_name)
|
210
260
|
end
|
211
261
|
|
212
262
|
def determine_flag_colmn_for(flag)
|
213
|
-
return DEFAULT_COLUMN_NAME if
|
214
|
-
|
263
|
+
return DEFAULT_COLUMN_NAME if flag_mapping.nil?
|
264
|
+
flag_mapping.each_pair do |colmn, mapping|
|
215
265
|
return colmn if mapping.include?(flag)
|
216
266
|
end
|
217
|
-
raise NoSuchFlagException.new(
|
267
|
+
raise NoSuchFlagException.new(
|
268
|
+
%[determine_flag_colmn_for: Couldn't determine column for your flags!]
|
269
|
+
)
|
218
270
|
end
|
219
271
|
|
220
272
|
def chained_flags_with(column = DEFAULT_COLUMN_NAME, *args)
|
221
273
|
if (ActiveRecord::VERSION::MAJOR >= 3)
|
222
274
|
where(chained_flags_condition(column, *args))
|
223
275
|
else
|
224
|
-
all(:
|
276
|
+
all(conditions: chained_flags_condition(column, *args))
|
225
277
|
end
|
226
278
|
end
|
227
279
|
|
228
280
|
def chained_flags_condition(colmn = DEFAULT_COLUMN_NAME, *args)
|
229
|
-
|
281
|
+
%[(#{table_name}.#{colmn} in (#{chained_flags_values(colmn, *args).join(",")}))]
|
230
282
|
end
|
231
283
|
|
232
284
|
def flag_keys(colmn = DEFAULT_COLUMN_NAME)
|
@@ -235,114 +287,136 @@ module FlagShihTzu
|
|
235
287
|
|
236
288
|
private
|
237
289
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
290
|
+
def flag_value_range_for_column(colmn)
|
291
|
+
max = flag_mapping[colmn].values.max
|
292
|
+
Range.new(0, (2 * max) - 1)
|
293
|
+
end
|
242
294
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
end
|
251
|
-
check_flag(flag, colmn)
|
252
|
-
flag_values = sql_in_for_flag(flag, colmn)
|
253
|
-
if neg
|
254
|
-
val = val - flag_values
|
255
|
-
else
|
256
|
-
val = val & flag_values
|
257
|
-
end
|
295
|
+
def chained_flags_values(colmn, *args)
|
296
|
+
val = flag_value_range_for_column(colmn).to_a
|
297
|
+
args.each do |flag|
|
298
|
+
neg = false
|
299
|
+
if flag.to_s.match /^not_/
|
300
|
+
neg = true
|
301
|
+
flag = flag.to_s.sub(/^not_/, "").to_sym
|
258
302
|
end
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
options = args.shift
|
264
|
-
if args.size >= 1
|
265
|
-
add_options = args.shift
|
303
|
+
check_flag(flag, colmn)
|
304
|
+
flag_values = sql_in_for_flag(flag, colmn)
|
305
|
+
if neg
|
306
|
+
val = val - flag_values
|
266
307
|
else
|
267
|
-
|
268
|
-
hash[key] = options.delete(key)
|
269
|
-
hash
|
270
|
-
end
|
308
|
+
val = val & flag_values
|
271
309
|
end
|
272
|
-
return options, add_options
|
273
310
|
end
|
311
|
+
val
|
312
|
+
end
|
274
313
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
314
|
+
def parse_flag_options(*args)
|
315
|
+
options = args.shift
|
316
|
+
add_options = if args.size >= 1
|
317
|
+
args.shift
|
318
|
+
else
|
319
|
+
options.
|
320
|
+
keys.
|
321
|
+
select { |key| !key.is_a?(Fixnum) }.
|
322
|
+
inject({}) do |hash, key|
|
323
|
+
hash[key] = options.delete(key)
|
324
|
+
hash
|
325
|
+
end
|
326
|
+
end
|
327
|
+
[options, add_options]
|
328
|
+
end
|
329
|
+
|
330
|
+
def check_flag_column(colmn, custom_table_name = table_name)
|
331
|
+
# If you aren't using ActiveRecord (eg. you are outside rails)
|
332
|
+
# then do not fail here
|
333
|
+
# If you are using ActiveRecord then you only want to check for the
|
334
|
+
# table if the table exists so it won't fail pre-migration
|
335
|
+
has_ar = (!!defined?(ActiveRecord) && respond_to?(:descends_from_active_record?))
|
336
|
+
# Supposedly Rails 2.3 takes care of this, but this precaution
|
337
|
+
# is needed for backwards compatibility
|
338
|
+
has_table = has_ar ? connection.tables.include?(custom_table_name) : true
|
339
|
+
if has_table
|
340
|
+
found_column = columns.detect { |column| column.name == colmn }
|
341
|
+
# If you have not yet run the migration that adds the 'flags' column
|
342
|
+
# then we don't want to fail,
|
343
|
+
# because we need to be able to run the migration
|
344
|
+
# If the column is there but is of the wrong type,
|
345
|
+
# then we must fail, because flag_shih_tzu will not work
|
346
|
+
if found_column.nil?
|
347
|
+
warn(
|
348
|
+
%[Error: Column "#{colmn}" doesn't exist on table "#{custom_table_name}". Did you forget to run migrations?]
|
349
|
+
)
|
294
350
|
return false
|
351
|
+
elsif found_column.type != :integer
|
352
|
+
raise IncorrectFlagColumnException.new(
|
353
|
+
%[Table "#{custom_table_name}" must have an integer column named "#{colmn}" in order to use FlagShihTzu.]
|
354
|
+
)
|
295
355
|
end
|
296
|
-
|
297
|
-
|
356
|
+
else
|
357
|
+
# ActiveRecord gem may not have loaded yet?
|
358
|
+
warn(
|
359
|
+
%[FlagShihTzu#has_flags: Table "#{custom_table_name}" doesn't exist. Have all migrations been run?]
|
360
|
+
) if has_ar
|
361
|
+
return false
|
298
362
|
end
|
299
363
|
|
300
|
-
|
301
|
-
|
364
|
+
true
|
365
|
+
end
|
302
366
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
367
|
+
def sql_condition_for_flag(flag, colmn, enabled = true, custom_table_name = table_name)
|
368
|
+
check_flag(flag, colmn)
|
369
|
+
|
370
|
+
if flag_options[colmn][:flag_query_mode] == :bit_operator
|
371
|
+
# use & bit operator directly in the SQL query.
|
372
|
+
# This has the drawback of not using an index on the flags colum.
|
373
|
+
%[(#{custom_table_name}.#{colmn} & #{flag_mapping[colmn][flag]} = #{enabled ? flag_mapping[colmn][flag] : 0})]
|
374
|
+
elsif flag_options[colmn][:flag_query_mode] == :in_list
|
375
|
+
# use IN() operator in the SQL query.
|
376
|
+
# This has the drawback of becoming a big query
|
377
|
+
# when you have lots of flags.
|
378
|
+
neg = enabled ? "" : "not "
|
379
|
+
%[(#{custom_table_name}.#{colmn} #{neg}in (#{sql_in_for_flag(flag, colmn).join(",")}))]
|
380
|
+
else
|
381
|
+
raise NoSuchFlagQueryModeException
|
315
382
|
end
|
383
|
+
end
|
316
384
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
385
|
+
# returns an array of integers suitable for a SQL IN statement.
|
386
|
+
def sql_in_for_flag(flag, colmn)
|
387
|
+
val = flag_mapping[colmn][flag]
|
388
|
+
flag_value_range_for_column(colmn).select { |bits| bits & val == val }
|
389
|
+
end
|
322
390
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
391
|
+
def sql_set_for_flag(flag, colmn, enabled = true, custom_table_name = table_name)
|
392
|
+
check_flag(flag, colmn)
|
393
|
+
"#{colmn} = #{colmn} #{enabled ? "| " : "& ~" }#{flag_mapping[colmn][flag]}"
|
394
|
+
end
|
327
395
|
|
328
|
-
|
329
|
-
|
330
|
-
|
396
|
+
def valid_flag_key?(flag_key)
|
397
|
+
flag_key > 0 && flag_key == flag_key.to_i
|
398
|
+
end
|
331
399
|
|
332
|
-
|
333
|
-
|
334
|
-
|
400
|
+
def valid_flag_name?(flag_name)
|
401
|
+
flag_name.is_a?(Symbol)
|
402
|
+
end
|
335
403
|
|
336
|
-
|
337
|
-
|
338
|
-
|
404
|
+
def valid_flag_column_name?(colmn)
|
405
|
+
colmn.is_a?(String)
|
406
|
+
end
|
339
407
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
408
|
+
# Returns the correct method to create a named scope.
|
409
|
+
# Use to prevent deprecation notices on Rails 3
|
410
|
+
# when using +named_scope+ instead of +scope+.
|
411
|
+
def named_scope_method
|
412
|
+
# Can't use respond_to because both AR 2 and 3
|
413
|
+
# respond to both +scope+ and +named_scope+.
|
414
|
+
ActiveRecord::VERSION::MAJOR == 2 ? :named_scope : :scope
|
415
|
+
end
|
416
|
+
|
417
|
+
def active_record_class?
|
418
|
+
ancestors.include?(ActiveRecord::Base)
|
419
|
+
end
|
346
420
|
end
|
347
421
|
|
348
422
|
# Performs the bitwise operation so the flag will return +true+.
|
@@ -350,7 +424,7 @@ module FlagShihTzu
|
|
350
424
|
colmn = determine_flag_colmn_for(flag) if colmn.nil?
|
351
425
|
self.class.check_flag(flag, colmn)
|
352
426
|
|
353
|
-
set_flags(
|
427
|
+
set_flags(flags(colmn) | self.class.flag_mapping[colmn][flag], colmn)
|
354
428
|
end
|
355
429
|
|
356
430
|
# Performs the bitwise operation so the flag will return +false+.
|
@@ -358,7 +432,7 @@ module FlagShihTzu
|
|
358
432
|
colmn = determine_flag_colmn_for(flag) if colmn.nil?
|
359
433
|
self.class.check_flag(flag, colmn)
|
360
434
|
|
361
|
-
set_flags(
|
435
|
+
set_flags(flags(colmn) & ~self.class.flag_mapping[colmn][flag], colmn)
|
362
436
|
end
|
363
437
|
|
364
438
|
def flag_enabled?(flag, colmn = nil)
|
@@ -388,7 +462,9 @@ module FlagShihTzu
|
|
388
462
|
end
|
389
463
|
|
390
464
|
def selected_flags(colmn = DEFAULT_COLUMN_NAME)
|
391
|
-
all_flags(colmn).
|
465
|
+
all_flags(colmn).
|
466
|
+
map { |flag_name| self.send(flag_name) ? flag_name : nil }.
|
467
|
+
compact
|
392
468
|
end
|
393
469
|
|
394
470
|
# Useful for a form builder
|
@@ -396,7 +472,9 @@ module FlagShihTzu
|
|
396
472
|
def selected_flags=(chosen_flags)
|
397
473
|
unselect_all_flags
|
398
474
|
chosen_flags.each do |selected_flag|
|
399
|
-
|
475
|
+
if selected_flag.present?
|
476
|
+
enable_flag(selected_flag.to_sym, DEFAULT_COLUMN_NAME)
|
477
|
+
end
|
400
478
|
end
|
401
479
|
end
|
402
480
|
|
@@ -417,33 +495,45 @@ module FlagShihTzu
|
|
417
495
|
end
|
418
496
|
|
419
497
|
# returns true if successful
|
420
|
-
# third parameter allows you to specify that `self` should
|
498
|
+
# third parameter allows you to specify that `self` should
|
499
|
+
# also have its in-memory flag attribute updated.
|
421
500
|
def update_flag!(flag, value, update_instance = false)
|
422
501
|
truthy = FlagShihTzu::TRUE_VALUES.include?(value)
|
423
502
|
sql = self.class.set_flag_sql(flag.to_sym, truthy)
|
424
503
|
if update_instance
|
425
504
|
if truthy
|
426
|
-
|
505
|
+
enable_flag(flag)
|
427
506
|
else
|
428
|
-
|
507
|
+
disable_flag(flag)
|
429
508
|
end
|
430
509
|
end
|
431
510
|
if (ActiveRecord::VERSION::MAJOR <= 3)
|
432
|
-
self.class.
|
511
|
+
self.class.
|
512
|
+
update_all(sql, self.class.primary_key => id) == 1
|
433
513
|
else
|
434
|
-
self.class.
|
514
|
+
self.class.
|
515
|
+
where("#{self.class.primary_key} = ?", id).
|
516
|
+
update_all(sql) == 1
|
435
517
|
end
|
436
518
|
end
|
437
519
|
|
438
|
-
# Use with chained_flags_with to find records with specific flags
|
520
|
+
# Use with chained_flags_with to find records with specific flags
|
521
|
+
# set to the same values as on this record.
|
439
522
|
# For a record that has sent_warm_up_email = true and the other flags false:
|
440
|
-
#
|
441
|
-
#
|
442
|
-
#
|
443
|
-
#
|
523
|
+
#
|
524
|
+
# user.chained_flags_with_signature
|
525
|
+
# => [:sent_warm_up_email,
|
526
|
+
# :not_follow_up_called,
|
527
|
+
# :not_sent_final_email,
|
528
|
+
# :not_scheduled_appointment]
|
529
|
+
# User.chained_flags_with("flags", *user.chained_flags_with_signature)
|
530
|
+
# => the set of Users that have the same flags set as user.
|
531
|
+
#
|
444
532
|
def chained_flags_with_signature(colmn = DEFAULT_COLUMN_NAME, *args)
|
445
533
|
flags_to_collect = args.empty? ? all_flags(colmn) : args
|
446
|
-
truthy_and_chosen =
|
534
|
+
truthy_and_chosen =
|
535
|
+
selected_flags(colmn).
|
536
|
+
select { |flag| flags_to_collect.include?(flag) }
|
447
537
|
truthy_and_chosen.concat(
|
448
538
|
collect_flags(*flags_to_collect) do |memo, flag|
|
449
539
|
memo << "not_#{flag}".to_sym unless truthy_and_chosen.include?(flag)
|
@@ -451,33 +541,41 @@ module FlagShihTzu
|
|
451
541
|
)
|
452
542
|
end
|
453
543
|
|
454
|
-
# Use with a checkbox form builder, like simple_form's
|
455
|
-
#
|
456
|
-
#
|
457
|
-
#
|
458
|
-
#
|
544
|
+
# Use with a checkbox form builder, like rails' or simple_form's
|
545
|
+
# :selected_flags, used in the example below, is a method defined
|
546
|
+
# by flag_shih_tzu for bulk setting flags like this:
|
547
|
+
#
|
548
|
+
# form_for @user do |f|
|
549
|
+
# f.collection_check_boxes(:selected_flags,
|
550
|
+
# f.object.as_flag_collection("flags",
|
551
|
+
# :sent_warm_up_email,
|
552
|
+
# :not_follow_up_called),
|
553
|
+
# :first,
|
554
|
+
# :last)
|
555
|
+
# end
|
556
|
+
#
|
459
557
|
def as_flag_collection(colmn = DEFAULT_COLUMN_NAME, *args)
|
460
558
|
flags_to_collect = args.empty? ? all_flags(colmn) : args
|
461
559
|
collect_flags(*flags_to_collect) do |memo, flag|
|
462
|
-
memo << [flag,
|
560
|
+
memo << [flag, flag_enabled?(flag, colmn)]
|
463
561
|
end
|
464
562
|
end
|
465
563
|
|
466
564
|
private
|
467
565
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
end
|
566
|
+
def collect_flags(*args)
|
567
|
+
args.inject([]) do |memo, flag|
|
568
|
+
yield memo, flag
|
569
|
+
memo
|
473
570
|
end
|
571
|
+
end
|
474
572
|
|
475
|
-
|
476
|
-
|
477
|
-
|
573
|
+
def get_bit_for(flag, colmn)
|
574
|
+
flags(colmn) & self.class.flag_mapping[colmn][flag]
|
575
|
+
end
|
478
576
|
|
479
|
-
|
480
|
-
|
481
|
-
|
577
|
+
def determine_flag_colmn_for(flag)
|
578
|
+
self.class.determine_flag_colmn_for(flag)
|
579
|
+
end
|
482
580
|
|
483
581
|
end
|