enummer 1.0.3 → 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: da7e1c544817a7e7b874a4ca20372880f20d7cafe6cc5bb663e2224cd99d7ff2
4
- data.tar.gz: 3d18b5a7b106387dc8e76631f0b84204a7d11520f5dbb36b70bd8aa403b9569c
3
+ metadata.gz: 3c5046553ca9c053f2632d3bc1ca202a9c8da4b1d93fdca16c5d35606e774932
4
+ data.tar.gz: 06651c73f0aacb682d4a8dbb7b22387504eb2e6f6bc02d6de7dec88ef41605b7
5
5
  SHA512:
6
- metadata.gz: d16b48b263ca8ecf943e301993283ce356e3cf12961bd66839ce5a2400a3069197beeb4c75d24b2f7565a7c31fb1fe741e3a8c9a65f72d2b3d08549bf5ee3966
7
- data.tar.gz: 2b4d0c8c13b4133299c16e29034233c98fd1446c477f48bdc1acc6fc62db687da4ed8df47db6354475fab593043bf9e8ce0f11ca9bbc4e41796d62d678d69ab4
6
+ metadata.gz: e11ec3eabc2ede11eb342fc5022ef48c3905a338180ce925452d36baed39597a351fe183494e4ae18a3e63e2956e61a2cf7439d85111f08d8a3a5712d9cddf49
7
+ data.tar.gz: 7fa79d2c2d7743ab75c26c1754aa010894bfb99314869118e075f663ac33511b435c9200d360c16ddcb0fba55c21600a28c5b0076e75fb323dc6727dc9bb8690
data/README.md CHANGED
@@ -33,6 +33,18 @@ Now set up enummer with the available values in your model:
33
33
  enummer permissions: %i[read write execute]
34
34
  ```
35
35
 
36
+ Similar to `enum`, enummer can also be initialized with a hash, where the numeric index represents the position of the bit that maps to the flag:
37
+
38
+ ``` ruby
39
+ enummer permissions: {
40
+ read: 0,
41
+ write: 1,
42
+ execute: 2
43
+ }
44
+ ```
45
+
46
+ This makes it easier to add/remove entries without worrying about migrating historical data.
47
+
36
48
  ### Scopes
37
49
 
38
50
  Scopes will now be provided for `<option>` and `not_<option>`.
@@ -4,17 +4,16 @@ require "active_record/type"
4
4
 
5
5
  module Enummer
6
6
  class EnummerType < ::ActiveRecord::Type::Value
7
- # @param [Array<Symbol>] value_names list of all possible values for this type
8
- def initialize(value_names:)
9
- @value_names = value_names
10
- @bit_pairs = determine_bit_pairs(value_names)
7
+ # @param [Array<Symbol>] values hash with bit-value pairs for all possible values for this type
8
+ def initialize(values:)
9
+ @values = values
11
10
  end
12
11
 
13
12
  # @return Symbol Representation of this type
14
13
  # @example
15
14
  # :enummer[read|write|execute]
16
15
  def type
17
- "enummer[#{@value_names.join("|")}]".to_sym
16
+ :"enummer[#{@values.keys.join("|")}]"
18
17
  end
19
18
 
20
19
  # @param [Symbol|Array<Symbol>] value Current value represented as one or more symbols
@@ -22,7 +21,7 @@ module Enummer
22
21
  def serialize(value)
23
22
  return unless value
24
23
 
25
- Array.wrap(value).sum { |value_name| @bit_pairs.fetch(value_name.to_sym, 0) }
24
+ Array.wrap(value).sum { |value_name| @values.fetch(value_name, 0) }
26
25
  end
27
26
 
28
27
  # @param [Numeric] value Numeric representation of values
@@ -31,19 +30,17 @@ module Enummer
31
30
  return [] unless value
32
31
  return [] if value.to_i.zero?
33
32
 
34
- @bit_pairs.each_with_object([]) do |(pair_name, pair_value), value_names|
33
+ @values.each_with_object([]) do |(pair_name, pair_value), value_names|
35
34
  next if (value & pair_value).zero?
36
35
 
37
36
  value_names << pair_name
38
37
  end
39
38
  end
40
39
 
41
- private
42
-
43
- def determine_bit_pairs(value_names)
44
- value_names.map.with_index do |name, shift|
45
- [name, 1 << shift]
46
- end.to_h
40
+ # @param [Array<Symbol>] value Current value represented as one or more symbols or strings
41
+ # @return [Array<Symbol>] Current value represented as symbols
42
+ def cast(value)
43
+ Array.wrap(value).map(&:to_sym)
47
44
  end
48
45
  end
49
46
  end
@@ -13,10 +13,11 @@ module Enummer
13
13
  options[:_suffix] = values.delete(:_suffix)
14
14
 
15
15
  name, values = values.first
16
+ values = _enummer_determine_bit_pairs(values)
16
17
 
17
- attribute(name, :enummer, value_names: values)
18
+ attribute(name, :enummer, values: values)
18
19
 
19
- singleton_class.__send__(:define_method, name) { values }
20
+ singleton_class.__send__(:define_method, name) { values.keys }
20
21
 
21
22
  _enummer_build_with_scope(name, values)
22
23
  _enummer_build_values(name, values, options)
@@ -24,32 +25,31 @@ module Enummer
24
25
 
25
26
  private
26
27
 
27
- def _enummer_build_with_scope(attribute_name, value_names)
28
+ def _enummer_build_with_scope(attribute_name, values)
28
29
  scope "with_#{attribute_name}", lambda { |desired|
29
- expected = Array.wrap(desired).sum(0) { |value| 1 << value_names.index(value) }
30
+ expected = Array.wrap(desired).sum(0) { |value| values[value.to_sym] }
30
31
 
31
32
  where("#{attribute_name} & :expected = :expected", expected: expected)
32
33
  }
33
34
  end
34
35
 
35
- def _enummer_build_values(attribute_name, value_names, options)
36
- value_names.each_with_index do |name, i|
36
+ def _enummer_build_values(attribute_name, values, options)
37
+ values.each do |name, bit|
37
38
  method_name = _enummer_method_name(attribute_name, name, options)
38
39
 
39
- define_method("#{method_name}?") { self[attribute_name].include?(name) }
40
- define_method("#{method_name}=") do |new_value|
41
- if new_value
42
- self[attribute_name].push(name)
40
+ define_method(:"#{method_name}?") { self[attribute_name].include?(name) }
41
+ define_method(:"#{method_name}=") do |new_value|
42
+ if ActiveModel::Type::Boolean.new.cast(new_value)
43
+ self[attribute_name] += [name]
43
44
  else
44
- self[attribute_name].delete(name)
45
+ self[attribute_name] -= [name]
45
46
  end
47
+ self[attribute_name].uniq!
46
48
  end
47
- define_method("#{method_name}!") do
49
+ define_method(:"#{method_name}!") do
48
50
  update(attribute_name => self[attribute_name] + [name])
49
51
  end
50
52
 
51
- bit = 1 << i
52
-
53
53
  scope method_name, -> { where("#{attribute_name} & :bit = :bit", bit: bit) }
54
54
  scope "not_#{method_name}", -> { where("#{attribute_name} & :bit != :bit", bit: bit) }
55
55
  end
@@ -68,5 +68,12 @@ module Enummer
68
68
 
69
69
  value
70
70
  end
71
+
72
+ def _enummer_determine_bit_pairs(values)
73
+ values = values.map.with_index { |value, i| [value, i] }.to_h if values.is_a?(Array)
74
+ values.transform_values do |shift|
75
+ 1 << shift
76
+ end
77
+ end
71
78
  end
72
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enummer
4
- VERSION = "1.0.3"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # desc "Explaining what the task does"
3
4
  # task :enummer do
4
5
  # # Task goes here
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enummer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Schembri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-27 00:00:00.000000000 Z
11
+ date: 2024-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -55,14 +55,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - ">="
57
57
  - !ruby/object:Gem::Version
58
- version: '2.7'
58
+ version: '3.1'
59
59
  required_rubygems_version: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0'
64
64
  requirements: []
65
- rubygems_version: 3.3.3
65
+ rubygems_version: 3.5.9
66
66
  signing_key:
67
67
  specification_version: 4
68
68
  summary: Multi-value enums for Rails.