enummer 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +59 -6
- data/lib/enummer/enummer_type.rb +10 -8
- data/lib/enummer/extension.rb +20 -19
- data/lib/enummer/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adf5116258e6b0e0e5e3b4fc962f97228c26369c41c200a8af07dccd67f8d48e
|
4
|
+
data.tar.gz: ea4399838cf8e5cf8be9b23629b88af16c5355f0684d645a7f27db1d94fa642d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 328f419c099db1f1845c9e851fc7f85d7e26728d20ac2d400161ca8f0ba27738e835361499bb3e34f78b4be06b940cc1126d952d48a59cb9d287c6cd2d5cc9af
|
7
|
+
data.tar.gz: e119a0af64fa3318df0cfe09ff927c6e15780f592c13163565a6ce33cce7e61246a0395e97c86e7323de1829411efb5e25714959e6da98dbfcffe37824a1a6fd
|
data/README.md
CHANGED
@@ -1,17 +1,25 @@
|
|
1
1
|
# Enummer
|
2
|
-
|
2
|
+
|
3
|
+
[![Gem](https://img.shields.io/gem/v/enummer?color=green)](https://rubygems.org/gems/enummer)
|
4
|
+
[![Codecov](https://img.shields.io/codecov/c/github/shkm/enummer/main)](https://app.codecov.io/gh/shkm/enummer)
|
5
|
+
[![Licence](https://img.shields.io/github/license/shkm/enummer)](https://github.com/shkm/enummer/blob/main/MIT-LICENSE)
|
6
|
+
[![Documentation](https://img.shields.io/badge/yard-docs-informational)](https://www.rubydoc.info/github/shkm/enummer/main)
|
7
|
+
|
8
|
+
Enummer is a lightweight answer for adding enums with multiple values to Rails, with a similar syntax to Rails' built-in `enum`. At the moment it officially supports only PostgreSQL and recent Rails versions, though YMMV on another DBMS.
|
3
9
|
|
4
10
|
## Installation
|
5
11
|
Add `gem "enummer"` to your Gemfile and `bundle`.
|
6
12
|
|
7
13
|
## Usage
|
8
|
-
|
14
|
+
|
15
|
+
### Setup
|
16
|
+
Create a migration for an integer that looks something like this:
|
9
17
|
|
10
18
|
```ruby
|
11
19
|
class CreateUsers < ActiveRecord::Migration[7.0]
|
12
20
|
def change
|
13
21
|
create_table :users do |t|
|
14
|
-
t.
|
22
|
+
t.integer :permissions, default: 0, null: false
|
15
23
|
end
|
16
24
|
end
|
17
25
|
end
|
@@ -23,11 +31,55 @@ Now set up enummer with the available values in your model:
|
|
23
31
|
enummer permissions: %i[read write execute]
|
24
32
|
```
|
25
33
|
|
26
|
-
|
34
|
+
### Scopes
|
35
|
+
|
36
|
+
Scopes will now be provided for `<option>` and `not_<option>`.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
User.read
|
40
|
+
User.not_read
|
41
|
+
User.write
|
42
|
+
User.not_write
|
43
|
+
User.execute
|
44
|
+
User.not_execute
|
45
|
+
```
|
46
|
+
|
47
|
+
### Getter methods
|
48
|
+
|
49
|
+
Simply calling the instance method for the column will return an array of options. Question mark methods are also provided.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
user = User.last
|
53
|
+
|
54
|
+
user.permissions # => [:read, :write]
|
55
|
+
|
56
|
+
user.read? # => true
|
57
|
+
user.write? # => true
|
58
|
+
user.execute? # => false
|
59
|
+
```
|
60
|
+
|
61
|
+
### Setter methods
|
62
|
+
|
63
|
+
Options can be set with an array of symbols or via bang methods. Bang methods will additionally persist the changes.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
user.update(permissions: %i[read write])
|
67
|
+
user.write!
|
68
|
+
```
|
69
|
+
|
70
|
+
## FAQ
|
71
|
+
|
72
|
+
### Which data type should I use?
|
73
|
+
That depends on how many options you expect to store. [In PostgreSQL](https://www.postgresql.org/docs/9.1/datatype-numeric.html) you should be able to store `bytes * 8 - 1` of your data type:
|
27
74
|
|
28
|
-
|
75
|
+
| Type | Bytes | Values |
|
76
|
+
|----------|-------|-------------|
|
77
|
+
| smallint | 2 | 15 |
|
78
|
+
| integer | 4 | 31 |
|
79
|
+
| bigint | 8 | 65 |
|
80
|
+
| numeric | ??? | all of them |
|
29
81
|
|
30
|
-
|
82
|
+
### How can I use it outside of Rails?
|
31
83
|
lol stop
|
32
84
|
|
33
85
|
## Contributing
|
@@ -36,6 +88,7 @@ Make an issue / PR and we'll see.
|
|
36
88
|
## Alternatives
|
37
89
|
- [flag_shih_tzu](https://github.com/pboling/flag_shih_tzu)
|
38
90
|
- Lots of booleans
|
91
|
+
- DB Arrays
|
39
92
|
|
40
93
|
## License
|
41
94
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/enummer/enummer_type.rb
CHANGED
@@ -4,30 +4,32 @@ require "active_record/type"
|
|
4
4
|
|
5
5
|
module Enummer
|
6
6
|
class EnummerType < ::ActiveRecord::Type::Value
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(value_names:, limit:)
|
7
|
+
# @param [Array<Symbol>] value_names list of all possible values for this type
|
8
|
+
def initialize(value_names:)
|
10
9
|
@value_names = value_names
|
11
10
|
@bit_pairs = determine_bit_pairs(value_names)
|
12
|
-
@limit = limit
|
13
11
|
end
|
14
12
|
|
13
|
+
# @return Symbol Representation of this type
|
14
|
+
# @example
|
15
|
+
# :enummer[read|write|execute]
|
15
16
|
def type
|
16
17
|
"enummer[#{@value_names.join("|")}]".to_sym
|
17
18
|
end
|
18
19
|
|
20
|
+
# @param [Symbol|Array<Symbol>] value Current value represented as one or more symbols
|
21
|
+
# @return Numeric Numeric representation of values
|
19
22
|
def serialize(value)
|
20
23
|
return unless value
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
int.to_s(2).rjust(@limit, "0")
|
25
|
+
Array.wrap(value).sum { |value_name| @bit_pairs.fetch(value_name, 0) }
|
25
26
|
end
|
26
27
|
|
28
|
+
# @param [Numeric] value Numeric representation of values
|
29
|
+
# @return [Array<Symbol>] Current value represented as symbols
|
27
30
|
def deserialize(value)
|
28
31
|
return [] unless value
|
29
32
|
|
30
|
-
value = value.to_i(2)
|
31
33
|
@bit_pairs.each_with_object([]) do |(pair_name, pair_value), value_names|
|
32
34
|
next if (value & pair_value).zero?
|
33
35
|
|
data/lib/enummer/extension.rb
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
module Enummer
|
4
4
|
module Extension
|
5
|
+
# @param [Hash] values The attribute name to options mapping for an multi-option enum
|
6
|
+
# @option values [Boolean|String] :_prefix The prefix to give to generated methods. If true, uses the attribute name.
|
7
|
+
# @option values [Boolean|String] :_suffix The suffix to give to generated methods. If true, uses the attribute name.
|
8
|
+
# @example Defining an enummer with a prefix. This would generate `#can_read?`, `#can_read=`, `#can_read!`, `.can_read`, etc.
|
9
|
+
# enummer permissions: %i[read write execute], :_prefix: 'can'
|
5
10
|
def enummer(values)
|
6
11
|
options = {}
|
7
12
|
options[:_prefix] = values.delete(:_prefix)
|
@@ -9,19 +14,25 @@ module Enummer
|
|
9
14
|
|
10
15
|
name, values = values.first
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
attribute(name, :enummer, value_names: values, limit: limit)
|
17
|
+
attribute(name, :enummer, value_names: values)
|
15
18
|
|
16
19
|
singleton_class.__send__(:define_method, name) { values }
|
17
20
|
|
18
|
-
_enummer_build_with_scope(name, values
|
19
|
-
_enummer_build_values(name, values,
|
21
|
+
_enummer_build_with_scope(name, values)
|
22
|
+
_enummer_build_values(name, values, options)
|
20
23
|
end
|
21
24
|
|
22
25
|
private
|
23
26
|
|
24
|
-
def
|
27
|
+
def _enummer_build_with_scope(attribute_name, value_names)
|
28
|
+
scope "with_#{attribute_name}", lambda { |desired|
|
29
|
+
expected = Array.wrap(desired).sum(0) { |value| 1 << value_names.index(value) }
|
30
|
+
|
31
|
+
where("#{attribute_name} & :expected = :expected", expected: expected)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def _enummer_build_values(attribute_name, value_names, options)
|
25
36
|
value_names.each_with_index do |name, i|
|
26
37
|
method_name = _enummer_method_name(attribute_name, name, options)
|
27
38
|
|
@@ -37,23 +48,13 @@ module Enummer
|
|
37
48
|
update(attribute_name => self[attribute_name] + [name])
|
38
49
|
end
|
39
50
|
|
40
|
-
|
51
|
+
bit = 1 << i
|
41
52
|
|
42
|
-
scope method_name, -> { where("
|
43
|
-
scope "not_#{method_name}", -> { where("
|
53
|
+
scope method_name, -> { where("#{attribute_name} & :bit = :bit", bit: bit) }
|
54
|
+
scope "not_#{method_name}", -> { where("#{attribute_name} & :bit != :bit", bit: bit) }
|
44
55
|
end
|
45
56
|
end
|
46
57
|
|
47
|
-
def _enummer_build_with_scope(attribute_name, value_names, limit)
|
48
|
-
scope "with_#{attribute_name}", lambda { |desired|
|
49
|
-
desired = Array.wrap(desired)
|
50
|
-
|
51
|
-
bitstring = (0..limit - 1).to_a.sum("") { |i| desired.include?(value_names[i]) ? "1" : "0" }.reverse
|
52
|
-
|
53
|
-
where("#{attribute_name} & :expected = :expected", expected: bitstring)
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
58
|
def _enummer_method_name(attribute_name, value_name, options)
|
58
59
|
prefix = _enummer_affix(attribute_name, options[:_prefix])
|
59
60
|
suffix = _enummer_affix(attribute_name, options[:_suffix])
|
data/lib/enummer/version.rb
CHANGED
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:
|
4
|
+
version: 1.0.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-
|
11
|
+
date: 2022-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 7.0.0
|
27
|
-
description: Enummer implements multi-value enums with
|
27
|
+
description: Enummer implements multi-value enums with bitwise operations.
|
28
28
|
email:
|
29
29
|
- jamie@schembri.me
|
30
30
|
executables: []
|
@@ -55,7 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements:
|
56
56
|
- - ">="
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version: '
|
58
|
+
version: '2.7'
|
59
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
@@ -65,5 +65,5 @@ requirements: []
|
|
65
65
|
rubygems_version: 3.3.3
|
66
66
|
signing_key:
|
67
67
|
specification_version: 4
|
68
|
-
summary: Multi-value enums for Rails
|
68
|
+
summary: Multi-value enums for Rails.
|
69
69
|
test_files: []
|