Skip to content

Commit

Permalink
Merge pull request joelmoss#13 from spemmons/master
Browse files Browse the repository at this point in the history
"without_" scope extension, fix bad handling of 0 raised by zykadelic, fix global scope issue raised by buffpojken, DRY-up scopes, added tests, and BONUS Travis-CI config!
  • Loading branch information
joelmoss committed Apr 2, 2012
2 parents 1417739 + 10be48b commit 1a9415e
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 40 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
@@ -0,0 +1,4 @@
script: 'bundle exec rake test'
language: ruby
rvm:
- 1.9.3
7 changes: 5 additions & 2 deletions README.rdoc
Expand Up @@ -83,12 +83,15 @@ Find records without any bitmask set:
User.no_roles
# => (all users without a role)

Find records without a specific attribute.
Find records without specific attributes:

User.without_roles(:editor)
# => (all users who are not editors)

Note that "without_" only supports a single attribute argument, and the "no_" method does not support arguments.
User.without_roles(:writer, :editor)
# => (all users who are NEITHER writers nor editors)

Note that "without_" supports one or more attribute arguments, and the "no_" method does not support arguments.
And "with_exact_" without arguments is alias for "no_"


Expand Down
27 changes: 12 additions & 15 deletions lib/bitmask_attributes/definition.rb
Expand Up @@ -115,32 +115,30 @@ def create_scopes_on(model)
scope :with_#{attribute},
proc { |*values|
if values.blank?
where('#{attribute} > 0#{or_is_not_null_condition}')
where('#{attribute} > 0')
else
sets = values.map do |value|
mask = #{model}.bitmask_for_#{attribute}(value)
mask = ::#{model}.bitmask_for_#{attribute}(value)
"#{attribute} & \#{mask} <> 0"
end
where(sets.join(' AND '))
end
}
scope :without_#{attribute},
proc { |value|
if value
mask = #{model}.bitmask_for_#{attribute}(value)
where("#{attribute} & ? = 0#{or_is_null_condition}", mask)
proc { |*values|
if values.blank?
no_#{attribute}
else
where("#{attribute} = 0#{or_is_null_condition}")
end
}
where("#{attribute} & ? = 0#{or_is_null_condition}", ::#{model}.bitmask_for_#{attribute}(*values))
end
}
scope :with_exact_#{attribute},
proc { | *values|
if values.blank?
no_#{attribute}
else
mask = values.inject(0) {|sum, value| sum | #{model}.bitmask_for_#{attribute}(value) }
where("#{attribute} = ?", mask)
where("#{attribute} = ?", ::#{model}.bitmask_for_#{attribute}(*values))
end
}
Expand All @@ -149,17 +147,16 @@ def create_scopes_on(model)
scope :with_any_#{attribute},
proc { |*values|
if values.blank?
where('#{attribute} > 0#{or_is_not_null_condition}')
where('#{attribute} > 0')
else
mask = values.inject(0){|sum,value| sum + #{model}.bitmask_for_#{attribute}(value)}
where("#{attribute} & \#{mask} <> 0")
where("#{attribute} & ? <> 0", ::#{model}.bitmask_for_#{attribute}(*values))
end
}
)
values.each do |value|
model.class_eval %(
scope :#{attribute}_for_#{value},
proc { where('#{attribute} & ? <> 0', #{model}.bitmask_for_#{attribute}(:#{value})) }
proc { where('#{attribute} & ? <> 0', ::#{model}.bitmask_for_#{attribute}(:#{value})) }
)
end
end
Expand Down
33 changes: 27 additions & 6 deletions test/bitmask_attributes_test.rb
Expand Up @@ -141,23 +141,26 @@ def self.context_with_classes(label,campaign_class,company_class)
@campaign2 = @company.campaigns.create
@campaign3 = @company.campaigns.create :medium => [:web, :email]
@campaign4 = @company.campaigns.create :medium => [:web]
@campaign5 = @company.campaigns.create :medium => [:web, :print, :email]
@campaign6 = @company.campaigns.create :medium => [:web, :print, :email, :phone]
@campaign7 = @company.campaigns.create :medium => [:email, :phone]
end

should "support retrieval by any value" do
assert_equal [@campaign1, @campaign3, @campaign4], @company.campaigns.with_medium
assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
end

should "support retrieval by one matching value" do
assert_equal [@campaign1], @company.campaigns.with_medium(:print)
assert_equal [@campaign1, @campaign5, @campaign6], @company.campaigns.with_medium(:print)
end

should "support retrieval by any matching value (OR)" do
assert_equal [@campaign1, @campaign3], @company.campaigns.with_any_medium(:print, :email)
assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_any_medium(:print, :email)
end

should "support retrieval by all matching values" do
assert_equal [@campaign1], @company.campaigns.with_medium(:web, :print)
assert_equal [@campaign3], @company.campaigns.with_medium(:web, :email)
assert_equal [@campaign1, @campaign5, @campaign6], @company.campaigns.with_medium(:web, :print)
assert_equal [@campaign3, @campaign5, @campaign6], @company.campaigns.with_medium(:web, :email)
end

should "support retrieval for no values" do
Expand All @@ -166,14 +169,32 @@ def self.context_with_classes(label,campaign_class,company_class)
end

should "support retrieval without a specific value" do
assert_equal [@campaign2, @campaign3, @campaign4], @company.campaigns.without_medium(:print)
assert_equal [@campaign2, @campaign3, @campaign4, @campaign7], @company.campaigns.without_medium(:print)
assert_equal [@campaign2, @campaign7], @company.campaigns.without_medium(:web, :print)
assert_equal [@campaign2, @campaign3, @campaign4], @company.campaigns.without_medium(:print, :phone)
end

should "support retrieval by exact value" do
assert_equal [@campaign4], @company.campaigns.with_exact_medium(:web)
assert_equal [@campaign1], @company.campaigns.with_exact_medium(:web, :print)
assert_equal [@campaign2], @company.campaigns.with_exact_medium
end

should "not retrieve retrieve a subsequent zero value for an unqualified with scope " do
assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
@campaign4.medium = []
@campaign4.save
assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_any_medium
end

should "not retrieve retrieve a subsequent zero value for a qualified with scope " do
assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6], @company.campaigns.with_medium(:web)
@campaign4.medium = []
@campaign4.save
assert_equal [@campaign1, @campaign3, @campaign5, @campaign6], @company.campaigns.with_medium(:web)
assert_equal [@campaign1, @campaign3, @campaign5, @campaign6], @company.campaigns.with_any_medium(:web)
end
end

should "can check if at least one value is set" do
Expand Down
17 changes: 0 additions & 17 deletions test/support/helpers.rb

This file was deleted.

0 comments on commit 1a9415e

Please sign in to comment.