bitmask_attributes 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.
- data/.gitignore +2 -1
 - data/.travis.yml +4 -0
 - data/CHANGELOG.rdoc +59 -6
 - data/Gemfile +2 -6
 - data/Gemfile.lock +17 -17
 - data/README.rdoc +62 -2
 - data/lib/bitmask_attributes.rb +1 -1
 - data/lib/bitmask_attributes/definition.rb +40 -26
 - data/lib/bitmask_attributes/version.rb +1 -1
 - data/test/bitmask_attributes_test.rb +231 -175
 - data/test/support/models.rb +32 -8
 - metadata +11 -7
 - data/test/support/helpers.rb +0 -17
 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/CHANGELOG.rdoc
    CHANGED
    
    | 
         @@ -1,14 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            === Version 0.3.0 - 2012-04-30 21:36:18 +0100
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Aaron Hamid (1):
         
     | 
| 
      
 4 
     | 
    
         
            +
            * wrap two scopes in procs to fix migration/startup issues
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Andre Duffeck (1):
         
     | 
| 
      
 7 
     | 
    
         
            +
            * fix values_for
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Ivan Buiko (1):
         
     | 
| 
      
 10 
     | 
    
         
            +
            * Adding retrieval by exact value
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Joel Moss (9):
         
     | 
| 
      
 13 
     | 
    
         
            +
            * Merge pull request #6 from incandescent/fix-scope-proc
         
     | 
| 
      
 14 
     | 
    
         
            +
            * Merge pull request #4 from SUSE/fix_values_for
         
     | 
| 
      
 15 
     | 
    
         
            +
            * Bundle update
         
     | 
| 
      
 16 
     | 
    
         
            +
            * Adding retrieval by exact value
         
     | 
| 
      
 17 
     | 
    
         
            +
            * Merge branch 'retrieval-by-exact-value'
         
     | 
| 
      
 18 
     | 
    
         
            +
            * Resolved merge conflict
         
     | 
| 
      
 19 
     | 
    
         
            +
            * Merge pull request #9 from numerex/master
         
     | 
| 
      
 20 
     | 
    
         
            +
            * Merge pull request #13 from spemmons/master
         
     | 
| 
      
 21 
     | 
    
         
            +
            * Merge pull request #16 from spemmons/master
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            Sebastian Borrazas (1):
         
     | 
| 
      
 24 
     | 
    
         
            +
            * Not raising exception when the bitmask column is not found, since its adding it on a migration
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            spemmons (22):
         
     | 
| 
      
 27 
     | 
    
         
            +
            * detect whether or not nulls are possible with an attribute and remove OR conditions checking if it is null or not
         
     | 
| 
      
 28 
     | 
    
         
            +
            * ignore RubyMine info
         
     | 
| 
      
 29 
     | 
    
         
            +
            * merge changes with joel moss for scopes
         
     | 
| 
      
 30 
     | 
    
         
            +
            * check for model not being ready when creating scopes
         
     | 
| 
      
 31 
     | 
    
         
            +
            * support nulls with an explicit attribute, not by inspecting the model due to preloading issues
         
     | 
| 
      
 32 
     | 
    
         
            +
            * add documentation for the :null option
         
     | 
| 
      
 33 
     | 
    
         
            +
            * support multiple values in the "without_..." scope that excludes match for of any of the bits; previously 2nd and following values were ignored
         
     | 
| 
      
 34 
     | 
    
         
            +
            * update documentation to reflect support for multiple arguments to "without_..."
         
     | 
| 
      
 35 
     | 
    
         
            +
            * update documentation to reflect support for multiple arguments to "without_..."
         
     | 
| 
      
 36 
     | 
    
         
            +
            * update documentation to reflect support for multiple arguments to "without_..."
         
     | 
| 
      
 37 
     | 
    
         
            +
            * added tests to verify the validity of zykadelic's complaint that "with_" scopes were improperly including "OR IS NOT NULL" and fixed the code by removing the condition in this case
         
     | 
| 
      
 38 
     | 
    
         
            +
            * DRY-up scope expressions, standardizing on "no_" and "bitmask_for_...(*values)" instead of repeating more complex calculations; also found another example of zykadelic's complaint with "with_any_" that is fixed and has tests
         
     | 
| 
      
 39 
     | 
    
         
            +
            * add travis configuration file
         
     | 
| 
      
 40 
     | 
    
         
            +
            * follow buffpojken in forcing string-interpolated model to work in global scope
         
     | 
| 
      
 41 
     | 
    
         
            +
            * Merge branch 'master' of github.com:spemmons/bitmask_attributes
         
     | 
| 
      
 42 
     | 
    
         
            +
            * remove out-dated helpers that, although no longer used, were being loaded by Travis-CI and failing
         
     | 
| 
      
 43 
     | 
    
         
            +
            * clarify travis config to fix failing CI build that works locally
         
     | 
| 
      
 44 
     | 
    
         
            +
            * apparently 1.9.2 doesn't work... will figure out why later
         
     | 
| 
      
 45 
     | 
    
         
            +
            * add :zero option and tests
         
     | 
| 
      
 46 
     | 
    
         
            +
            * check for a string match instead of a symbol to allow values arriving from web forms and services to match properly
         
     | 
| 
      
 47 
     | 
    
         
            +
            * added documentation for the :zero attribute
         
     | 
| 
      
 48 
     | 
    
         
            +
            * rename :zero to :zero_value for clarity
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            steve emmons (3):
         
     | 
| 
      
 51 
     | 
    
         
            +
            * Merge pull request #1 from numerex/master
         
     | 
| 
      
 52 
     | 
    
         
            +
            * Merge pull request #2 from numerex/master
         
     | 
| 
      
 53 
     | 
    
         
            +
            * Merge pull request #15 from spemmons/master
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       1 
56 
     | 
    
         
             
            === Version 0.2.4 - 2011-11-23 09:37:50 +0000
         
     | 
| 
       2 
57 
     | 
    
         | 
| 
       3 
58 
     | 
    
         
             
            Ivan Buiko (3):
         
     | 
| 
       4 
     | 
    
         
            -
            *  
     | 
| 
       5 
     | 
    
         
            -
            * latest versions in Gemfile.lock
         
     | 
| 
       6 
     | 
    
         
            -
            * don't validate attribute during creating table
         
     | 
| 
      
 59 
     | 
    
         
            +
            * No longer validates attribute during migrations
         
     | 
| 
       7 
60 
     | 
    
         | 
| 
       8 
61 
     | 
    
         
             
            Joel Moss (3):
         
     | 
| 
       9 
     | 
    
         
            -
            *  
     | 
| 
       10 
     | 
    
         
            -
            *  
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 62 
     | 
    
         
            +
            * Added changeling tasks for help with gem releases
         
     | 
| 
      
 63 
     | 
    
         
            +
            * Created docs using sdoc
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
       12 
65 
     | 
    
         | 
| 
       13 
66 
     | 
    
         | 
| 
       14 
67 
     | 
    
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,40 +1,40 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                bitmask_attributes (0.2. 
     | 
| 
      
 4 
     | 
    
         
            +
                bitmask_attributes (0.2.4)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  activerecord (~> 3.0)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            GEM
         
     | 
| 
       8 
8 
     | 
    
         
             
              remote: http://rubygems.org/
         
     | 
| 
       9 
9 
     | 
    
         
             
              specs:
         
     | 
| 
       10 
     | 
    
         
            -
                activemodel (3. 
     | 
| 
       11 
     | 
    
         
            -
                  activesupport (= 3. 
     | 
| 
      
 10 
     | 
    
         
            +
                activemodel (3.2.2)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  activesupport (= 3.2.2)
         
     | 
| 
       12 
12 
     | 
    
         
             
                  builder (~> 3.0.0)
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
       16 
     | 
    
         
            -
                   
     | 
| 
       17 
     | 
    
         
            -
                  arel (~> 2.2.1)
         
     | 
| 
      
 13 
     | 
    
         
            +
                activerecord (3.2.2)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  activemodel (= 3.2.2)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  activesupport (= 3.2.2)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  arel (~> 3.0.2)
         
     | 
| 
       18 
17 
     | 
    
         
             
                  tzinfo (~> 0.3.29)
         
     | 
| 
       19 
     | 
    
         
            -
                activesupport (3. 
     | 
| 
      
 18 
     | 
    
         
            +
                activesupport (3.2.2)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  i18n (~> 0.6)
         
     | 
| 
       20 
20 
     | 
    
         
             
                  multi_json (~> 1.0)
         
     | 
| 
       21 
     | 
    
         
            -
                ansi (1.4. 
     | 
| 
       22 
     | 
    
         
            -
                arel ( 
     | 
| 
      
 21 
     | 
    
         
            +
                ansi (1.4.2)
         
     | 
| 
      
 22 
     | 
    
         
            +
                arel (3.0.2)
         
     | 
| 
       23 
23 
     | 
    
         
             
                builder (3.0.0)
         
     | 
| 
       24 
24 
     | 
    
         
             
                i18n (0.6.0)
         
     | 
| 
       25 
     | 
    
         
            -
                json (1.6. 
     | 
| 
       26 
     | 
    
         
            -
                multi_json (1.0 
     | 
| 
      
 25 
     | 
    
         
            +
                json (1.6.5)
         
     | 
| 
      
 26 
     | 
    
         
            +
                multi_json (1.1.0)
         
     | 
| 
       27 
27 
     | 
    
         
             
                rake (0.9.2.2)
         
     | 
| 
       28 
     | 
    
         
            -
                rdoc (3. 
     | 
| 
      
 28 
     | 
    
         
            +
                rdoc (3.12)
         
     | 
| 
       29 
29 
     | 
    
         
             
                  json (~> 1.4)
         
     | 
| 
       30 
30 
     | 
    
         
             
                sdoc (0.3.16)
         
     | 
| 
       31 
31 
     | 
    
         
             
                  json (>= 1.1.3)
         
     | 
| 
       32 
32 
     | 
    
         
             
                  rdoc (~> 3.10)
         
     | 
| 
       33 
33 
     | 
    
         
             
                shoulda (2.11.3)
         
     | 
| 
       34 
     | 
    
         
            -
                sqlite3 (1.3. 
     | 
| 
      
 34 
     | 
    
         
            +
                sqlite3 (1.3.5)
         
     | 
| 
       35 
35 
     | 
    
         
             
                turn (0.8.3)
         
     | 
| 
       36 
36 
     | 
    
         
             
                  ansi
         
     | 
| 
       37 
     | 
    
         
            -
                tzinfo (0.3. 
     | 
| 
      
 37 
     | 
    
         
            +
                tzinfo (0.3.32)
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
       40 
40 
     | 
    
         
             
              ruby
         
     | 
| 
         @@ -44,5 +44,5 @@ DEPENDENCIES 
     | 
|
| 
       44 
44 
     | 
    
         
             
              rake
         
     | 
| 
       45 
45 
     | 
    
         
             
              sdoc
         
     | 
| 
       46 
46 
     | 
    
         
             
              shoulda
         
     | 
| 
       47 
     | 
    
         
            -
              sqlite3 (>= 1.3. 
     | 
| 
      
 47 
     | 
    
         
            +
              sqlite3 (>= 1.3.5)
         
     | 
| 
       48 
48 
     | 
    
         
             
              turn
         
     | 
    
        data/README.rdoc
    CHANGED
    
    | 
         @@ -71,6 +71,10 @@ A couple useful named scopes are also generated when you use 
     | 
|
| 
       71 
71 
     | 
    
         
             
                # => (all users who are BOTH editors and writers)
         
     | 
| 
       72 
72 
     | 
    
         
             
                User.with_any_roles(:editor, :writer)
         
     | 
| 
       73 
73 
     | 
    
         
             
                # => (all users who are editors OR writers)
         
     | 
| 
      
 74 
     | 
    
         
            +
                User.with_exact_roles(:writer)
         
     | 
| 
      
 75 
     | 
    
         
            +
                # => (all users who are ONLY writers)
         
     | 
| 
      
 76 
     | 
    
         
            +
                User.with_exact_roles(:writer, :editor)
         
     | 
| 
      
 77 
     | 
    
         
            +
                # => (all users who are BOTH editors and writers and nothing else)
         
     | 
| 
       74 
78 
     | 
    
         | 
| 
       75 
79 
     | 
    
         
             
            Find records without any bitmask set:
         
     | 
| 
       76 
80 
     | 
    
         | 
| 
         @@ -79,12 +83,16 @@ Find records without any bitmask set: 
     | 
|
| 
       79 
83 
     | 
    
         
             
                User.no_roles
         
     | 
| 
       80 
84 
     | 
    
         
             
                # => (all users without a role)
         
     | 
| 
       81 
85 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
            Find records without  
     | 
| 
      
 86 
     | 
    
         
            +
            Find records without specific attributes:
         
     | 
| 
       83 
87 
     | 
    
         | 
| 
       84 
88 
     | 
    
         
             
                User.without_roles(:editor)
         
     | 
| 
       85 
89 
     | 
    
         
             
                # => (all users who are not editors)
         
     | 
| 
       86 
90 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 91 
     | 
    
         
            +
                User.without_roles(:writer, :editor)
         
     | 
| 
      
 92 
     | 
    
         
            +
                # => (all users who are NEITHER writers nor editors)
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            Note that "without_" supports one or more attribute arguments, and the "no_" method does not support arguments.
         
     | 
| 
      
 95 
     | 
    
         
            +
            And "with_exact_" without arguments is alias for "no_"
         
     | 
| 
       88 
96 
     | 
    
         | 
| 
       89 
97 
     | 
    
         | 
| 
       90 
98 
     | 
    
         
             
            === Adding Methods
         
     | 
| 
         @@ -102,6 +110,58 @@ named scopes): 
     | 
|
| 
       102 
110 
     | 
    
         
             
                user.other_attribute.worked?
         
     | 
| 
       103 
111 
     | 
    
         
             
                # => true
         
     | 
| 
       104 
112 
     | 
    
         | 
| 
      
 113 
     | 
    
         
            +
            === Handling null values
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
            By default, bitmasks support the potential for the underlying integer value to be null. However, if you have created
         
     | 
| 
      
 116 
     | 
    
         
            +
            a field that is guaranteed never to be null, you can simplify the SQL query conditions by declaring ":null => false"
         
     | 
| 
      
 117 
     | 
    
         
            +
            in the definition:
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                 bitmask :never_null_attributes,:as => [:value1, :value2], :null => false
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            === Allowing for a "zero" value
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            It is common to use web forms to set bitmask bits using checkboxes. If the various bits each are represented by a
         
     | 
| 
      
 124 
     | 
    
         
            +
            checkbox and the user unchecks them all, the resulting "params" posted to the controller will be missing. When this
         
     | 
| 
      
 125 
     | 
    
         
            +
            happens, a controller will need to ensure that a "params" hash entry has an empty array or a call to "update_attributes"
         
     | 
| 
      
 126 
     | 
    
         
            +
            will not change the attribute. For example:
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                In model...
         
     | 
| 
      
 129 
     | 
    
         
            +
                    class SomeModel < ActiveRecord::Base
         
     | 
| 
      
 130 
     | 
    
         
            +
                        bitmask :some_attribute, :as => [:value1, :value2]
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                In view...
         
     | 
| 
      
 134 
     | 
    
         
            +
                    <input type="checkbox" name="some_model[some_attribute][]" value="value1"/>
         
     | 
| 
      
 135 
     | 
    
         
            +
                    <input type="checkbox" name="some_model[some_attribute][]" value="value2"/>
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                In controller...
         
     | 
| 
      
 138 
     | 
    
         
            +
                    def update
         
     | 
| 
      
 139 
     | 
    
         
            +
                        @some_model = SomeModel.find(params[:id])
         
     | 
| 
      
 140 
     | 
    
         
            +
                        params[:some_attribute] ||= []
         
     | 
| 
      
 141 
     | 
    
         
            +
                        @some_model.update_attributes(params)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            As an alternative, you may provide a special symbol representing "zero":
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                In model...
         
     | 
| 
      
 147 
     | 
    
         
            +
                    class SomeModel < ActiveRecord::Base
         
     | 
| 
      
 148 
     | 
    
         
            +
                        bitmask :some_attribute, :as => [:value1, :value2], :zero_value => :none
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                In view...
         
     | 
| 
      
 152 
     | 
    
         
            +
                    <input type="checkbox" name="some_model[some_attribute][]" value="value1"/>
         
     | 
| 
      
 153 
     | 
    
         
            +
                    <input type="checkbox" name="some_model[some_attribute][]" value="value2"/>
         
     | 
| 
      
 154 
     | 
    
         
            +
                    <input type="hidden"   name="some_model[some_attribute][]" value="none"/>
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                In controller...
         
     | 
| 
      
 157 
     | 
    
         
            +
                    def update
         
     | 
| 
      
 158 
     | 
    
         
            +
                        @some_model = SomeModel.find(params[:id])
         
     | 
| 
      
 159 
     | 
    
         
            +
                        @some_model.update_attributes(params)
         
     | 
| 
      
 160 
     | 
    
         
            +
                    end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            This technique can be particularly useful for both forms and web services where setting the attribute in question may
         
     | 
| 
      
 163 
     | 
    
         
            +
            be optionally included or not such that the controller setting of an empty array in the first example would not be
         
     | 
| 
      
 164 
     | 
    
         
            +
            correct.
         
     | 
| 
       105 
165 
     | 
    
         | 
| 
       106 
166 
     | 
    
         
             
            === Warning: Modifying possible values
         
     | 
| 
       107 
167 
     | 
    
         | 
    
        data/lib/bitmask_attributes.rb
    CHANGED
    
    | 
         @@ -9,7 +9,7 @@ module BitmaskAttributes 
     | 
|
| 
       9 
9 
     | 
    
         
             
                  unless options[:as] && options[:as].kind_of?(Array)
         
     | 
| 
       10 
10 
     | 
    
         
             
                    raise ArgumentError, "Must provide an Array :as option"
         
     | 
| 
       11 
11 
     | 
    
         
             
                  end
         
     | 
| 
       12 
     | 
    
         
            -
                  bitmask_definitions[attribute] = Definition.new(attribute, options[:as].to_a,  
     | 
| 
      
 12 
     | 
    
         
            +
                  bitmask_definitions[attribute] = Definition.new(attribute, options[:as].to_a,options[:null].nil? || options[:null],options[:zero_value],&extension)
         
     | 
| 
       13 
13 
     | 
    
         
             
                  bitmask_definitions[attribute].install_on(self)
         
     | 
| 
       14 
14 
     | 
    
         
             
                end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
         @@ -1,11 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module BitmaskAttributes
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Definition
         
     | 
| 
       3 
     | 
    
         
            -
                attr_reader :attribute, :values, :extension
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :attribute, :values, :allow_null, :zero_value, :extension
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                def initialize(attribute, values=[], &extension)
         
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(attribute, values=[],allow_null = true,zero_value = nil, &extension)
         
     | 
| 
       6 
6 
     | 
    
         
             
                  @attribute = attribute
         
     | 
| 
       7 
7 
     | 
    
         
             
                  @values = values
         
     | 
| 
       8 
8 
     | 
    
         
             
                  @extension = extension
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @allow_null = allow_null
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @zero_value = zero_value
         
     | 
| 
       9 
11 
     | 
    
         
             
                end
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                def install_on(model)
         
     | 
| 
         @@ -17,7 +19,7 @@ module BitmaskAttributes 
     | 
|
| 
       17 
19 
     | 
    
         
             
                  create_scopes_on model
         
     | 
| 
       18 
20 
     | 
    
         
             
                  create_attribute_methods_on model
         
     | 
| 
       19 
21 
     | 
    
         
             
                end
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       21 
23 
     | 
    
         
             
                private
         
     | 
| 
       22 
24 
     | 
    
         | 
| 
       23 
25 
     | 
    
         
             
                  def validate_for(model)
         
     | 
| 
         @@ -25,9 +27,9 @@ module BitmaskAttributes 
     | 
|
| 
       25 
27 
     | 
    
         
             
                    # database (the migration has not been run) or table doesn't exist. This usually
         
     | 
| 
       26 
28 
     | 
    
         
             
                    # occurs in the 'test' and 'production' environment or during migration.
         
     | 
| 
       27 
29 
     | 
    
         
             
                    return if defined?(Rails) && Rails.configuration.cache_classes || !model.table_exists?
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       29 
31 
     | 
    
         
             
                    unless model.columns.detect { |col| col.name == attribute.to_s }
         
     | 
| 
       30 
     | 
    
         
            -
                       
     | 
| 
      
 32 
     | 
    
         
            +
                      Rails.logger.warn "WARNING: `#{attribute}' is not an attribute of `#{model}'. But, it's ok if it happens during migrations and your \"bitmasked\" attribute is still not created."
         
     | 
| 
       31 
33 
     | 
    
         
             
                    end
         
     | 
| 
       32 
34 
     | 
    
         
             
                  end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
         @@ -56,7 +58,7 @@ module BitmaskAttributes 
     | 
|
| 
       56 
58 
     | 
    
         
             
                    model.class_eval %(
         
     | 
| 
       57 
59 
     | 
    
         
             
                      def #{attribute}=(raw_value)
         
     | 
| 
       58 
60 
     | 
    
         
             
                        values = raw_value.kind_of?(Array) ? raw_value : [raw_value]
         
     | 
| 
       59 
     | 
    
         
            -
                        self.#{attribute}.replace(values.reject( 
     | 
| 
      
 61 
     | 
    
         
            +
                        self.#{attribute}.replace(values.reject{|value| #{eval_string_for_zero('value')}})
         
     | 
| 
       60 
62 
     | 
    
         
             
                      end
         
     | 
| 
       61 
63 
     | 
    
         
             
                    )
         
     | 
| 
       62 
64 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -74,7 +76,9 @@ module BitmaskAttributes 
     | 
|
| 
       74 
76 
     | 
    
         
             
                    model.class_eval %(
         
     | 
| 
       75 
77 
     | 
    
         
             
                      def self.bitmask_for_#{attribute}(*values)
         
     | 
| 
       76 
78 
     | 
    
         
             
                        values.inject(0) do |bitmask, value|
         
     | 
| 
       77 
     | 
    
         
            -
                           
     | 
| 
      
 79 
     | 
    
         
            +
                          if #{eval_string_for_zero('value')}
         
     | 
| 
      
 80 
     | 
    
         
            +
                            bit = 0
         
     | 
| 
      
 81 
     | 
    
         
            +
                          elsif (bit = bitmasks[:#{attribute}][value]).nil?
         
     | 
| 
       78 
82 
     | 
    
         
             
                            raise ArgumentError, "Unsupported value for #{attribute}: \#{value.inspect}"
         
     | 
| 
       79 
83 
     | 
    
         
             
                          end
         
     | 
| 
       80 
84 
     | 
    
         
             
                          bitmask | bit
         
     | 
| 
         @@ -105,50 +109,60 @@ module BitmaskAttributes 
     | 
|
| 
       105 
109 
     | 
    
         
             
                  end
         
     | 
| 
       106 
110 
     | 
    
         | 
| 
       107 
111 
     | 
    
         
             
                  def create_scopes_on(model)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    or_is_null_condition = " OR #{attribute} IS NULL" if allow_null
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
       108 
114 
     | 
    
         
             
                    model.class_eval %(
         
     | 
| 
       109 
115 
     | 
    
         
             
                      scope :with_#{attribute},
         
     | 
| 
       110 
116 
     | 
    
         
             
                        proc { |*values|
         
     | 
| 
       111 
117 
     | 
    
         
             
                          if values.blank?
         
     | 
| 
       112 
     | 
    
         
            -
                            where('#{attribute} > 0 
     | 
| 
      
 118 
     | 
    
         
            +
                            where('#{attribute} > 0')
         
     | 
| 
       113 
119 
     | 
    
         
             
                          else
         
     | 
| 
       114 
120 
     | 
    
         
             
                            sets = values.map do |value|
         
     | 
| 
       115 
     | 
    
         
            -
                              mask =  
     | 
| 
      
 121 
     | 
    
         
            +
                              mask = ::#{model}.bitmask_for_#{attribute}(value)
         
     | 
| 
       116 
122 
     | 
    
         
             
                              "#{attribute} & \#{mask} <> 0"
         
     | 
| 
       117 
123 
     | 
    
         
             
                            end
         
     | 
| 
       118 
124 
     | 
    
         
             
                            where(sets.join(' AND '))
         
     | 
| 
       119 
125 
     | 
    
         
             
                          end
         
     | 
| 
       120 
126 
     | 
    
         
             
                        }
         
     | 
| 
       121 
127 
     | 
    
         
             
                      scope :without_#{attribute}, 
         
     | 
| 
       122 
     | 
    
         
            -
                        proc { | 
     | 
| 
       123 
     | 
    
         
            -
                          if  
     | 
| 
       124 
     | 
    
         
            -
                             
     | 
| 
       125 
     | 
    
         
            -
                            where("#{attribute} IS NULL OR #{attribute} & ? = 0", mask)
         
     | 
| 
      
 128 
     | 
    
         
            +
                        proc { |*values|
         
     | 
| 
      
 129 
     | 
    
         
            +
                          if values.blank?
         
     | 
| 
      
 130 
     | 
    
         
            +
                            no_#{attribute}
         
     | 
| 
       126 
131 
     | 
    
         
             
                          else
         
     | 
| 
       127 
     | 
    
         
            -
                            where("#{attribute}  
     | 
| 
       128 
     | 
    
         
            -
                          end 
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                      scope : 
     | 
| 
      
 132 
     | 
    
         
            +
                            where("#{attribute} & ? = 0#{or_is_null_condition}", ::#{model}.bitmask_for_#{attribute}(*values))
         
     | 
| 
      
 133 
     | 
    
         
            +
                          end
         
     | 
| 
      
 134 
     | 
    
         
            +
                        }
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                      scope :with_exact_#{attribute},
         
     | 
| 
      
 137 
     | 
    
         
            +
                        proc { | *values|
         
     | 
| 
      
 138 
     | 
    
         
            +
                          if values.blank?
         
     | 
| 
      
 139 
     | 
    
         
            +
                            no_#{attribute}
         
     | 
| 
      
 140 
     | 
    
         
            +
                          else
         
     | 
| 
      
 141 
     | 
    
         
            +
                            where("#{attribute} = ?", ::#{model}.bitmask_for_#{attribute}(*values))
         
     | 
| 
      
 142 
     | 
    
         
            +
                          end
         
     | 
| 
      
 143 
     | 
    
         
            +
                        }
         
     | 
| 
       132 
144 
     | 
    
         | 
| 
      
 145 
     | 
    
         
            +
                      scope :no_#{attribute}, proc { where("#{attribute} = 0#{or_is_null_condition}") }
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
       133 
147 
     | 
    
         
             
                      scope :with_any_#{attribute},
         
     | 
| 
       134 
148 
     | 
    
         
             
                        proc { |*values|
         
     | 
| 
       135 
149 
     | 
    
         
             
                          if values.blank?
         
     | 
| 
       136 
     | 
    
         
            -
                            where('#{attribute} > 0 
     | 
| 
      
 150 
     | 
    
         
            +
                            where('#{attribute} > 0')
         
     | 
| 
       137 
151 
     | 
    
         
             
                          else
         
     | 
| 
       138 
     | 
    
         
            -
                             
     | 
| 
       139 
     | 
    
         
            -
                              mask = #{model}.bitmask_for_#{attribute}(value)
         
     | 
| 
       140 
     | 
    
         
            -
                              "#{attribute} & \#{mask} <> 0"
         
     | 
| 
       141 
     | 
    
         
            -
                            end
         
     | 
| 
       142 
     | 
    
         
            -
                            where(sets.join(' OR '))
         
     | 
| 
      
 152 
     | 
    
         
            +
                            where("#{attribute} & ? <> 0", ::#{model}.bitmask_for_#{attribute}(*values))
         
     | 
| 
       143 
153 
     | 
    
         
             
                          end
         
     | 
| 
       144 
154 
     | 
    
         
             
                        }
         
     | 
| 
       145 
155 
     | 
    
         
             
                    )
         
     | 
| 
       146 
156 
     | 
    
         
             
                    values.each do |value|
         
     | 
| 
       147 
157 
     | 
    
         
             
                      model.class_eval %(
         
     | 
| 
       148 
158 
     | 
    
         
             
                        scope :#{attribute}_for_#{value},
         
     | 
| 
       149 
     | 
    
         
            -
                              where('#{attribute} & ? <> 0',  
     | 
| 
      
 159 
     | 
    
         
            +
                              proc { where('#{attribute} & ? <> 0', ::#{model}.bitmask_for_#{attribute}(:#{value})) }
         
     | 
| 
       150 
160 
     | 
    
         
             
                      )
         
     | 
| 
       151 
161 
     | 
    
         
             
                    end      
         
     | 
| 
       152 
162 
     | 
    
         
             
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  def eval_string_for_zero(value_string)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    zero_value ? "#{value_string}.blank? || #{value_string}.to_s == '#{zero_value}'" : "#{value_string}.blank?"
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
       153 
167 
     | 
    
         
             
              end
         
     | 
| 
       154 
     | 
    
         
            -
            end
         
     | 
| 
      
 168 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,219 +1,275 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'test_helper'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            class BitmaskAttributesTest < ActiveSupport::TestCase
         
     | 
| 
       4 
     | 
    
         
            -
              
         
     | 
| 
       5 
     | 
    
         
            -
              context "Campaign" do
         
     | 
| 
       6 
     | 
    
         
            -
                teardown do
         
     | 
| 
       7 
     | 
    
         
            -
                  Company.destroy_all
         
     | 
| 
       8 
     | 
    
         
            -
                  Campaign.destroy_all
         
     | 
| 
       9 
     | 
    
         
            -
                end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                should "return all defined values of a given bitmask attribute" do
         
     | 
| 
       12 
     | 
    
         
            -
                  assert_equal Campaign.values_for_medium, [:web, :print, :email, :phone]
         
     | 
| 
       13 
     | 
    
         
            -
                end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                should "can assign single value to bitmask" do
         
     | 
| 
       16 
     | 
    
         
            -
                  assert_stored Campaign.new(:medium => :web), :web
         
     | 
| 
       17 
     | 
    
         
            -
                end
         
     | 
| 
       18 
4 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
              def self.context_with_classes(label,campaign_class,company_class)
         
     | 
| 
      
 6 
     | 
    
         
            +
                context label do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  setup do
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @campaign_class = campaign_class
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @company_class = company_class
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
       22 
11 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                   
     | 
| 
       27 
     | 
    
         
            -
                  assert_stored campaign, :web, :print, :phone
         
     | 
| 
       28 
     | 
    
         
            -
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  teardown do
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @company_class.destroy_all
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @campaign_class.destroy_all
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
       29 
16 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
       33 
     | 
    
         
            -
                  campaign.medium << :phone
         
     | 
| 
       34 
     | 
    
         
            -
                  assert_stored campaign, :web, :print, :phone
         
     | 
| 
       35 
     | 
    
         
            -
                  campaign.medium << :phone
         
     | 
| 
       36 
     | 
    
         
            -
                  assert_stored campaign, :web, :print, :phone
         
     | 
| 
       37 
     | 
    
         
            -
                  campaign.medium << "phone"
         
     | 
| 
       38 
     | 
    
         
            -
                  assert_stored campaign, :web, :print, :phone
         
     | 
| 
       39 
     | 
    
         
            -
                  assert_equal 1, campaign.medium.select { |value| value == :phone }.size
         
     | 
| 
       40 
     | 
    
         
            -
                  assert_equal 0, campaign.medium.select { |value| value == "phone" }.size
         
     | 
| 
       41 
     | 
    
         
            -
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  should "return all defined values of a given bitmask attribute" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                    assert_equal @campaign_class.values_for_medium, [:web, :print, :email, :phone]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
       42 
20 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                   
     | 
| 
       46 
     | 
    
         
            -
                  campaign.medium = [:phone, :email]
         
     | 
| 
       47 
     | 
    
         
            -
                  assert_stored campaign, :phone, :email
         
     | 
| 
       48 
     | 
    
         
            -
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  should "can assign single value to bitmask" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                    assert_stored @campaign_class.new(:medium => :web), :web
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
       49 
24 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                   
     | 
| 
       53 
     | 
    
         
            -
                  assert campaign.save
         
     | 
| 
       54 
     | 
    
         
            -
                  assert_stored Campaign.find(campaign.id), :web, :print
         
     | 
| 
       55 
     | 
    
         
            -
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  should "can assign multiple values to bitmask" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    assert_stored @campaign_class.new(:medium => [:web, :print]), :web, :print
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
       56 
28 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                    campaign.medium 
     | 
| 
      
 29 
     | 
    
         
            +
                  should "can add single value to bitmask" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 31 
     | 
    
         
            +
                    assert_stored campaign, :web, :print
         
     | 
| 
      
 32 
     | 
    
         
            +
                    campaign.medium << :phone
         
     | 
| 
      
 33 
     | 
    
         
            +
                    assert_stored campaign, :web, :print, :phone
         
     | 
| 
       61 
34 
     | 
    
         
             
                  end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  should "ignores duplicate values added to bitmask" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 38 
     | 
    
         
            +
                    assert_stored campaign, :web, :print
         
     | 
| 
      
 39 
     | 
    
         
            +
                    campaign.medium << :phone
         
     | 
| 
      
 40 
     | 
    
         
            +
                    assert_stored campaign, :web, :print, :phone
         
     | 
| 
      
 41 
     | 
    
         
            +
                    campaign.medium << :phone
         
     | 
| 
      
 42 
     | 
    
         
            +
                    assert_stored campaign, :web, :print, :phone
         
     | 
| 
      
 43 
     | 
    
         
            +
                    campaign.medium << "phone"
         
     | 
| 
      
 44 
     | 
    
         
            +
                    assert_stored campaign, :web, :print, :phone
         
     | 
| 
      
 45 
     | 
    
         
            +
                    assert_equal 1, campaign.medium.select { |value| value == :phone }.size
         
     | 
| 
      
 46 
     | 
    
         
            +
                    assert_equal 0, campaign.medium.select { |value| value == "phone" }.size
         
     | 
| 
       64 
47 
     | 
    
         
             
                  end
         
     | 
| 
       65 
     | 
    
         
            -
                  assert campaign.misc.worked?
         
     | 
| 
       66 
     | 
    
         
            -
                end
         
     | 
| 
       67 
48 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                  should "can assign new values at once to bitmask" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 51 
     | 
    
         
            +
                    assert_stored campaign, :web, :print
         
     | 
| 
      
 52 
     | 
    
         
            +
                    campaign.medium = [:phone, :email]
         
     | 
| 
      
 53 
     | 
    
         
            +
                    assert_stored campaign, :phone, :email
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
       74 
55 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                     
     | 
| 
       79 
     | 
    
         
            -
                     
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
       81 
     | 
    
         
            -
                end
         
     | 
| 
       82 
     | 
    
         
            -
                
         
     | 
| 
       83 
     | 
    
         
            -
                should "assert use of unknown value in convenience method will result in exception" do
         
     | 
| 
       84 
     | 
    
         
            -
                  assert_unsupported { Campaign.bitmask_for_medium(:web, :and_this_isnt_valid)  }
         
     | 
| 
       85 
     | 
    
         
            -
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  should "can save bitmask to db and retrieve values transparently" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 58 
     | 
    
         
            +
                    assert_stored campaign, :web, :print
         
     | 
| 
      
 59 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 60 
     | 
    
         
            +
                    assert_stored @campaign_class.find(campaign.id), :web, :print
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
       86 
62 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
      
 63 
     | 
    
         
            +
                  should "can add custom behavor to value proxies during bitmask definition" do
         
     | 
| 
      
 64 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 65 
     | 
    
         
            +
                    assert_raises NoMethodError do
         
     | 
| 
      
 66 
     | 
    
         
            +
                      campaign.medium.worked?
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                    assert_nothing_raised do
         
     | 
| 
      
 69 
     | 
    
         
            +
                      campaign.misc.worked?
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                    assert campaign.misc.worked?
         
     | 
| 
       91 
72 
     | 
    
         
             
                  end
         
     | 
| 
       92 
     | 
    
         
            -
                  assert_equal Campaign.bitmask_for_medium(:web, :print), string_bit
         
     | 
| 
       93 
     | 
    
         
            -
                end
         
     | 
| 
       94 
73 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
                  should "cannot use unsupported values" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    assert_unsupported { @campaign_class.new(:medium => [:web, :print, :this_will_fail]) }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => :web)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    assert_unsupported { campaign.medium << :this_will_fail_also }
         
     | 
| 
      
 78 
     | 
    
         
            +
                    assert_unsupported { campaign.medium = [:so_will_this] }
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
       100 
80 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                   
     | 
| 
      
 81 
     | 
    
         
            +
                  should "can determine bitmasks using convenience method" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                    assert @campaign_class.bitmask_for_medium(:web, :print)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    assert_equal(
         
     | 
| 
      
 84 
     | 
    
         
            +
                      @campaign_class.bitmasks[:medium][:web] | @campaign_class.bitmasks[:medium][:print],
         
     | 
| 
      
 85 
     | 
    
         
            +
                      @campaign_class.bitmask_for_medium(:web, :print)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    )
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
       108 
88 
     | 
    
         | 
| 
       109 
     | 
    
         
            -
                   
     | 
| 
       110 
     | 
    
         
            -
                     
     | 
| 
       111 
     | 
    
         
            -
                      assert @campaign.medium_for_web?
         
     | 
| 
       112 
     | 
    
         
            -
                      assert @campaign.medium_for_print?
         
     | 
| 
       113 
     | 
    
         
            -
                      assert !@campaign.medium_for_email?
         
     | 
| 
       114 
     | 
    
         
            -
                    end
         
     | 
| 
       115 
     | 
    
         
            -
                    
         
     | 
| 
       116 
     | 
    
         
            -
                    should "be supported by the simple predicate method" do
         
     | 
| 
       117 
     | 
    
         
            -
                      assert @campaign.medium?(:web)
         
     | 
| 
       118 
     | 
    
         
            -
                      assert @campaign.medium?(:print)
         
     | 
| 
       119 
     | 
    
         
            -
                      assert !@campaign.medium?(:email)
         
     | 
| 
       120 
     | 
    
         
            -
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  should "assert use of unknown value in convenience method will result in exception" do
         
     | 
| 
      
 90 
     | 
    
         
            +
                    assert_unsupported { @campaign_class.bitmask_for_medium(:web, :and_this_isnt_valid)  }
         
     | 
| 
       121 
91 
     | 
    
         
             
                  end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                   
     | 
| 
       124 
     | 
    
         
            -
                     
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                      assert  
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  should "hash of values is with indifferent access" do
         
     | 
| 
      
 94 
     | 
    
         
            +
                    string_bit = nil
         
     | 
| 
      
 95 
     | 
    
         
            +
                    assert_nothing_raised do
         
     | 
| 
      
 96 
     | 
    
         
            +
                      assert (string_bit = @campaign_class.bitmask_for_medium('web', 'print'))
         
     | 
| 
       127 
97 
     | 
    
         
             
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                    assert_equal @campaign_class.bitmask_for_medium(:web, :print), string_bit
         
     | 
| 
       128 
99 
     | 
    
         
             
                  end
         
     | 
| 
       129 
     | 
    
         
            -
                end
         
     | 
| 
       130 
100 
     | 
    
         | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
                     
     | 
| 
       134 
     | 
    
         
            -
                     
     | 
| 
       135 
     | 
    
         
            -
                    @campaign2 = @company.campaigns.create
         
     | 
| 
       136 
     | 
    
         
            -
                    @campaign3 = @company.campaigns.create :medium => [:web, :email] 
         
     | 
| 
      
 101 
     | 
    
         
            +
                  should "save bitmask with non-standard attribute names" do
         
     | 
| 
      
 102 
     | 
    
         
            +
                    campaign = @campaign_class.new(:Legacy => [:upper, :case])
         
     | 
| 
      
 103 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 104 
     | 
    
         
            +
                    assert_equal [:upper, :case], @campaign_class.find(campaign.id).Legacy
         
     | 
| 
       137 
105 
     | 
    
         
             
                  end
         
     | 
| 
       138 
106 
     | 
    
         | 
| 
       139 
     | 
    
         
            -
                  should " 
     | 
| 
       140 
     | 
    
         
            -
                    assert_equal  
     | 
| 
      
 107 
     | 
    
         
            +
                  should "ignore blanks fed as values" do
         
     | 
| 
      
 108 
     | 
    
         
            +
                    assert_equal 0b11,@campaign_class.bitmask_for_medium(:web, :print, '')
         
     | 
| 
      
 109 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print, ''])
         
     | 
| 
      
 110 
     | 
    
         
            +
                    assert_stored campaign, :web, :print
         
     | 
| 
       141 
111 
     | 
    
         
             
                  end
         
     | 
| 
       142 
112 
     | 
    
         | 
| 
       143 
     | 
    
         
            -
                   
     | 
| 
       144 
     | 
    
         
            -
                     
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                  context "checking" do
         
     | 
| 
      
 114 
     | 
    
         
            +
                    setup { @campaign = @campaign_class.new(:medium => [:web, :print]) }
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    context "for a single value" do
         
     | 
| 
      
 117 
     | 
    
         
            +
                      should "be supported by an attribute_for_value convenience method" do
         
     | 
| 
      
 118 
     | 
    
         
            +
                        assert @campaign.medium_for_web?
         
     | 
| 
      
 119 
     | 
    
         
            +
                        assert @campaign.medium_for_print?
         
     | 
| 
      
 120 
     | 
    
         
            +
                        assert !@campaign.medium_for_email?
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                      should "be supported by the simple predicate method" do
         
     | 
| 
      
 124 
     | 
    
         
            +
                        assert @campaign.medium?(:web)
         
     | 
| 
      
 125 
     | 
    
         
            +
                        assert @campaign.medium?(:print)
         
     | 
| 
      
 126 
     | 
    
         
            +
                        assert !@campaign.medium?(:email)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      end
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    context "for multiple values" do
         
     | 
| 
      
 131 
     | 
    
         
            +
                      should "be supported by the simple predicate method" do
         
     | 
| 
      
 132 
     | 
    
         
            +
                        assert @campaign.medium?(:web, :print)
         
     | 
| 
      
 133 
     | 
    
         
            +
                        assert !@campaign.medium?(:web, :email)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      end
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
       149 
136 
     | 
    
         
             
                  end
         
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
                   
     | 
| 
       152 
     | 
    
         
            -
                     
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  context "named scopes" do
         
     | 
| 
      
 139 
     | 
    
         
            +
                    setup do
         
     | 
| 
      
 140 
     | 
    
         
            +
                      @company = @company_class.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 
     | 
    
         
            +
                      @campaign4 = @company.campaigns.create :medium => [:web]
         
     | 
| 
      
 145 
     | 
    
         
            +
                      @campaign5 = @company.campaigns.create :medium => [:web, :print, :email]
         
     | 
| 
      
 146 
     | 
    
         
            +
                      @campaign6 = @company.campaigns.create :medium => [:web, :print, :email, :phone]
         
     | 
| 
      
 147 
     | 
    
         
            +
                      @campaign7 = @company.campaigns.create :medium => [:email, :phone]
         
     | 
| 
      
 148 
     | 
    
         
            +
                    end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                    should "support retrieval by any value" do
         
     | 
| 
      
 151 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
         
     | 
| 
      
 152 
     | 
    
         
            +
                    end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                    should "support retrieval by one matching value" do
         
     | 
| 
      
 155 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign5, @campaign6], @company.campaigns.with_medium(:print)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                    should "support retrieval by any matching value (OR)" do
         
     | 
| 
      
 159 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_any_medium(:print, :email)
         
     | 
| 
      
 160 
     | 
    
         
            +
                    end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                    should "support retrieval by all matching values" do
         
     | 
| 
      
 163 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign5, @campaign6], @company.campaigns.with_medium(:web, :print)
         
     | 
| 
      
 164 
     | 
    
         
            +
                      assert_equal [@campaign3, @campaign5, @campaign6], @company.campaigns.with_medium(:web, :email)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                    should "support retrieval for no values" do
         
     | 
| 
      
 168 
     | 
    
         
            +
                      assert_equal [@campaign2], @company.campaigns.without_medium
         
     | 
| 
      
 169 
     | 
    
         
            +
                      assert_equal [@campaign2], @company.campaigns.no_medium
         
     | 
| 
      
 170 
     | 
    
         
            +
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    should "support retrieval without a specific value" do
         
     | 
| 
      
 173 
     | 
    
         
            +
                      assert_equal [@campaign2, @campaign3, @campaign4, @campaign7], @company.campaigns.without_medium(:print)
         
     | 
| 
      
 174 
     | 
    
         
            +
                      assert_equal [@campaign2, @campaign7], @company.campaigns.without_medium(:web, :print)
         
     | 
| 
      
 175 
     | 
    
         
            +
                      assert_equal [@campaign2, @campaign3, @campaign4], @company.campaigns.without_medium(:print, :phone)
         
     | 
| 
      
 176 
     | 
    
         
            +
                    end
         
     | 
| 
      
 177 
     | 
    
         
            +
                    
         
     | 
| 
      
 178 
     | 
    
         
            +
                    should "support retrieval by exact value" do
         
     | 
| 
      
 179 
     | 
    
         
            +
                      assert_equal [@campaign4], @company.campaigns.with_exact_medium(:web)
         
     | 
| 
      
 180 
     | 
    
         
            +
                      assert_equal [@campaign1], @company.campaigns.with_exact_medium(:web, :print)
         
     | 
| 
      
 181 
     | 
    
         
            +
                      assert_equal [@campaign2], @company.campaigns.with_exact_medium
         
     | 
| 
      
 182 
     | 
    
         
            +
                    end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                    should "not retrieve retrieve a subsequent zero value for an unqualified with scope " do
         
     | 
| 
      
 185 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
         
     | 
| 
      
 186 
     | 
    
         
            +
                      @campaign4.medium = []
         
     | 
| 
      
 187 
     | 
    
         
            +
                      @campaign4.save
         
     | 
| 
      
 188 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_medium
         
     | 
| 
      
 189 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign5, @campaign6, @campaign7], @company.campaigns.with_any_medium
         
     | 
| 
      
 190 
     | 
    
         
            +
                    end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                    should "not retrieve retrieve a subsequent zero value for a qualified with scope " do
         
     | 
| 
      
 193 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign4, @campaign5, @campaign6], @company.campaigns.with_medium(:web)
         
     | 
| 
      
 194 
     | 
    
         
            +
                      @campaign4.medium = []
         
     | 
| 
      
 195 
     | 
    
         
            +
                      @campaign4.save
         
     | 
| 
      
 196 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign5, @campaign6], @company.campaigns.with_medium(:web)
         
     | 
| 
      
 197 
     | 
    
         
            +
                      assert_equal [@campaign1, @campaign3, @campaign5, @campaign6], @company.campaigns.with_any_medium(:web)
         
     | 
| 
      
 198 
     | 
    
         
            +
                    end
         
     | 
| 
       154 
199 
     | 
    
         
             
                  end
         
     | 
| 
       155 
200 
     | 
    
         | 
| 
       156 
     | 
    
         
            -
                  should " 
     | 
| 
       157 
     | 
    
         
            -
                     
     | 
| 
       158 
     | 
    
         
            -
                     
     | 
| 
      
 201 
     | 
    
         
            +
                  should "can check if at least one value is set" do
         
     | 
| 
      
 202 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 203 
     | 
    
         
            +
                    assert campaign.medium?
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                    campaign = @campaign_class.new
         
     | 
| 
      
 206 
     | 
    
         
            +
                    assert !campaign.medium?
         
     | 
| 
       159 
207 
     | 
    
         
             
                  end
         
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
                  should " 
     | 
| 
       162 
     | 
    
         
            -
                     
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                  should "find by bitmask values" do
         
     | 
| 
      
 210 
     | 
    
         
            +
                    campaign = @campaign_class.new(:medium => [:web, :print])
         
     | 
| 
      
 211 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                    assert_equal(
         
     | 
| 
      
 214 
     | 
    
         
            +
                      @campaign_class.find(:all, :conditions => ['medium & ? <> 0', @campaign_class.bitmask_for_medium(:print)]),
         
     | 
| 
      
 215 
     | 
    
         
            +
                      @campaign_class.medium_for_print
         
     | 
| 
      
 216 
     | 
    
         
            +
                    )
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                    assert_equal @campaign_class.medium_for_print.first, @campaign_class.medium_for_print.medium_for_web.first
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                    assert_equal [], @campaign_class.medium_for_email
         
     | 
| 
      
 221 
     | 
    
         
            +
                    assert_equal [], @campaign_class.medium_for_web.medium_for_email
         
     | 
| 
       163 
222 
     | 
    
         
             
                  end
         
     | 
| 
       164 
     | 
    
         
            -
                end
         
     | 
| 
       165 
223 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                  
         
     | 
| 
       170 
     | 
    
         
            -
                  campaign = Campaign.new
         
     | 
| 
       171 
     | 
    
         
            -
                  assert !campaign.medium?
         
     | 
| 
       172 
     | 
    
         
            -
                end
         
     | 
| 
      
 224 
     | 
    
         
            +
                  should "find no values" do
         
     | 
| 
      
 225 
     | 
    
         
            +
                    campaign = @campaign_class.create(:medium => [:web, :print])
         
     | 
| 
      
 226 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
       173 
227 
     | 
    
         | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                  campaign = Campaign.new(:medium => [:web, :print])
         
     | 
| 
       176 
     | 
    
         
            -
                  assert campaign.save
         
     | 
| 
       177 
     | 
    
         
            -
                  
         
     | 
| 
       178 
     | 
    
         
            -
                  assert_equal(
         
     | 
| 
       179 
     | 
    
         
            -
                    Campaign.find(:all, :conditions => ['medium & ? <> 0', Campaign.bitmask_for_medium(:print)]),
         
     | 
| 
       180 
     | 
    
         
            -
                    Campaign.medium_for_print
         
     | 
| 
       181 
     | 
    
         
            -
                  )
         
     | 
| 
       182 
     | 
    
         
            -
                  
         
     | 
| 
       183 
     | 
    
         
            -
                  assert_equal Campaign.medium_for_print.first, Campaign.medium_for_print.medium_for_web.first
         
     | 
| 
       184 
     | 
    
         
            -
                  
         
     | 
| 
       185 
     | 
    
         
            -
                  assert_equal [], Campaign.medium_for_email
         
     | 
| 
       186 
     | 
    
         
            -
                  assert_equal [], Campaign.medium_for_web.medium_for_email
         
     | 
| 
       187 
     | 
    
         
            -
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
                    assert_equal [], @campaign_class.no_medium
         
     | 
| 
       188 
229 
     | 
    
         | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                   
     | 
| 
       194 
     | 
    
         
            -
                  
         
     | 
| 
       195 
     | 
    
         
            -
                  campaign.medium = []
         
     | 
| 
       196 
     | 
    
         
            -
                  assert campaign.save
         
     | 
| 
       197 
     | 
    
         
            -
                  
         
     | 
| 
       198 
     | 
    
         
            -
                  assert_equal [campaign], Campaign.no_medium
         
     | 
| 
       199 
     | 
    
         
            -
                end
         
     | 
| 
      
 230 
     | 
    
         
            +
                    campaign.medium = []
         
     | 
| 
      
 231 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                    assert_equal [campaign], @campaign_class.no_medium
         
     | 
| 
      
 234 
     | 
    
         
            +
                  end
         
     | 
| 
       200 
235 
     | 
    
         | 
| 
      
 236 
     | 
    
         
            +
                  should "allow zero in values without changing result" do
         
     | 
| 
      
 237 
     | 
    
         
            +
                    assert_equal 0,@campaign_class.bitmask_for_allow_zero(:none)
         
     | 
| 
      
 238 
     | 
    
         
            +
                    assert_equal 0b111,@campaign_class.bitmask_for_allow_zero(:one,:two,:three,:none)
         
     | 
| 
       201 
239 
     | 
    
         | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
      
 240 
     | 
    
         
            +
                    campaign = @campaign_class.new(:allow_zero => :none)
         
     | 
| 
      
 241 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 242 
     | 
    
         
            +
                    assert_equal [],campaign.allow_zero
         
     | 
| 
       203 
243 
     | 
    
         | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
       205 
     | 
    
         
            -
                     
     | 
| 
      
 244 
     | 
    
         
            +
                    campaign.allow_zero = :none
         
     | 
| 
      
 245 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 246 
     | 
    
         
            +
                    assert_equal [],campaign.allow_zero
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                    campaign.allow_zero = [:one,:none]
         
     | 
| 
      
 249 
     | 
    
         
            +
                    assert campaign.save
         
     | 
| 
      
 250 
     | 
    
         
            +
                    assert_equal [:one],campaign.allow_zero
         
     | 
| 
       206 
251 
     | 
    
         
             
                  end
         
     | 
| 
       207 
252 
     | 
    
         | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                  private
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                    def assert_unsupported(&block)
         
     | 
| 
      
 257 
     | 
    
         
            +
                      assert_raises(ArgumentError, &block)
         
     | 
| 
       211 
258 
     | 
    
         
             
                    end
         
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
                    def assert_stored(record, *values)
         
     | 
| 
      
 261 
     | 
    
         
            +
                      values.each do |value|
         
     | 
| 
      
 262 
     | 
    
         
            +
                        assert record.medium.any? { |v| v.to_s == value.to_s }, "Values #{record.medium.inspect} does not include #{value.inspect}"
         
     | 
| 
      
 263 
     | 
    
         
            +
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                      full_mask = values.inject(0) do |mask, value|
         
     | 
| 
      
 265 
     | 
    
         
            +
                        mask | @campaign_class.bitmasks[:medium][value]
         
     | 
| 
      
 266 
     | 
    
         
            +
                      end
         
     | 
| 
      
 267 
     | 
    
         
            +
                      assert_equal full_mask, record.medium.to_i
         
     | 
| 
       214 
268 
     | 
    
         
             
                    end
         
     | 
| 
       215 
     | 
    
         
            -
                    assert_equal full_mask, record.medium.to_i
         
     | 
| 
       216 
     | 
    
         
            -
                  end
         
     | 
| 
       217 
269 
     | 
    
         | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
       218 
271 
     | 
    
         
             
              end
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
              context_with_classes 'Campaign with null attributes',CampaignWithNull,CompanyWithNull
         
     | 
| 
      
 274 
     | 
    
         
            +
              context_with_classes 'Campaign without null attributes',CampaignWithoutNull,CompanyWithoutNull
         
     | 
| 
       219 
275 
     | 
    
         
             
            end
         
     | 
    
        data/test/support/models.rb
    CHANGED
    
    | 
         @@ -1,26 +1,50 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ActiveRecord::Schema.define do 
         
     | 
| 
       2 
     | 
    
         
            -
              create_table : 
     | 
| 
      
 2 
     | 
    
         
            +
              create_table :campaign_with_nulls do |t|
         
     | 
| 
       3 
3 
     | 
    
         
             
                t.integer :company_id
         
     | 
| 
       4 
     | 
    
         
            -
                t.integer :medium, :misc, :Legacy
         
     | 
| 
      
 4 
     | 
    
         
            +
                t.integer :medium, :allow_zero, :misc, :Legacy
         
     | 
| 
       5 
5 
     | 
    
         
             
              end
         
     | 
| 
       6 
     | 
    
         
            -
              create_table : 
     | 
| 
      
 6 
     | 
    
         
            +
              create_table :company_with_nulls do |t|
         
     | 
| 
      
 7 
     | 
    
         
            +
                t.string :name
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              create_table :campaign_without_nulls do |t|
         
     | 
| 
      
 10 
     | 
    
         
            +
                t.integer :company_id
         
     | 
| 
      
 11 
     | 
    
         
            +
                t.integer :medium, :allow_zero, :misc, :Legacy, :null => false, :default => 0
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              create_table :company_without_nulls do |t|
         
     | 
| 
       7 
14 
     | 
    
         
             
                t.string :name
         
     | 
| 
       8 
15 
     | 
    
         
             
              end
         
     | 
| 
       9 
16 
     | 
    
         
             
            end
         
     | 
| 
       10 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
            # Pseudo models for testing purposes
         
     | 
| 
       11 
19 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            class  
     | 
| 
       13 
     | 
    
         
            -
              has_many :campaigns
         
     | 
| 
      
 20 
     | 
    
         
            +
            class CompanyWithNull < ActiveRecord::Base
         
     | 
| 
      
 21 
     | 
    
         
            +
              has_many :campaigns,:class_name => 'CampaignWithNull',:foreign_key => 'company_id'
         
     | 
| 
       14 
22 
     | 
    
         
             
            end
         
     | 
| 
       15 
23 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
              belongs_to :company
         
     | 
| 
      
 24 
     | 
    
         
            +
            class CampaignWithNull < ActiveRecord::Base
         
     | 
| 
      
 25 
     | 
    
         
            +
              belongs_to :company,:class_name => 'CompanyWithNull'
         
     | 
| 
       19 
26 
     | 
    
         
             
              bitmask :medium, :as => [:web, :print, :email, :phone]
         
     | 
| 
      
 27 
     | 
    
         
            +
              bitmask :allow_zero, :as => [:one, :two, :three], :zero_value => :none
         
     | 
| 
       20 
28 
     | 
    
         
             
              bitmask :misc, :as => %w(some useless values) do
         
     | 
| 
       21 
29 
     | 
    
         
             
                def worked?
         
     | 
| 
       22 
30 
     | 
    
         
             
                  true
         
     | 
| 
       23 
31 
     | 
    
         
             
                end
         
     | 
| 
       24 
32 
     | 
    
         
             
              end
         
     | 
| 
       25 
33 
     | 
    
         
             
              bitmask :Legacy, :as => [:upper, :case]
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            class CompanyWithoutNull < ActiveRecord::Base
         
     | 
| 
      
 37 
     | 
    
         
            +
              has_many :campaigns,:class_name => 'CampaignWithoutNull',:foreign_key => 'company_id'
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            class CampaignWithoutNull < ActiveRecord::Base
         
     | 
| 
      
 41 
     | 
    
         
            +
              belongs_to :company,:class_name => 'CompanyWithoutNull'
         
     | 
| 
      
 42 
     | 
    
         
            +
              bitmask :medium, :as => [:web, :print, :email, :phone], :null => false
         
     | 
| 
      
 43 
     | 
    
         
            +
              bitmask :allow_zero, :as => [:one, :two, :three], :zero_value => :none, :null => false
         
     | 
| 
      
 44 
     | 
    
         
            +
              bitmask :misc, :as => %w(some useless values), :null => false do
         
     | 
| 
      
 45 
     | 
    
         
            +
                def worked?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  true
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
              bitmask :Legacy, :as => [:upper, :case], :null => false
         
     | 
| 
       26 
50 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: bitmask_attributes
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.3.0
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
6 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       7 
7 
     | 
    
         
             
            authors:
         
     | 
| 
         @@ -9,11 +9,11 @@ authors: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date:  
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2012-04-30 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: activerecord
         
     | 
| 
       16 
     | 
    
         
            -
              requirement:  
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       17 
17 
     | 
    
         
             
                none: false
         
     | 
| 
       18 
18 
     | 
    
         
             
                requirements:
         
     | 
| 
       19 
19 
     | 
    
         
             
                - - ~>
         
     | 
| 
         @@ -21,7 +21,12 @@ dependencies: 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    version: '3.0'
         
     | 
| 
       22 
22 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       23 
23 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       24 
     | 
    
         
            -
              version_requirements:  
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 25 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 26 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 27 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 28 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 29 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
       25 
30 
     | 
    
         
             
            description: 
         
     | 
| 
       26 
31 
     | 
    
         
             
            email: joel@developwithstyle.com
         
     | 
| 
       27 
32 
     | 
    
         
             
            executables: []
         
     | 
| 
         @@ -31,6 +36,7 @@ files: 
     | 
|
| 
       31 
36 
     | 
    
         
             
            - .document
         
     | 
| 
       32 
37 
     | 
    
         
             
            - .gitignore
         
     | 
| 
       33 
38 
     | 
    
         
             
            - .rvmrc
         
     | 
| 
      
 39 
     | 
    
         
            +
            - .travis.yml
         
     | 
| 
       34 
40 
     | 
    
         
             
            - CHANGELOG.rdoc
         
     | 
| 
       35 
41 
     | 
    
         
             
            - Gemfile
         
     | 
| 
       36 
42 
     | 
    
         
             
            - Gemfile.lock
         
     | 
| 
         @@ -75,7 +81,6 @@ files: 
     | 
|
| 
       75 
81 
     | 
    
         
             
            - lib/bitmask_attributes/value_proxy.rb
         
     | 
| 
       76 
82 
     | 
    
         
             
            - lib/bitmask_attributes/version.rb
         
     | 
| 
       77 
83 
     | 
    
         
             
            - test/bitmask_attributes_test.rb
         
     | 
| 
       78 
     | 
    
         
            -
            - test/support/helpers.rb
         
     | 
| 
       79 
84 
     | 
    
         
             
            - test/support/models.rb
         
     | 
| 
       80 
85 
     | 
    
         
             
            - test/test_helper.rb
         
     | 
| 
       81 
86 
     | 
    
         
             
            homepage: http://github.com/joelmoss/bitmask_attributes
         
     | 
| 
         @@ -98,12 +103,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       98 
103 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       99 
104 
     | 
    
         
             
            requirements: []
         
     | 
| 
       100 
105 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       101 
     | 
    
         
            -
            rubygems_version: 1.8. 
     | 
| 
      
 106 
     | 
    
         
            +
            rubygems_version: 1.8.23
         
     | 
| 
       102 
107 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       103 
108 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       104 
109 
     | 
    
         
             
            summary: Simple bitmask attribute support for ActiveRecord
         
     | 
| 
       105 
110 
     | 
    
         
             
            test_files:
         
     | 
| 
       106 
111 
     | 
    
         
             
            - test/bitmask_attributes_test.rb
         
     | 
| 
       107 
     | 
    
         
            -
            - test/support/helpers.rb
         
     | 
| 
       108 
112 
     | 
    
         
             
            - test/support/models.rb
         
     | 
| 
       109 
113 
     | 
    
         
             
            - test/test_helper.rb
         
     | 
    
        data/test/support/helpers.rb
    DELETED
    
    | 
         @@ -1,17 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            class ActiveSupport::TestCase
         
     | 
| 
       2 
     | 
    
         
            -
              
         
     | 
| 
       3 
     | 
    
         
            -
              def assert_unsupported(&block)
         
     | 
| 
       4 
     | 
    
         
            -
                assert_raises(ArgumentError, &block)
         
     | 
| 
       5 
     | 
    
         
            -
              end
         
     | 
| 
       6 
     | 
    
         
            -
              
         
     | 
| 
       7 
     | 
    
         
            -
              def assert_stored(record, *values)
         
     | 
| 
       8 
     | 
    
         
            -
                values.each do |value|
         
     | 
| 
       9 
     | 
    
         
            -
                  assert record.medium.any? { |v| v.to_s == value.to_s }, "Values #{record.medium.inspect} does not include #{value.inspect}"
         
     | 
| 
       10 
     | 
    
         
            -
                end
         
     | 
| 
       11 
     | 
    
         
            -
                full_mask = values.inject(0) do |mask, value|
         
     | 
| 
       12 
     | 
    
         
            -
                  mask | Campaign.bitmasks[:medium][value]
         
     | 
| 
       13 
     | 
    
         
            -
                end
         
     | 
| 
       14 
     | 
    
         
            -
                assert_equal full_mask, record.medium.to_i
         
     | 
| 
       15 
     | 
    
         
            -
              end
         
     | 
| 
       16 
     | 
    
         
            -
              
         
     | 
| 
       17 
     | 
    
         
            -
            end
         
     |