From 2ec24c82911f436a9c229b6e99172a4ba33b881a Mon Sep 17 00:00:00 2001 From: spemmons Date: Mon, 16 Apr 2012 07:38:23 -0500 Subject: [PATCH] add :zero option and tests --- lib/bitmask_attributes.rb | 2 +- lib/bitmask_attributes/definition.rb | 20 ++++++++++++-------- test/bitmask_attributes_test.rb | 18 ++++++++++++++++++ test/support/models.rb | 6 ++++-- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/lib/bitmask_attributes.rb b/lib/bitmask_attributes.rb index 9c9fdf9..1190d6f 100644 --- a/lib/bitmask_attributes.rb +++ b/lib/bitmask_attributes.rb @@ -9,7 +9,7 @@ def bitmask(attribute, options={}, &extension) unless options[:as] && options[:as].kind_of?(Array) raise ArgumentError, "Must provide an Array :as option" end - bitmask_definitions[attribute] = Definition.new(attribute, options[:as].to_a,options[:null].nil? || options[:null], &extension) + bitmask_definitions[attribute] = Definition.new(attribute, options[:as].to_a,options[:null].nil? || options[:null],options[:zero],&extension) bitmask_definitions[attribute].install_on(self) end diff --git a/lib/bitmask_attributes/definition.rb b/lib/bitmask_attributes/definition.rb index 34dce58..d7c8e21 100644 --- a/lib/bitmask_attributes/definition.rb +++ b/lib/bitmask_attributes/definition.rb @@ -1,12 +1,13 @@ module BitmaskAttributes class Definition - attr_reader :attribute, :values, :allow_null, :extension + attr_reader :attribute, :values, :allow_null, :zero_value, :extension - def initialize(attribute, values=[],allow_null = true, &extension) + def initialize(attribute, values=[],allow_null = true,zero_value = nil, &extension) @attribute = attribute @values = values @extension = extension @allow_null = allow_null + @zero_value = zero_value end def install_on(model) @@ -57,7 +58,7 @@ def override_setter_on(model) model.class_eval %( def #{attribute}=(raw_value) values = raw_value.kind_of?(Array) ? raw_value : [raw_value] - self.#{attribute}.replace(values.reject(&:blank?)) + self.#{attribute}.replace(values.reject{|value| #{eval_string_for_zero('value')}}) end ) end @@ -75,7 +76,9 @@ def create_convenience_class_method_on(model) model.class_eval %( def self.bitmask_for_#{attribute}(*values) values.inject(0) do |bitmask, value| - unless (bit = bitmasks[:#{attribute}][value]) + if #{eval_string_for_zero('value')} + bit = 0 + elsif (bit = bitmasks[:#{attribute}][value]).nil? raise ArgumentError, "Unsupported value for #{attribute}: \#{value.inspect}" end bitmask | bit @@ -106,10 +109,7 @@ def #{attribute}?(*values) end def create_scopes_on(model) - if allow_null - or_is_null_condition = " OR #{attribute} IS NULL" - or_is_not_null_condition = " OR #{attribute} IS NOT NULL" - end + or_is_null_condition = " OR #{attribute} IS NULL" if allow_null model.class_eval %( scope :with_#{attribute}, @@ -160,5 +160,9 @@ def create_scopes_on(model) ) end end + + def eval_string_for_zero(value_string) + zero_value ? "#{value_string}.blank? || #{value_string} == :#{zero_value}" : "#{value_string}.blank?" + end end end diff --git a/test/bitmask_attributes_test.rb b/test/bitmask_attributes_test.rb index 2ff290a..ad82d07 100644 --- a/test/bitmask_attributes_test.rb +++ b/test/bitmask_attributes_test.rb @@ -105,6 +105,7 @@ def self.context_with_classes(label,campaign_class,company_class) end should "ignore blanks fed as values" do + assert_equal 0b11,@campaign_class.bitmask_for_medium(:web, :print, '') campaign = @campaign_class.new(:medium => [:web, :print, '']) assert_stored campaign, :web, :print end @@ -232,6 +233,23 @@ def self.context_with_classes(label,campaign_class,company_class) assert_equal [campaign], @campaign_class.no_medium end + should "allow zero in values without changing result" do + assert_equal 0,@campaign_class.bitmask_for_allow_zero(:none) + assert_equal 0b111,@campaign_class.bitmask_for_allow_zero(:one,:two,:three,:none) + + campaign = @campaign_class.new(:allow_zero => :none) + assert campaign.save + assert_equal [],campaign.allow_zero + + campaign.allow_zero = :none + assert campaign.save + assert_equal [],campaign.allow_zero + + campaign.allow_zero = [:one,:none] + assert campaign.save + assert_equal [:one],campaign.allow_zero + end + private diff --git a/test/support/models.rb b/test/support/models.rb index 19d4053..a7d950b 100644 --- a/test/support/models.rb +++ b/test/support/models.rb @@ -1,14 +1,14 @@ ActiveRecord::Schema.define do create_table :campaign_with_nulls do |t| t.integer :company_id - t.integer :medium, :misc, :Legacy + t.integer :medium, :allow_zero, :misc, :Legacy end create_table :company_with_nulls do |t| t.string :name end create_table :campaign_without_nulls do |t| t.integer :company_id - t.integer :medium, :misc, :Legacy, :null => false, :default => 0 + t.integer :medium, :allow_zero, :misc, :Legacy, :null => false, :default => 0 end create_table :company_without_nulls do |t| t.string :name @@ -24,6 +24,7 @@ class CompanyWithNull < ActiveRecord::Base class CampaignWithNull < ActiveRecord::Base belongs_to :company,:class_name => 'CompanyWithNull' bitmask :medium, :as => [:web, :print, :email, :phone] + bitmask :allow_zero, :as => [:one, :two, :three], :zero => :none bitmask :misc, :as => %w(some useless values) do def worked? true @@ -39,6 +40,7 @@ class CompanyWithoutNull < ActiveRecord::Base class CampaignWithoutNull < ActiveRecord::Base belongs_to :company,:class_name => 'CompanyWithoutNull' bitmask :medium, :as => [:web, :print, :email, :phone], :null => false + bitmask :allow_zero, :as => [:one, :two, :three], :zero => :none, :null => false bitmask :misc, :as => %w(some useless values), :null => false do def worked? true