bitmask_enum 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b142602ee1da79ca17074c2fe1edcabeb98d5a053c2486f98ef95410a6f0b15
4
- data.tar.gz: fa1d5994dd353bd811ed560f1fbbb204d7d8fe2ff824280c8b4dc689592fb72e
3
+ metadata.gz: ca2abf599d5126367ff0a605da44b150e39d475a2e715fb7a1c424edc54a31ea
4
+ data.tar.gz: f67516fe2b686f8d92044ad745be0189c6cb71af86ef2689c9b3785b16a7e99a
5
5
  SHA512:
6
- metadata.gz: 0bf71ad17b882b72b65f90902c54c8ecf2e2c6589acb4fd90b8b4f586d02b5caa20d2500a0a0b880ea10045048dae6062d5346801a6b0d89c6048dca3908f9e4
7
- data.tar.gz: 4fc29a681c368a0808d4554fd74e448a28cf24486a81d0488d765add4124e38ce1e40ffeddcf38bedad81579813103bf58fc52e3d3feb38dc63c25aacb8c812b
6
+ metadata.gz: a2261aa059b461ce5ed1083a66fd8e9173c3f4fd58241e9beb116a1ac0848077f347370e8468d8012bf1555153a1f2fbaa293edd7944f392ed6391e03a19b7dd
7
+ data.tar.gz: 7ab5c0cd95db21e8e36aa744d46e61efc943ad465e6912898843fbf91e641d265b7bce6ecd857e8575b93b7678379d00813923b14f8ddff97c1ebd27c9d7d8b1
data/.rubocop.yml CHANGED
@@ -6,6 +6,8 @@ AllCops:
6
6
  NewCops: enable
7
7
  TargetRubyVersion: 2.4
8
8
 
9
+ Metrics/ClassLength:
10
+ Max: 120
9
11
  Metrics/MethodLength:
10
12
  Max: 20
11
13
  RSpec/ExampleLength:
data/CHANGELOG.md CHANGED
@@ -37,3 +37,9 @@ Add YARD docs.
37
37
  Standardize output to symbols.
38
38
  Add validation of the attribute - less_than: 1 << flags.size
39
39
  Add max ActiveRecord version to protect against future breaking releases
40
+
41
+ # 1.1.0 : 2022-08-30
42
+
43
+ Add dynamic scopes for any of provided flags enabled or disabled.
44
+ Add dynamic scopes for all of provided flags enabled or disabled.
45
+ Correct and update some documentation.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bitmask_enum (1.0.0)
4
+ bitmask_enum (1.1.0)
5
5
  activerecord (>= 4.2, <= 7.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -10,6 +10,8 @@ Supporting Ruby 2.4+ and Rails 4.2+.
10
10
 
11
11
  Credit is due to Joel Moss' gem [bitmask_attributes](https://github.com/joelmoss/bitmask_attributes). I came across it while considering if I should write a gem for this. It's great work and some elements of it inspired this gem, I just had my own thoughts about how I'd like the gem to operate, and wanted some more end-to-end experience on gem production so I decided to create this rather than pick up the torch on that repo.
12
12
 
13
+ This gem attempts to improve performance by precomputing the integer values for the enum rather than using bitwise operations in the SQL.
14
+
13
15
  ## Installation
14
16
 
15
17
  Add this line to your application's Gemfile:
@@ -28,6 +30,8 @@ Or install it yourself as:
28
30
 
29
31
  ## Usage
30
32
 
33
+ [RubyDocs for BitmaskEnum](https://www.rubydoc.info/github/lucygilbert/bitmask_enum/master)
34
+
31
35
  In the model, the bitmask enum is added in a similar way to enums. Given an integer attribute called `attribs`, flags of `flag` and `flag2`, adding the `flag_prefix` option with the value `type`, the following line would be used:
32
36
 
33
37
  ```ruby
@@ -129,7 +133,9 @@ The method returns an array of all enabled flags on the instance. The items will
129
133
 
130
134
  ### `{attribute}=` (_Override_)
131
135
 
132
- **No params**
136
+ **Params**
137
+
138
+ - value [Integer, Symbol, String, Array\<Symbol, String\>] - An integer, a defined flag or array of defined flags
133
139
 
134
140
  This method will be created once on the instance.
135
141
 
@@ -163,6 +169,54 @@ The method is a scope of all records for which the flag is disabled.
163
169
 
164
170
  **Return value:** `ActiveRecord::Relation` - a collection of all records for which the flag is disabled.
165
171
 
172
+ ### `any_{attribute}_enabled`
173
+
174
+ **Params**
175
+
176
+ - flags [Symbol, String, Array\<Symbol, String\>] - A defined flag or array of defined flags
177
+
178
+ This method will be created once on the class.
179
+
180
+ The method is a scope of all records for which any of the provided flags are enabled.
181
+
182
+ **Return value:** `ActiveRecord::Relation` - a collection of all records for which the flag is enabled.
183
+
184
+ ### `any_{attribute}_disabled`
185
+
186
+ **Params**
187
+
188
+ - flags [Symbol, String, Array\<Symbol, String\>] - A defined flag or array of defined flags
189
+
190
+ This method will be created once on the class.
191
+
192
+ The method is a scope of all records for which any of the provided flags are disabled.
193
+
194
+ **Return value:** `ActiveRecord::Relation` - a collection of all records for which the flag is disabled.
195
+
196
+ ### `all_{attribute}_enabled`
197
+
198
+ **Params**
199
+
200
+ - flags [Symbol, String, Array\<Symbol, String\>] - A defined flag or array of defined flags
201
+
202
+ This method will be created once on the class.
203
+
204
+ The method is a scope of all records for which all of the provided flags are enabled.
205
+
206
+ **Return value:** `ActiveRecord::Relation` - a collection of all records for which the flag is enabled.
207
+
208
+ ### `all_{attribute}_disabled`
209
+
210
+ **Params**
211
+
212
+ - flags [Symbol, String, Array\<Symbol, String\>] - A defined flag or array of defined flags
213
+
214
+ This method will be created once on the class.
215
+
216
+ The method is a scope of all records for which all of the provided flags are disabled.
217
+
218
+ **Return value:** `ActiveRecord::Relation` - a collection of all records for which the flag is disabled.
219
+
166
220
  ### `{attribute}`
167
221
 
168
222
  **No params**
@@ -30,6 +30,10 @@ module BitmaskEnum
30
30
  flag_getter_method
31
31
  flag_setter_method
32
32
 
33
+ dynamic_any_enabled_scope
34
+ dynamic_any_disabled_scope
35
+ dynamic_all_enabled_scope
36
+ dynamic_all_disabled_scope
33
37
  class_flag_values_method
34
38
  end
35
39
 
@@ -45,8 +49,8 @@ module BitmaskEnum
45
49
  flag_on_method(flag_label, flag_index)
46
50
  flag_off_method(flag_label, flag_index)
47
51
 
48
- class_flag_enabled_scope(flag_label, flag_index)
49
- class_flag_disabled_scope(flag_label, flag_index)
52
+ flag_enabled_scope(flag_label, flag_index)
53
+ flag_disabled_scope(flag_label, flag_index)
50
54
  end
51
55
 
52
56
  def flag_check_method(flag_label, flag_index)
@@ -80,25 +84,55 @@ module BitmaskEnum
80
84
  @model.class_eval EvalScripts.flag_method(method_name, method_code), __FILE__, __LINE__
81
85
  end
82
86
 
83
- def class_flag_enabled_scope(flag_label, flag_index)
84
- class_flag_scope("#{flag_label}_enabled", :on, flag_index)
87
+ def flag_enabled_scope(flag_label, flag_index)
88
+ flag_scope("#{flag_label}_enabled", :on, flag_index)
85
89
  end
86
90
 
87
- def class_flag_disabled_scope(flag_label, flag_index)
88
- class_flag_scope("#{flag_label}_disabled", :off, flag_index)
91
+ def flag_disabled_scope(flag_label, flag_index)
92
+ flag_scope("#{flag_label}_disabled", :off, flag_index)
89
93
  end
90
94
 
91
- def class_flag_scope(scope_name, setting, flag_index)
92
- comparator = setting == :on ? :> : :==
93
- values_for_bitmask = (0...(1 << @flags.size)).select { |x| (x & (1 << flag_index)).send(comparator, 0) }
94
-
95
- values_for_bitmask = @nil_handler.in_array(values_for_bitmask) if setting == :off
95
+ def flag_scope(scope_name, setting, flag_index)
96
+ values_for_bitmask = values_for_flag_bitmask(setting, flag_index)
96
97
 
97
98
  @conflict_checker.check_class_method!(scope_name)
98
99
 
99
100
  @model.class_eval EvalScripts.flag_scope(scope_name, @attribute, values_for_bitmask), __FILE__, __LINE__
100
101
  end
101
102
 
103
+ def dynamic_any_enabled_scope
104
+ dynamic_scope("any_#{@attribute}_enabled", :on, '|')
105
+ end
106
+
107
+ def dynamic_any_disabled_scope
108
+ dynamic_scope("any_#{@attribute}_disabled", :off, '|')
109
+ end
110
+
111
+ def dynamic_all_enabled_scope
112
+ dynamic_scope("all_#{@attribute}_enabled", :on, '&')
113
+ end
114
+
115
+ def dynamic_all_disabled_scope
116
+ dynamic_scope("all_#{@attribute}_disabled", :off, '&')
117
+ end
118
+
119
+ def dynamic_scope(scope_name, setting, bitwise_operator)
120
+ flags_and_values = @flags.each_with_index.map do |flag, flag_index|
121
+ [flag, values_for_flag_bitmask(setting, flag_index)]
122
+ end
123
+
124
+ @model.class_eval EvalScripts.dynamic_scope(
125
+ scope_name, @attribute, flags_and_values, bitwise_operator
126
+ ), __FILE__, __LINE__ - 2
127
+ end
128
+
129
+ def values_for_flag_bitmask(setting, flag_index)
130
+ comparator = setting == :on ? :> : :==
131
+ values_for_bitmask = (0...(1 << @flags.size)).select { |x| (x & (1 << flag_index)).send(comparator, 0) }
132
+ values_for_bitmask = @nil_handler.in_array(values_for_bitmask) if setting == :off
133
+ values_for_bitmask
134
+ end
135
+
102
136
  def flag_settings_hash_method
103
137
  method_name = "#{@attribute}_settings"
104
138
 
@@ -33,7 +33,7 @@ module BitmaskEnum
33
33
  # Code for methods scoping by flag: `.flag_enabled`, `.flag_disabled`
34
34
  # @param scope_name [String] Name of the scope
35
35
  # @param attribute [String] Name of the attribute
36
- # @param values_for_bitmask [Array] Array of integers for which the flag would be disabled
36
+ # @param values_for_bitmask [Array] Array of integers for which the flag would be enabled/disabled
37
37
  # @return [String] Code string to be evaled
38
38
  def flag_scope(scope_name, attribute, values_for_bitmask)
39
39
  %(
@@ -43,6 +43,33 @@ module BitmaskEnum
43
43
  )
44
44
  end
45
45
 
46
+ # Code for methods dynamically scoping by flags: `.attribs_enabled`, `.attribs_disabled`
47
+ # @param scope_name [String] Name of the scope
48
+ # @param attribute [String] Name of the attribute
49
+ # @param flags_and_values [Array] Array of arrays, first being the flag, second being the enum values for the flag
50
+ # @param bitwise_operator [String] Bitwise operator used to combine the enum value arrays
51
+ # @return [String] Code string to be evaled
52
+ def dynamic_scope(scope_name, attribute, flags_and_values, bitwise_operator)
53
+ %(
54
+ scope :#{scope_name}, ->(flags) do # scope :attribs_disabled, ->(flags) do
55
+ enum_values = { # enum_values = {
56
+ #{flags_and_values.map { |f, v| "#{f}: #{v}" }.join(', ')} # flag: [1,3], flag2: [2]
57
+ } # }
58
+ #
59
+ where('#{attribute}' => Array(flags).map do |flag| # where('attribs' => Array(flags).map do |flag|
60
+ flag_values = enum_values[flag.to_sym] # flag_values = enum_values[flag.to_sym]
61
+ if flag_values.nil? # if flag_index.nil?
62
+ raise( # raise(
63
+ ArgumentError, # ArgumentError,
64
+ "Invalid flag \#{flag} for #{attribute}" # "Invalid flag \#{flag} for attribs"
65
+ ) # )
66
+ end # end
67
+ flag_values # flag_values
68
+ end.reduce(&:#{bitwise_operator})) # end.map(&:|))
69
+ end # end
70
+ )
71
+ end
72
+
46
73
  # Code for method returning hash of flags with their boolean setting: `#attribs_settings`
47
74
  # @param method_name [String] Name of the method
48
75
  # @param flag_hash_contents [String] Contents of the hash which provides the flag settings
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BitmaskEnum
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitmask_enum
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucy Gilbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2022-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord