bitmasker 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -16,6 +16,10 @@ Synopsis
16
16
  end
17
17
  ```
18
18
 
19
+ [![Code Climate](https://codeclimate.com/github/amiel/bitmasker.png)](https://codeclimate.com/github/amiel/bitmasker)
20
+ [![Build Status](https://travis-ci.org/amiel/bitmasker.png)](https://travis-ci.org/amiel/bitmasker)
21
+
22
+
19
23
  Examples
20
24
  --------
21
25
 
@@ -34,7 +38,8 @@ Examples
34
38
  end
35
39
  ```
36
40
 
37
- this will define the following methods:
41
+ This will define the following methods:
42
+
38
43
  * `User#notifications` -- returns a BitmaskAttributes object representing all values
39
44
  * `User#send_weekly_newsletter?` -- predicate
40
45
  * `User#send_weekly_newsletter` -- works just like the predicate, makes it easy to use actionview form helpers
@@ -43,8 +48,28 @@ this will define the following methods:
43
48
  * `User#send_monthly_newsletter`
44
49
  * `User#send_monthly_newsletter=(value)`
45
50
 
46
- the call to `config.accessible` calls `attr_accessible :send_weekly_newsletter, :send_monthly_newsletter` in your model
51
+ the call to `config.accessible` calls `attr_accessible :send_weekly_newsletter, :send_monthly_newsletter` in your model.
52
+
53
+ ### Scopes
54
+
55
+ Bitmasker also sets up a few useful scopes:
47
56
 
57
+ * `User#with_notifications`
58
+ * `User#without_notifications`
59
+ * `User#with_any_notifications`
60
+
61
+ #### Scopes Examples
62
+
63
+ ```ruby
64
+ # Users that want weekly newsletter
65
+ User.with_notifications(:send_weekly_newsletter)
66
+
67
+ # Users that want monthly AND weekly newsletters
68
+ User.with_notifications(:send_monthly_newsletter, :send_weekly_newsletter)
69
+
70
+ # Users that want monthly OR weekly newsletters
71
+ User.with_any_notifications(:send_monthly_newsletter, :send_weekly_newsletter)
72
+ ```
48
73
 
49
74
 
50
75
  View Example
@@ -79,5 +104,37 @@ if you are using attr_accessible in your model and you want to mass-assign your
79
104
  * `name` name of the field name in the database where all this info is stored, should be an integer
80
105
 
81
106
 
107
+ Updating from `has_bitmask_attributes`
108
+ --------------------------------------
109
+
110
+ If you used the `method_format` feature from `has_bitmask_attributes`, you will need to change
111
+ your configuration as `method_format` has been removed.
112
+
113
+ ### Before
114
+
115
+ ```ruby
116
+ # in app/models/user.rb
117
+ class User < ActiveRecord::Base
118
+ has_bitmask_attributes :notifications do |config|
119
+ config.attribute :weekly_newsletter, 0b0001
120
+ config.attribute :monthly_newsletter, 0b0010, true
121
+ config.method_format 'send_%s'
122
+ end
123
+ end
124
+ ```
125
+
126
+ ### After
127
+
128
+ ```ruby
129
+ # in app/models/user.rb
130
+ class User < ActiveRecord::Base
131
+ has_bitmask_attributes :notifications do |config|
132
+ config.attribute :send_weekly_newsletter, 0b0001
133
+ config.attribute :send_monthly_newsletter, 0b0010, true
134
+ end
135
+ end
136
+ ```
137
+
138
+
82
139
  Copyright (c) 2012 Amiel Martin, released under the MIT license
83
140
 
@@ -0,0 +1,61 @@
1
+ module Bitmasker
2
+ class BitmaskScope
3
+ include ActiveModel::AttributeMethods
4
+ attribute_method_prefix 'with_'
5
+ attribute_method_prefix 'with_any_'
6
+ attribute_method_prefix 'without_'
7
+
8
+ class_attribute :model_class
9
+ class_attribute :field_name
10
+ class_attribute :mask_name
11
+ class_attribute :bitmask_attributes
12
+
13
+ def self.make(model_class, field_name, mask_name, bitmask_attributes)
14
+ klass = Class.new(self) do
15
+ define_attribute_methods [mask_name]
16
+
17
+ def self.to_s
18
+ "#{superclass}(#{model_class}##{field_name})"
19
+ end
20
+ end
21
+
22
+ klass.model_class = model_class
23
+ klass.field_name = field_name
24
+ klass.mask_name = mask_name
25
+ klass.bitmask_attributes = bitmask_attributes.stringify_keys
26
+
27
+ klass
28
+ end
29
+
30
+ def bitmask
31
+ Bitmask.new(bitmask_attributes, 0)
32
+ end
33
+
34
+ # REVIEW: This (the unused _ attribute) tells me I have the design wrong
35
+ def with_attribute(_, *attributes)
36
+ # TODO: Test lots of databases
37
+ bitmask_query attributes, "#{field_name} & :mask = :mask"
38
+ end
39
+
40
+ def with_any_attribute(_, *attributes)
41
+ # TODO: Test lots of databases
42
+ bitmask_query attributes, "#{field_name} & :mask <> 0"
43
+ end
44
+
45
+ def without_attribute(_, *attributes)
46
+ # TODO: Test lots of databases
47
+ bitmask_query attributes, "#{field_name} & :mask = 0 OR #{field_name} IS NULL"
48
+ end
49
+
50
+ private
51
+
52
+ def bitmask_query(attributes, query)
53
+ mask = bitmask
54
+ mask.set_array(Array.wrap(attributes).flatten.map(&:to_s))
55
+
56
+ # TODO: Test lots of databases
57
+ model_class.where(query, mask: mask.to_i)
58
+ end
59
+
60
+ end
61
+ end
@@ -8,6 +8,8 @@ module Bitmasker
8
8
  @mask_name = mask_name
9
9
  @field_name = mask_name.to_s + '_mask'
10
10
 
11
+ @scope_name = mask_name.to_s + '_scope'
12
+
11
13
  @use_attr_accessible = false
12
14
  end
13
15
 
@@ -33,14 +35,22 @@ module Bitmasker
33
35
 
34
36
  def generate
35
37
  klass = BitmaskAttributes.make(@model, @field_name, @bitmask_attributes, @bitmask_defaults)
38
+ scope_klass = BitmaskScope.make(@model, @field_name, @mask_name, @bitmask_attributes)
36
39
 
37
40
  @model.send :define_method, @mask_name do
38
41
  klass.new(self)
39
42
  end
40
43
 
44
+ @model.singleton_class.send :define_method, @scope_name do
45
+ scope_klass.new
46
+ end
47
+
48
+ @model.singleton_class.delegate "with_#{@mask_name}",
49
+ "without_#{@mask_name}", "with_any_#{@mask_name}",
50
+ to: @scope_name
51
+
41
52
  @bitmask_attributes.each do |attribute, mask|
42
- @model.delegate attribute, "#{attribute}?", "#{attribute}=",
43
- "#{attribute}_was",
53
+ @model.delegate attribute, "#{attribute}?", "#{attribute}=", "#{attribute}_was",
44
54
  to: @mask_name
45
55
 
46
56
  @model.attr_accessible attribute if @use_attr_accessible
@@ -1,3 +1,3 @@
1
1
  module Bitmasker
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/bitmasker.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'bitmask'
2
2
  require 'bitmasker/model'
3
3
  require 'bitmasker/bitmask_attributes'
4
+ require 'bitmasker/bitmask_scope'
4
5
  require 'bitmasker/generator'
5
6
 
6
7
  require 'bitmasker/rails' if defined? ::Rails
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class Bitmasker::BitmaskAttributesTest < MiniTest::Unit::TestCase
3
+ class Bitmasker::BitmaskAttributesTest < MiniTest::Test
4
4
 
5
5
  MockModel = Class.new do
6
6
  def self.value_to_boolean(value)
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ class Bitmasker::BitmaskScopeTest < MiniTest::Test
4
+
5
+ MockModel = Class.new
6
+
7
+ def model_instance
8
+ @model_instance ||= MockModel.new
9
+ end
10
+
11
+ def setup
12
+ @klass = Bitmasker::BitmaskScope.make(
13
+ MockModel, 'email_mask', 'emails',
14
+ send_weekly_email: 0b0001,
15
+ send_monthly_newsletter: 0b0010,
16
+ send_daily_spam: 0b0100,
17
+ )
18
+ end
19
+
20
+ def subject
21
+ @subject ||= @klass.new
22
+ end
23
+
24
+ def test_klass_to_s
25
+ assert_equal "Bitmasker::BitmaskScope(Bitmasker::BitmaskScopeTest::MockModel#email_mask)", @klass.to_s
26
+ end
27
+
28
+
29
+ def test_with_attribute
30
+ MockModel.expects(:where).with("email_mask & :mask = :mask", mask: 1)
31
+ subject.with_emails(:send_weekly_email)
32
+ end
33
+
34
+ def test_with_attributes_array
35
+ MockModel.expects(:where).with("email_mask & :mask = :mask", mask: 6)
36
+ subject.with_emails([:send_monthly_newsletter, :send_daily_spam])
37
+ end
38
+
39
+ def test_with_attributes
40
+ MockModel.expects(:where).with("email_mask & :mask = :mask", mask: 6)
41
+ subject.with_emails(:send_monthly_newsletter, :send_daily_spam)
42
+ end
43
+
44
+ def test_without_attribute
45
+ MockModel.expects(:where).with("email_mask & :mask = 0 OR email_mask IS NULL", mask: 2)
46
+ subject.without_emails(:send_monthly_newsletter)
47
+ end
48
+
49
+ def test_with_any_attribute
50
+ MockModel.expects(:where).with("email_mask & :mask <> 0", mask: 3)
51
+ subject.with_any_emails([:send_weekly_email, :send_monthly_newsletter])
52
+ end
53
+ end
@@ -41,7 +41,7 @@ class MockModel
41
41
  end
42
42
 
43
43
 
44
- class BitmaskAttributesTest < MiniTest::Unit::TestCase
44
+ class BitmaskAttributesTest < MiniTest::Test
45
45
 
46
46
  def test_does_stuff_attribute
47
47
  mock = MockModel.new
data/test/test_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'minitest/autorun'
2
- require 'turn/autorun'
2
+ # require 'turn/autorun'
3
3
 
4
4
  require 'mocha/setup'
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitmasker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-21 00:00:00.000000000 Z
12
+ date: 2013-10-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bitmask
@@ -100,6 +100,7 @@ extensions: []
100
100
  extra_rdoc_files: []
101
101
  files:
102
102
  - lib/bitmasker/bitmask_attributes.rb
103
+ - lib/bitmasker/bitmask_scope.rb
103
104
  - lib/bitmasker/generator.rb
104
105
  - lib/bitmasker/model.rb
105
106
  - lib/bitmasker/rails.rb
@@ -109,6 +110,7 @@ files:
109
110
  - Rakefile
110
111
  - README.md
111
112
  - test/bitmasker/bitmask_attributes_test.rb
113
+ - test/bitmasker/bitmask_scope_test.rb
112
114
  - test/integration_test.rb
113
115
  - test/test_helper.rb
114
116
  homepage: https://github.com/amiel/bitmasker
@@ -123,20 +125,27 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
125
  - - ! '>='
124
126
  - !ruby/object:Gem::Version
125
127
  version: '0'
128
+ segments:
129
+ - 0
130
+ hash: -2321849182877328955
126
131
  required_rubygems_version: !ruby/object:Gem::Requirement
127
132
  none: false
128
133
  requirements:
129
134
  - - ! '>='
130
135
  - !ruby/object:Gem::Version
131
136
  version: '0'
137
+ segments:
138
+ - 0
139
+ hash: -2321849182877328955
132
140
  requirements: []
133
141
  rubyforge_project:
134
- rubygems_version: 1.8.23
142
+ rubygems_version: 1.8.24
135
143
  signing_key:
136
144
  specification_version: 3
137
145
  summary: Bitmasker allows you to store many boolean values as one integer field in
138
146
  the database.
139
147
  test_files:
140
148
  - test/bitmasker/bitmask_attributes_test.rb
149
+ - test/bitmasker/bitmask_scope_test.rb
141
150
  - test/integration_test.rb
142
151
  - test/test_helper.rb