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.
Binary file
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  test/debug.log
2
+ test/flag_shih_tzu_plugin.sqlite3.db
2
3
  coverage
3
4
  .idea
4
5
  .idea/*
@@ -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
@@ -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/xing/flag_shih_tzu.png" />}[http://travis-ci.org/xing/flag_shih_tzu]
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
- Opionally, you can set the <tt>:bang_methods</tt> option to true to enable the bang methods:
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/xing/flag_shih_tzu/contributors].
325
+ {contributors}[https://github.com/pboling/flag_shih_tzu/contributors].
299
326
  Thanks!
300
327
 
301
- Please find out more about our work in our
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
@@ -27,5 +27,6 @@ ActiveRecord object.
27
27
  s.add_development_dependency "bundler"
28
28
  s.add_development_dependency "rdoc", ">= 2.4.2"
29
29
  s.add_development_dependency "rake"
30
+ #s.add_development_dependency "rcov"
30
31
  s.add_development_dependency "sqlite3"
31
32
  end
@@ -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, table_name = self.table_name)
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?(table_name) : true
130
-
131
- logger.warn("Error: Table '#{table_name}' doesn't exist") and return false unless has_table
132
-
133
- if !has_ar || (has_ar && has_table)
134
- if found_column = columns.find {|column| column.name == colmn}
135
- raise IncorrectFlagColumnException, "Warning: Column '#{colmn}'must be of type integer in order to use FlagShihTzu" unless found_column.type == :integer
136
- else
137
- # Do not raise an exception since the migration to add the flags column might still be pending
138
- logger.warn("Warning: Table '#{table_name}' must have an integer column named '#{colmn}' in order to use FlagShihTzu") and return false
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, table_name = self.table_name)
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
- "(#{table_name}.#{colmn} & #{flag_mapping[colmn][flag]} = #{enabled ? flag_mapping[colmn][flag] : 0})"
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
- "(#{table_name}.#{colmn} #{neg}in (#{sql_in_for_flag(flag, colmn).join(',')}))"
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
@@ -1,3 +1,3 @@
1
1
  module FlagShihTzu
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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
@@ -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.2.4
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