r3trofitted-bitmask-attribute 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.markdown
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ \#*
7
+ .#*
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2009 Bruce Williams
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,113 @@
1
+ bitmask-attribute
2
+ =================
3
+
4
+ Transparent manipulation of bitmask attributes.
5
+
6
+ Example
7
+ -------
8
+
9
+ Simply declare an existing integer column as a bitmask with its possible
10
+ values.
11
+
12
+ class User < ActiveRecord::Base
13
+ bitmask :roles, :as => [:writer, :publisher, :editor, :proofreader]
14
+ end
15
+
16
+ You can then modify the column using the declared values without resorting
17
+ to manual bitmasks.
18
+
19
+ user = User.create(:name => "Bruce", :roles => [:publisher, :editor])
20
+ user.roles
21
+ # => [:publisher, :editor]
22
+ user.roles << :writer
23
+ user.roles
24
+ # => [:publisher, :editor, :writer]
25
+
26
+ It's easy to find out if a record has a given value:
27
+
28
+ user.roles?(:editor)
29
+ # => true
30
+
31
+ You can check for multiple values (uses an `and` boolean):
32
+
33
+ user.roles?(:editor, :publisher)
34
+ # => true
35
+ user.roles?(:editor, :proofreader)
36
+ # => false
37
+
38
+ Or, just check if any values are present:
39
+
40
+ user.roles?
41
+ # => true
42
+
43
+ Named Scopes
44
+ ------------
45
+
46
+ A couple useful named scopes are also generated when you use
47
+ `bitmask`:
48
+
49
+ User.with_roles
50
+ # => (all users with roles)
51
+ User.with_roles(:editor)
52
+ # => (all editors)
53
+ User.with_roles(:editor, :writer)
54
+ # => (all users who are BOTH editors and writers)
55
+
56
+ Later we'll support an `or` boolean; for now, do something like:
57
+
58
+ User.with_roles(:editor) + User.with_roles(:writer)
59
+ # => (all users who are EITHER editors and writers)
60
+
61
+ Find records without any bitmask set:
62
+
63
+ User.without_roles
64
+ # => (all users without a role)
65
+
66
+ Later we'll support finding records without a specific bitmask.
67
+
68
+ Adding Methods
69
+ --------------
70
+
71
+ You can add your own methods to the bitmasked attributes (similar to
72
+ named scopes):
73
+
74
+ bitmask :other_attribute, :as => [:value1, :value2] do
75
+ def worked?
76
+ true
77
+ end
78
+ end
79
+
80
+ user = User.first
81
+ user.other_attribute.worked?
82
+ # => true
83
+
84
+
85
+ Warning: Modifying possible values
86
+ ----------------------------------
87
+
88
+ IMPORTANT: Once you have data using a bitmask, don't change the order
89
+ of the values, remove any values, or insert any new values in the `:as`
90
+ array anywhere except at the end. You won't like the results.
91
+
92
+ Contributing and reporting issues
93
+ ---------------------------------
94
+
95
+ Please feel free to fork & contribute fixes via GitHub pull requests.
96
+ The official repository for this project is
97
+ http://github.com/bruce/bitmask-attribute
98
+
99
+ Issues can be reported at
100
+ http://github.com/bruce/bitmask-attribute/issues
101
+
102
+ Credits
103
+ -------
104
+
105
+ Thanks to the following contributors:
106
+
107
+ * [Jason L Perry](http://github.com/ambethia)
108
+ * [Nicolas Fouché](http://github.com/nfo)
109
+
110
+ Copyright
111
+ ---------
112
+
113
+ Copyright (c) 2007-2009 Bruce Williams. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "bitmask-attribute"
8
+ gem.summary = %Q{Simple bitmask attribute support for ActiveRecord}
9
+ gem.email = "bruce@codefluency.com"
10
+ gem.homepage = "http://github.com/bruce/bitmask-attribute"
11
+ gem.authors = ["Bruce Williams"]
12
+ gem.add_dependency 'activerecord'
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+
41
+ task :default => :test
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION.yml')
46
+ config = YAML.load(File.read('VERSION.yml'))
47
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "bitmask-attribute #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.0
@@ -0,0 +1,2 @@
1
+ # Stub for dash-style requires
2
+ require File.dirname(__FILE__) << "/bitmask_attribute"
@@ -0,0 +1,77 @@
1
+ module BitmaskAttribute
2
+
3
+ class ValueProxy < Array
4
+
5
+ def initialize(record, attribute, &extension)
6
+ @record = record
7
+ @attribute = attribute
8
+ find_mapping
9
+ instance_eval(&extension) if extension
10
+ super(extract_values)
11
+ end
12
+
13
+ # =========================
14
+ # = OVERRIDE TO SERIALIZE =
15
+ # =========================
16
+
17
+ %w(push << delete replace reject! select!).each do |override|
18
+ class_eval(<<-EOEVAL)
19
+ def #{override}(*args)
20
+ returning(super) do
21
+ updated!
22
+ end
23
+ end
24
+ EOEVAL
25
+ end
26
+
27
+ def to_i
28
+ inject(0) { |memo, value| memo | @mapping[value] }
29
+ end
30
+
31
+ #######
32
+ private
33
+ #######
34
+
35
+ def validate!
36
+ each do |value|
37
+ if @mapping.key? value
38
+ true
39
+ else
40
+ raise ArgumentError, "Unsupported value for `#{@attribute}': #{value.inspect}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def symbolize!
46
+ map!(&:to_sym)
47
+ end
48
+
49
+ def updated!
50
+ symbolize!
51
+ validate!
52
+ uniq!
53
+ serialize!
54
+ end
55
+
56
+ def serialize!
57
+ @record.send(:write_attribute, @attribute, to_i)
58
+ end
59
+
60
+ def extract_values
61
+ stored = [@record.send(:read_attribute, @attribute) || 0, 0].max
62
+ @mapping.inject([]) do |values, (value, bitmask)|
63
+ returning values do
64
+ values << value.to_sym if (stored & bitmask > 0)
65
+ end
66
+ end
67
+ end
68
+
69
+ def find_mapping
70
+ unless (@mapping = @record.class.bitmasks[@attribute])
71
+ raise ArgumentError, "Could not find mapping for bitmask attribute :#{@attribute}"
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,154 @@
1
+ require 'bitmask_attribute/value_proxy'
2
+
3
+ module BitmaskAttribute
4
+
5
+ class Definition
6
+
7
+ attr_reader :attribute, :values, :extension
8
+ def initialize(attribute, values=[], &extension)
9
+ @attribute = attribute
10
+ @values = values
11
+ @extension = extension
12
+ end
13
+
14
+ def install_on(model)
15
+ validate_for model
16
+ generate_bitmasks_on model
17
+ override model
18
+ create_convenience_class_method_on(model)
19
+ create_convenience_instance_methods_on(model)
20
+ create_named_scopes_on(model)
21
+ end
22
+
23
+ #######
24
+ private
25
+ #######
26
+
27
+ def validate_for(model)
28
+ # The model cannot be validated if it is preloaded and the attribute/column is not in the
29
+ # database (the migration has not been run). This usually
30
+ # occurs in the 'test' and 'production' environments.
31
+ return if defined?(Rails) && Rails.configuration.cache_classes
32
+
33
+ unless model.columns.detect { |col| col.name == attribute.to_s }
34
+ raise ArgumentError, "`#{attribute}' is not an attribute of `#{model}'"
35
+ end
36
+ end
37
+
38
+ def generate_bitmasks_on(model)
39
+ model.bitmasks[attribute] = returning HashWithIndifferentAccess.new do |mapping|
40
+ values.each_with_index do |value, index|
41
+ mapping[value] = 0b1 << index
42
+ end
43
+ end
44
+ end
45
+
46
+ def override(model)
47
+ override_getter_on(model)
48
+ override_setter_on(model)
49
+ end
50
+
51
+ def override_getter_on(model)
52
+ model.class_eval %(
53
+ def #{attribute}
54
+ @#{attribute} ||= BitmaskAttribute::ValueProxy.new(self, :#{attribute}, &self.class.bitmask_definitions[:#{attribute}].extension)
55
+ end
56
+ )
57
+ end
58
+
59
+ def override_setter_on(model)
60
+ model.class_eval %(
61
+ def #{attribute}=(raw_value)
62
+ values = raw_value.kind_of?(Array) ? raw_value : [raw_value]
63
+ self.#{attribute}.replace(values.reject(&:blank?))
64
+ end
65
+ )
66
+ end
67
+
68
+ def create_convenience_class_method_on(model)
69
+ model.class_eval %(
70
+ def self.bitmask_for_#{attribute}(*values)
71
+ values.inject(0) do |bitmask, value|
72
+ unless (bit = bitmasks[:#{attribute}][value])
73
+ raise ArgumentError, "Unsupported value for #{attribute}: \#{value.inspect}"
74
+ end
75
+ bitmask | bit
76
+ end
77
+ end
78
+ )
79
+ end
80
+
81
+
82
+ def create_convenience_instance_methods_on(model)
83
+ values.each do |value|
84
+ model.class_eval %(
85
+ def #{attribute}_for_#{value}?
86
+ self.#{attribute}?(:#{value})
87
+ end
88
+ )
89
+ end
90
+ model.class_eval %(
91
+ def #{attribute}?(*values)
92
+ if !values.blank?
93
+ values.all? do |value|
94
+ self.#{attribute}.include?(value)
95
+ end
96
+ else
97
+ self.#{attribute}.present?
98
+ end
99
+ end
100
+ )
101
+ end
102
+
103
+ def create_named_scopes_on(model)
104
+ model.class_eval %(
105
+ named_scope :with_#{attribute},
106
+ proc { |*values|
107
+ if values.blank?
108
+ {:conditions => '#{attribute} > 0 OR #{attribute} IS NOT NULL'}
109
+ else
110
+ sets = values.map do |value|
111
+ mask = #{model}.bitmask_for_#{attribute}(value)
112
+ "#{attribute} & \#{mask} <> 0"
113
+ end
114
+ {:conditions => sets.join(' AND ')}
115
+ end
116
+ }
117
+ named_scope :without_#{attribute}, :conditions => "#{attribute} == 0 OR #{attribute} IS NULL"
118
+ named_scope :no_#{attribute}, :conditions => "#{attribute} == 0 OR #{attribute} IS NULL"
119
+ )
120
+ values.each do |value|
121
+ model.class_eval %(
122
+ named_scope :#{attribute}_for_#{value},
123
+ :conditions => ['#{attribute} & ? <> 0', #{model}.bitmask_for_#{attribute}(:#{value})]
124
+ )
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ def self.included(model)
131
+ model.extend ClassMethods
132
+ end
133
+
134
+ module ClassMethods
135
+
136
+ def bitmask(attribute, options={}, &extension)
137
+ unless options[:as] && options[:as].kind_of?(Array)
138
+ raise ArgumentError, "Must provide an Array :as option"
139
+ end
140
+ bitmask_definitions[attribute] = BitmaskAttribute::Definition.new(attribute, options[:as].to_a, &extension)
141
+ bitmask_definitions[attribute].install_on(self)
142
+ end
143
+
144
+ def bitmask_definitions
145
+ @bitmask_definitions ||= {}
146
+ end
147
+
148
+ def bitmasks
149
+ @bitmasks ||= {}
150
+ end
151
+
152
+ end
153
+
154
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ ActiveRecord::Base.instance_eval do
2
+ include BitmaskAttribute
3
+ end
@@ -0,0 +1,222 @@
1
+ require 'test_helper'
2
+
3
+ class BitmaskAttributeTest < Test::Unit::TestCase
4
+
5
+ context "Campaign" do
6
+
7
+ teardown do
8
+ Company.destroy_all
9
+ Campaign.destroy_all
10
+ end
11
+
12
+ should "can assign single value to bitmask" do
13
+ assert_stored Campaign.new(:medium => :web), :web
14
+ end
15
+
16
+ should "can assign multiple values to bitmask" do
17
+ assert_stored Campaign.new(:medium => [:web, :print]), :web, :print
18
+ end
19
+
20
+ should "can add single value to bitmask" do
21
+ campaign = Campaign.new(:medium => [:web, :print])
22
+ assert_stored campaign, :web, :print
23
+ campaign.medium << :phone
24
+ assert_stored campaign, :web, :print, :phone
25
+ end
26
+
27
+ should "ignores duplicate values added to bitmask" do
28
+ campaign = Campaign.new(:medium => [:web, :print])
29
+ assert_stored campaign, :web, :print
30
+ campaign.medium << :phone
31
+ assert_stored campaign, :web, :print, :phone
32
+ campaign.medium << :phone
33
+ assert_stored campaign, :web, :print, :phone
34
+ assert_equal 1, campaign.medium.select { |value| value == :phone }.size
35
+ end
36
+
37
+ should "can assign new values at once to bitmask" do
38
+ campaign = Campaign.new(:medium => [:web, :print])
39
+ assert_stored campaign, :web, :print
40
+ campaign.medium = [:phone, :email]
41
+ assert_stored campaign, :phone, :email
42
+ end
43
+
44
+ should "can save bitmask to db and retrieve values transparently" do
45
+ campaign = Campaign.new(:medium => [:web, :print])
46
+ assert_stored campaign, :web, :print
47
+ assert campaign.save
48
+ assert_stored Campaign.find(campaign.id), :web, :print
49
+ end
50
+
51
+ should "can add custom behavor to value proxies during bitmask definition" do
52
+ campaign = Campaign.new(:medium => [:web, :print])
53
+ assert_raises NoMethodError do
54
+ campaign.medium.worked?
55
+ end
56
+ assert_nothing_raised do
57
+ campaign.misc.worked?
58
+ end
59
+ assert campaign.misc.worked?
60
+ end
61
+
62
+ should "cannot use unsupported values" do
63
+ assert_unsupported { Campaign.new(:medium => [:web, :print, :this_will_fail]) }
64
+ campaign = Campaign.new(:medium => :web)
65
+ assert_unsupported { campaign.medium << :this_will_fail_also }
66
+ assert_unsupported { campaign.medium = [:so_will_this] }
67
+ end
68
+
69
+ should "can determine bitmasks using convenience method" do
70
+ assert Campaign.bitmask_for_medium(:web, :print)
71
+ assert_equal(
72
+ Campaign.bitmasks[:medium][:web] | Campaign.bitmasks[:medium][:print],
73
+ Campaign.bitmask_for_medium(:web, :print)
74
+ )
75
+ end
76
+
77
+ should "assert use of unknown value in convenience method will result in exception" do
78
+ assert_unsupported { Campaign.bitmask_for_medium(:web, :and_this_isnt_valid) }
79
+ end
80
+
81
+ should "hash of values is with indifferent access" do
82
+ string_bit = nil
83
+ assert_nothing_raised do
84
+ assert (string_bit = Campaign.bitmask_for_medium('web', 'print'))
85
+ end
86
+ assert_equal Campaign.bitmask_for_medium(:web, :print), string_bit
87
+ end
88
+
89
+ should "save bitmask with non-standard attribute names" do
90
+ campaign = Campaign.new(:Legacy => [:upper, :case])
91
+ assert campaign.save
92
+ assert_equal [:upper, :case], Campaign.find(campaign.id).Legacy
93
+ end
94
+
95
+ should "ignore blanks fed as values" do
96
+ campaign = Campaign.new(:medium => [:web, :print, ''])
97
+ assert_stored campaign, :web, :print
98
+ end
99
+
100
+ should "convert values passed as strings to symbols" do
101
+ campaign = Campaign.new
102
+ campaign.medium << "web"
103
+ assert_equal [:web], campaign.medium
104
+ end
105
+
106
+ context "checking" do
107
+
108
+ setup { @campaign = Campaign.new(:medium => [:web, :print]) }
109
+
110
+ context "for a single value" do
111
+
112
+ should "be supported by an attribute_for_value convenience method" do
113
+ assert @campaign.medium_for_web?
114
+ assert @campaign.medium_for_print?
115
+ assert !@campaign.medium_for_email?
116
+ end
117
+
118
+ should "be supported by the simple predicate method" do
119
+ assert @campaign.medium?(:web)
120
+ assert @campaign.medium?(:print)
121
+ assert !@campaign.medium?(:email)
122
+ end
123
+
124
+ end
125
+
126
+ context "for multiple values" do
127
+
128
+ should "be supported by the simple predicate method" do
129
+ assert @campaign.medium?(:web, :print)
130
+ assert !@campaign.medium?(:web, :email)
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+
137
+ context "named scopes" do
138
+
139
+ setup do
140
+ @company = Company.create(:name => "Test Co, Intl.")
141
+ @campaign1 = @company.campaigns.create :medium => [:web, :print]
142
+ @campaign2 = @company.campaigns.create
143
+ @campaign3 = @company.campaigns.create :medium => [:web, :email]
144
+ end
145
+
146
+ should "support retrieval by any value" do
147
+ assert_equal [@campaign1, @campaign3], @company.campaigns.with_medium
148
+ end
149
+
150
+ should "support retrieval by one matching value" do
151
+ assert_equal [@campaign1], @company.campaigns.with_medium(:print)
152
+ end
153
+
154
+ should "support retrieval by all matching values" do
155
+ assert_equal [@campaign1], @company.campaigns.with_medium(:web, :print)
156
+ assert_equal [@campaign3], @company.campaigns.with_medium(:web, :email)
157
+ end
158
+
159
+ should "support retrieval for no values" do
160
+ assert_equal [@campaign2], @company.campaigns.without_medium
161
+ end
162
+
163
+ end
164
+
165
+ should "can check if at least one value is set" do
166
+ campaign = Campaign.new(:medium => [:web, :print])
167
+
168
+ assert campaign.medium?
169
+
170
+ campaign = Campaign.new
171
+
172
+ assert !campaign.medium?
173
+ end
174
+
175
+ should "find by bitmask values" do
176
+ campaign = Campaign.new(:medium => [:web, :print])
177
+ assert campaign.save
178
+
179
+ assert_equal(
180
+ Campaign.find(:all, :conditions => ['medium & ? <> 0', Campaign.bitmask_for_medium(:print)]),
181
+ Campaign.medium_for_print
182
+ )
183
+
184
+ assert_equal Campaign.medium_for_print, Campaign.medium_for_print.medium_for_web
185
+
186
+ assert_equal [], Campaign.medium_for_email
187
+ assert_equal [], Campaign.medium_for_web.medium_for_email
188
+ end
189
+
190
+ should "find no values" do
191
+ campaign = Campaign.create(:medium => [:web, :print])
192
+ assert campaign.save
193
+
194
+ assert_equal [], Campaign.no_medium
195
+
196
+ campaign.medium = []
197
+ assert campaign.save
198
+
199
+ assert_equal [campaign], Campaign.no_medium
200
+ end
201
+
202
+ #######
203
+ private
204
+ #######
205
+
206
+ def assert_unsupported(&block)
207
+ assert_raises(ArgumentError, &block)
208
+ end
209
+
210
+ def assert_stored(record, *values)
211
+ values.each do |value|
212
+ assert record.medium.any? { |v| v.to_s == value.to_s }, "Values #{record.medium.inspect} does not include #{value.inspect}"
213
+ end
214
+ full_mask = values.inject(0) do |mask, value|
215
+ mask | Campaign.bitmasks[:medium][value]
216
+ end
217
+ assert_equal full_mask, record.medium.to_i
218
+ end
219
+
220
+ end
221
+
222
+ end
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ begin
5
+ require 'redgreen'
6
+ rescue LoadError
7
+ end
8
+
9
+ require 'active_support'
10
+ require 'active_record'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'bitmask-attribute'
15
+ require File.dirname(__FILE__) + '/../rails/init'
16
+
17
+ # ActiveRecord::Base.logger = Logger.new(STDOUT)
18
+
19
+ ActiveRecord::Base.establish_connection(
20
+ :adapter => 'sqlite3',
21
+ :database => ':memory:'
22
+ )
23
+
24
+ ActiveRecord::Schema.define do
25
+ create_table :campaigns do |t|
26
+ t.integer :company_id
27
+ t.integer :medium, :misc, :Legacy
28
+ end
29
+ create_table :companies do |t|
30
+ t.string :name
31
+ end
32
+ end
33
+
34
+ class Company < ActiveRecord::Base
35
+ has_many :campaigns
36
+ end
37
+
38
+ # Pseudo model for testing purposes
39
+ class Campaign < ActiveRecord::Base
40
+ belongs_to :company
41
+ bitmask :medium, :as => [:web, :print, :email, :phone]
42
+ bitmask :misc, :as => %w(some useless values) do
43
+ def worked?
44
+ true
45
+ end
46
+ end
47
+ bitmask :Legacy, :as => [:upper, :case]
48
+ end
49
+
50
+ class Test::Unit::TestCase
51
+
52
+ def assert_unsupported(&block)
53
+ assert_raises(ArgumentError, &block)
54
+ end
55
+
56
+ def assert_stored(record, *values)
57
+ values.each do |value|
58
+ assert record.medium.any? { |v| v.to_s == value.to_s }, "Values #{record.medium.inspect} does not include #{value.inspect}"
59
+ end
60
+ full_mask = values.inject(0) do |mask, value|
61
+ mask | Campaign.bitmasks[:medium][value]
62
+ end
63
+ assert_equal full_mask, record.medium.to_i
64
+ end
65
+
66
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: r3trofitted-bitmask-attribute
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ - 0
9
+ version: 1.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Bruce Williams
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-12 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description:
33
+ email: bruce@codefluency.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - LICENSE
40
+ - README.markdown
41
+ files:
42
+ - .document
43
+ - .gitignore
44
+ - LICENSE
45
+ - README.markdown
46
+ - Rakefile
47
+ - VERSION
48
+ - lib/bitmask-attribute.rb
49
+ - lib/bitmask_attribute.rb
50
+ - lib/bitmask_attribute/value_proxy.rb
51
+ - rails/init.rb
52
+ - test/bitmask_attribute_test.rb
53
+ - test/test_helper.rb
54
+ has_rdoc: true
55
+ homepage: http://github.com/bruce/bitmask-attribute
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options:
60
+ - --charset=UTF-8
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.3.6
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Simple bitmask attribute support for ActiveRecord
84
+ test_files:
85
+ - test/bitmask_attribute_test.rb
86
+ - test/test_helper.rb