taylors_enum 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +58 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +72 -0
- data/LICENSE.txt +21 -0
- data/README.md +176 -0
- data/Rakefile +16 -0
- data/lib/taylors_enum/active_record/active_record.rb +7 -0
- data/lib/taylors_enum/active_record/taylors_enum.rb +157 -0
- data/lib/taylors_enum/version.rb +5 -0
- data/lib/taylors_enum.rb +11 -0
- data/sig/taylors_enum.rbs +4 -0
- data/taylors_enum.gemspec +40 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 22eddc0a8e5096da1be305ffcaf244c99e9cd53f502acf7d5d3827d64ceb5781
|
4
|
+
data.tar.gz: 9dcbda215ceb54dc6aef75950ad45dfa8da07e20c88ac456f1aac22804f0c5e6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c8cd3171a1e074a18550b8055ba93cb008f636ac9d350dddbe7387a9e4d5848fc00565aeff7fb6a9382fffa3afa555e7f1e27033de0ebc53cbb525677390a7f
|
7
|
+
data.tar.gz: d672df8ce78450646179c625f27e596a74e9118f64140db5addf70b6c1d933049a3d368a143742222c9f5b15e8b7a5d076582b09a8c64de286e06de35701f4c5
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.6
|
3
|
+
|
4
|
+
Style/StringLiterals:
|
5
|
+
Enabled: true
|
6
|
+
EnforcedStyle: single_quotes
|
7
|
+
|
8
|
+
Style/StringLiteralsInInterpolation:
|
9
|
+
Enabled: true
|
10
|
+
EnforcedStyle: single_quotes
|
11
|
+
|
12
|
+
Style/TrailingCommaInHashLiteral:
|
13
|
+
Enabled: true
|
14
|
+
EnforcedStyle: comma
|
15
|
+
|
16
|
+
Style/TrailingCommaInArguments:
|
17
|
+
Enabled: true
|
18
|
+
EnforcedStyleForMultiline: comma
|
19
|
+
|
20
|
+
Style/StderrPuts:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/Documentation:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/FrozenStringLiteralComment:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Style/FormatStringToken:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Layout/MultilineMethodCallIndentation:
|
33
|
+
Enabled: true
|
34
|
+
EnforcedStyle: indented
|
35
|
+
|
36
|
+
Layout/LineLength:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Metrics/BlockLength:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Metrics/ModuleLength:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Metrics/AbcSize:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Metrics/CyclomaticComplexity:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Metrics/MethodLength:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Metrics/PerceivedComplexity:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Metrics/ClassLength:
|
58
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
taylors_enum (0.1.0)
|
5
|
+
activesupport (>= 4.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (7.0.3)
|
11
|
+
activesupport (= 7.0.3)
|
12
|
+
activerecord (7.0.3)
|
13
|
+
activemodel (= 7.0.3)
|
14
|
+
activesupport (= 7.0.3)
|
15
|
+
activesupport (7.0.3)
|
16
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
+
i18n (>= 1.6, < 2)
|
18
|
+
minitest (>= 5.1)
|
19
|
+
tzinfo (~> 2.0)
|
20
|
+
ast (2.4.2)
|
21
|
+
byebug (11.1.3)
|
22
|
+
coderay (1.1.3)
|
23
|
+
concurrent-ruby (1.1.10)
|
24
|
+
i18n (1.10.0)
|
25
|
+
concurrent-ruby (~> 1.0)
|
26
|
+
method_source (1.0.0)
|
27
|
+
minitest (5.15.0)
|
28
|
+
parallel (1.22.1)
|
29
|
+
parser (3.1.2.0)
|
30
|
+
ast (~> 2.4.1)
|
31
|
+
pg (1.2.3)
|
32
|
+
pry (0.13.1)
|
33
|
+
coderay (~> 1.1)
|
34
|
+
method_source (~> 1.0)
|
35
|
+
pry-byebug (3.9.0)
|
36
|
+
byebug (~> 11.0)
|
37
|
+
pry (~> 0.13.0)
|
38
|
+
rainbow (3.1.1)
|
39
|
+
rake (13.0.6)
|
40
|
+
regexp_parser (2.5.0)
|
41
|
+
rexml (3.2.5)
|
42
|
+
rubocop (1.30.0)
|
43
|
+
parallel (~> 1.10)
|
44
|
+
parser (>= 3.1.0.0)
|
45
|
+
rainbow (>= 2.2.2, < 4.0)
|
46
|
+
regexp_parser (>= 1.8, < 3.0)
|
47
|
+
rexml (>= 3.2.5, < 4.0)
|
48
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
49
|
+
ruby-progressbar (~> 1.7)
|
50
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
51
|
+
rubocop-ast (1.18.0)
|
52
|
+
parser (>= 3.1.1.0)
|
53
|
+
ruby-progressbar (1.11.0)
|
54
|
+
tzinfo (2.0.4)
|
55
|
+
concurrent-ruby (~> 1.0)
|
56
|
+
unicode-display_width (2.1.0)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
arm64-darwin-21
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
activerecord (>= 4.2)
|
63
|
+
minitest (~> 5.0)
|
64
|
+
pg (~> 1.2.0)
|
65
|
+
pry
|
66
|
+
pry-byebug (~> 3.9.0)
|
67
|
+
rake (~> 13.0)
|
68
|
+
rubocop (~> 1.21)
|
69
|
+
taylors_enum!
|
70
|
+
|
71
|
+
BUNDLED WITH
|
72
|
+
2.3.11
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 PJ
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# TaylorsEnum
|
2
|
+
|
3
|
+
TaylorsEnum is a gem that builds on top of ActiveRecord's built in [enums](https://api.rubyonrails.org/v5.2.4.4/classes/ActiveRecord/Enum.html#method-i-enum). Specifically, it will:
|
4
|
+
|
5
|
+
###### - Define additional methods to make it clearer which values exist in Rails-land, and which in the database
|
6
|
+
In Rails:
|
7
|
+
```
|
8
|
+
class Album < ActiveRecord::Base
|
9
|
+
self.table_name = 'albums'
|
10
|
+
enum name: %w[debut fearless speak_now red nineteen_eighty_nine reputation lover folklore evermore]
|
11
|
+
end
|
12
|
+
|
13
|
+
[1] pry(#<TestDefault>)> Album.names
|
14
|
+
=> {"debut"=>0, "fearless"=>1, "speak_now"=>2, "red"=>3, "nineteen_eighty_nine"=>4, "reputation"=>5, "lover"=>6, "folklore"=>7, "evermore"=>8}
|
15
|
+
```
|
16
|
+
|
17
|
+
With TaylorsEnum:
|
18
|
+
```
|
19
|
+
class AlbumBase < Album
|
20
|
+
taylors_enum name: %w[debut fearless speak_now red nineteen_eighty_nine reputation lover folklore evermore]
|
21
|
+
end
|
22
|
+
|
23
|
+
[2] pry(#<TestDefault>)> AlbumBase.name_rails_values
|
24
|
+
=> ["debut", "fearless", "speak_now", "red", "nineteen_eighty_nine", "reputation", "lover", "folklore", "evermore"]
|
25
|
+
[3] pry(#<TestDefault>)> AlbumBase.name_database_values
|
26
|
+
=> ["debut", "fearless", "speak_now", "red", "nineteen_eighty_nine", "reputation", "lover", "folklore", "evermore"]
|
27
|
+
|
28
|
+
```
|
29
|
+
|
30
|
+
|
31
|
+
###### - Define constants for each value provided
|
32
|
+
```
|
33
|
+
class AlbumBase < Album
|
34
|
+
taylors_enum name: %w[debut fearless speak_now red nineteen_eighty_nine reputation lover folklore evermore]
|
35
|
+
end
|
36
|
+
|
37
|
+
[5] pry(#<TestDefault>)> AlbumBase::FOLKLORE
|
38
|
+
=> "folklore"
|
39
|
+
[6] pry(#<TestDefault>)> AlbumBase::EVERMORE
|
40
|
+
=> "evermore"
|
41
|
+
# etc.
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
###### - Enables support for all the enum goodness when enumerating classes for Single Table Inheritance
|
46
|
+
```
|
47
|
+
module SingleTableInheritanceAlbums
|
48
|
+
class SingleTableInheritanceAlbum < ActiveRecord::Base
|
49
|
+
self.table_name = 'single_table_inheritance_albums'
|
50
|
+
|
51
|
+
taylors_enum type: %w[
|
52
|
+
SingleTableInheritanceAlbums::Debut
|
53
|
+
SingleTableInheritanceAlbums::Fearless
|
54
|
+
SingleTableInheritanceAlbums::SpeakNow
|
55
|
+
SingleTableInheritanceAlbums::Red
|
56
|
+
SingleTableInheritanceAlbums::NineteenEightyNine
|
57
|
+
SingleTableInheritanceAlbums::Reputation
|
58
|
+
SingleTableInheritanceAlbums::Lover
|
59
|
+
SingleTableInheritanceAlbums::Folklore
|
60
|
+
SingleTableInheritanceAlbums::Evermore
|
61
|
+
], single_table_inheritance: true
|
62
|
+
end
|
63
|
+
|
64
|
+
class Debut < SingleTableInheritanceAlbum; end
|
65
|
+
class Fearless < SingleTableInheritanceAlbum; end
|
66
|
+
class SpeakNow < SingleTableInheritanceAlbum; end
|
67
|
+
class Red < SingleTableInheritanceAlbum; end
|
68
|
+
class NineteenEightyNine < SingleTableInheritanceAlbum; end
|
69
|
+
class Reputation < SingleTableInheritanceAlbum; end
|
70
|
+
class Lover < SingleTableInheritanceAlbum; end
|
71
|
+
class Folklore < SingleTableInheritanceAlbum; end
|
72
|
+
class Evermore < SingleTableInheritanceAlbum; end
|
73
|
+
end
|
74
|
+
|
75
|
+
[5] pry(#<TestSingleTableInheritance>)> album = ::SingleTableInheritanceAlbums::Debut.create
|
76
|
+
=> #<SingleTableInheritanceAlbums::Debut:0x000000010581a708 id: 2, type: "SingleTableInheritanceAlbums::Debut", created_at: 2022-06-04 14:34:24.951932 UTC, updated_at: 2022-06-04 14:34:24.951932 UTC>
|
77
|
+
[6] pry(#<TestSingleTableInheritance>)> album.type
|
78
|
+
=> "SingleTableInheritanceAlbums::Debut"
|
79
|
+
[7] pry(#<TestSingleTableInheritance>)> album.debut?
|
80
|
+
=> true
|
81
|
+
[8] pry(#<TestSingleTableInheritance>)> album.fearless!
|
82
|
+
=> true
|
83
|
+
[9] pry(#<TestSingleTableInheritance>)> album.debut?
|
84
|
+
=> false
|
85
|
+
[10] pry(#<TestSingleTableInheritance>)> album.fearless?
|
86
|
+
=> true
|
87
|
+
[11] pry(#<TestSingleTableInheritance>)> album.type
|
88
|
+
=> "SingleTableInheritanceAlbums::Fearless"
|
89
|
+
[12] pry(#<TestSingleTableInheritance>)> ::SingleTableInheritanceAlbums::SingleTableInheritanceAlbum.fearless
|
90
|
+
=> [#<SingleTableInheritanceAlbums::Fearless:0x00000001059821e0 id: 1, type: "SingleTableInheritanceAlbums::Fearless", created_at: 2022-06-04 14:33:55.178418 UTC, updated_at: 2022-06-04 14:33:55.178418 UTC>,
|
91
|
+
#<SingleTableInheritanceAlbums::Fearless:0x0000000105981a10 id: 2, type: "SingleTableInheritanceAlbums::Fearless", created_at: 2022-06-04 14:34:24.951932 UTC, updated_at: 2022-06-04 14:34:50.616316 UTC>]
|
92
|
+
[13] pry(#<TestSingleTableInheritance>)> ::SingleTableInheritanceAlbums::SingleTableInheritanceAlbum.fearless.to_sql
|
93
|
+
=> "SELECT \"single_table_inheritance_albums\".* FROM \"single_table_inheritance_albums\" WHERE \"single_table_inheritance_albums\".\"type\" = 'SingleTableInheritanceAlbums::Fearless'"
|
94
|
+
```
|
95
|
+
|
96
|
+
###### - Enables support for all the enum goodness when enumerating classes for Polymorphic Associations
|
97
|
+
Note: this excludes the `<attribute>!` method to update a value, as, as I write this, I can't conceive of a scenario in which you'd want to update just the type, and not also the ID, of an associated object. If you want to do this, you can still do this manually via the `ActiveRecord#update` method.
|
98
|
+
|
99
|
+
```
|
100
|
+
class Award < ActiveRecord::Base
|
101
|
+
self.table_name = 'awards'
|
102
|
+
belongs_to :awardable, polymorphic: true
|
103
|
+
taylors_enum awardable_type: %w[Album Song], polymorphic: true
|
104
|
+
end
|
105
|
+
|
106
|
+
[1] pry(#<TestPolymorphic>)> song = Song.create!
|
107
|
+
=> #<Song:0x0000000105beddd0 id: 1, name: nil, created_at: 2022-06-04 14:39:38.837973 UTC, updated_at: 2022-06-04 14:39:38.837973 UTC>
|
108
|
+
[2] pry(#<TestPolymorphic>)> album = AlbumBase.create!(name: :folklore)
|
109
|
+
=> #<AlbumBase:0x0000000105c36c10 id: 1, name: "folklore", created_at: 2022-06-04 14:39:43.001592 UTC, updated_at: 2022-06-04 14:39:43.001592 UTC>
|
110
|
+
[3] pry(#<TestPolymorphic>)> song_award = Award.create!(awardable: song)
|
111
|
+
=> #<Award:0x0000000105c77030 id: 1, awardable_type: "Song", awardable_id: "1", created_at: 2022-06-04 14:39:46.714235 UTC, updated_at: 2022-06-04 14:39:46.714235 UTC>
|
112
|
+
[4] pry(#<TestPolymorphic>)> album_award = Award.create!(awardable: album)
|
113
|
+
=> #<Award:0x0000000105cb4ac0 id: 2, awardable_type: "Album", awardable_id: "1", created_at: 2022-06-04 14:39:49.444071 UTC, updated_at: 2022-06-04 14:39:49.444071 UTC>
|
114
|
+
[5] pry(#<TestPolymorphic>)> song_award.song?
|
115
|
+
=> true
|
116
|
+
[6] pry(#<TestPolymorphic>)> song_award.album?
|
117
|
+
=> false
|
118
|
+
[7] pry(#<TestPolymorphic>)> album_award.song?
|
119
|
+
=> false
|
120
|
+
[8] pry(#<TestPolymorphic>)> album_award.album?
|
121
|
+
=> true
|
122
|
+
[9] pry(#<TestPolymorphic>)> Award.song
|
123
|
+
=> [#<Award:0x0000000105dbfca8 id: 1, awardable_type: "Song", awardable_id: "1", created_at: 2022-06-04 14:39:46.714235 UTC, updated_at: 2022-06-04 14:39:46.714235 UTC>]
|
124
|
+
[10] pry(#<TestPolymorphic>)> Award.song.to_sql
|
125
|
+
=> "SELECT \"awards\".* FROM \"awards\" WHERE \"awards\".\"awardable_type\" = 'Song'"
|
126
|
+
```
|
127
|
+
|
128
|
+
|
129
|
+
## Installation
|
130
|
+
|
131
|
+
Install the gem and add to the application's Gemfile by executing:
|
132
|
+
|
133
|
+
$ bundle add taylors_enum
|
134
|
+
|
135
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
136
|
+
|
137
|
+
$ gem install taylors_enum
|
138
|
+
|
139
|
+
## Usage
|
140
|
+
|
141
|
+
Using taylors_enum is simple! Once the gem is installed, just add `taylors_enum <my_column>: ['array', 'of', 'values']` to any model that ultimately inherits from `ActiveRecord::Base`.
|
142
|
+
|
143
|
+
The values that you pass will be the values that are stored in the database. taylors_enum will then generate a companion for each value that will be used to define constants, `?` methods to check if an object has the given value in the specified column, `!` methods to update the column to that value, and scopes to query for records with that value. See the top of this README for what this looks like in practice.
|
144
|
+
|
145
|
+
taylors_enum also takes a series of options, provided as a hash:
|
146
|
+
- `prefix`: defaults to `nil`. If `true` is passed, the name of the column will be prepended to the start of the helper methods, scopes, and constants. If a string is passed, the given string will be prepended to the start of the helper methods, scopes, and constants.
|
147
|
+
|
148
|
+
- `suffix`: defaults to `nil`. If `true` is passed, the name of the column will be appended to the end of the helper methods, scopes, and constants. If a string is passed, the given string will be appended to the end of the helper methods, scopes, and constants.
|
149
|
+
|
150
|
+
- `constants`: defaults to `true`. If `false` is passed, constants will not be defined. This can be helpful for migrating onto taylors_enum, if you already have constants defined for certain enum values.
|
151
|
+
|
152
|
+
- `validations`: defaults to `true`. If `false` is passed, validations, `nil` will be allowed as a value in the specified column.
|
153
|
+
|
154
|
+
- `single_table_inheritance`: defaults to `false`. When using taylors_enum to help with columns on [Single Table Inheritance](https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html) models, pass this value as `true`, otherwise things won't work, and then you'll be sad.
|
155
|
+
|
156
|
+
- `polymorphic`: defaults to `false`. When using taylors_enum to help with type columns for [polymorphic associations](https://guides.rubyonrails.org/association_basics.html#polymorphic-associations), pass this value as `true`; this will ensure validations are run correctly, against database values rather than Rails values, and will also not create a `!` method to update the value of the column.
|
157
|
+
|
158
|
+
If you want to see the base Rails value that will be used to generate the `value?` and `value!` methods, that `VALUE` constants, and the `value` scopes, you can load
|
159
|
+
|
160
|
+
## Development
|
161
|
+
|
162
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
163
|
+
|
164
|
+
You'll also need to have a working database in order to run the tests. First, make sure you have [Postgres](https://www.postgresql.org/) installed. You can easily do this on a Mac with [Homebrew](https://wiki.postgresql.org/wiki/Homebrew).
|
165
|
+
|
166
|
+
From there, run `createdb taylors_enum` in the terminal to create a database with the required name. Then, run `psql taylors_enum` to open a terminal to that database, and run `create user postgres;` to create a user with the correct username for the test suite to connect to it. The database connection config is specified in `test/database.yml`
|
167
|
+
|
168
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
169
|
+
|
170
|
+
## Contributing
|
171
|
+
|
172
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/isitpj/taylors_enum.
|
173
|
+
|
174
|
+
## License
|
175
|
+
|
176
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/test_*.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubocop/rake_task'
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module TaylorsEnum
|
2
|
+
module ActiveRecord
|
3
|
+
module TaylorsEnum
|
4
|
+
module ClassMethods
|
5
|
+
DEFAULT_OPTIONS = {
|
6
|
+
prefix: nil, # can be true, false, or a string; if true, will use the column_name as the default value
|
7
|
+
suffix: nil, # can be true, false, or a string; if true, will use the column_name as the default value
|
8
|
+
constants: true, # can be true or false
|
9
|
+
validations: true, # can be true or false; TODO: allow a hash of validations args to be passed
|
10
|
+
single_table_inheritance: false,
|
11
|
+
polymorphic: false,
|
12
|
+
column: nil # this is set by the first argument passed to taylors_enum
|
13
|
+
}.with_indifferent_access.freeze
|
14
|
+
|
15
|
+
def taylors_enum(**enum_args)
|
16
|
+
enum_args, *options = *enum_args
|
17
|
+
enum_column, raw_values = *enum_args
|
18
|
+
|
19
|
+
options = DEFAULT_OPTIONS
|
20
|
+
.merge(**options.to_h)
|
21
|
+
.merge(column: enum_column)
|
22
|
+
.with_indifferent_access
|
23
|
+
|
24
|
+
values = format_values(raw_values, options: options)
|
25
|
+
|
26
|
+
define_list_methods!(values, column: enum_column)
|
27
|
+
|
28
|
+
define_constants!(values) if options[:constants].present?
|
29
|
+
|
30
|
+
# NOTE: when relying on the default rails enum, we validate against the rails-side values, as enum does its own custom validation; however, taylors_enum validates against the database-side values, as it relies on active_record validations
|
31
|
+
values_to_validate = options[:single_table_inheritance] || options[:polymorphic] ? values.values : values.keys
|
32
|
+
enforce_validations!(values: values_to_validate, column: enum_column) if options[:validations].present?
|
33
|
+
|
34
|
+
if options[:single_table_inheritance]
|
35
|
+
manually_define_single_table_inheritance_enum_methods(values, column: enum_column)
|
36
|
+
elsif options[:polymorphic]
|
37
|
+
manually_define_polymorphic_enum_methods(values, column: enum_column)
|
38
|
+
else
|
39
|
+
enum(enum_column => values) unless options[:single_table_inheritance]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_rails_value_for(database_value, column: nil, prefix: nil, suffix: nil)
|
44
|
+
format_values(
|
45
|
+
[database_value],
|
46
|
+
options: {
|
47
|
+
column: column,
|
48
|
+
prefix: prefix,
|
49
|
+
suffix: suffix
|
50
|
+
},
|
51
|
+
).keys.first
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def manually_define_single_table_inheritance_enum_methods(values, column:)
|
57
|
+
values.each do |rails_value, database_value|
|
58
|
+
define_boolean_method(rails_value, database_value, column)
|
59
|
+
define_update_method(rails_value, database_value, column)
|
60
|
+
define_scope(rails_value, database_value, column)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# NOTE: skip defining the update method for polymorphic, as it makes little sense to update the associated type without also updating the corresponding id
|
65
|
+
def manually_define_polymorphic_enum_methods(values, column:)
|
66
|
+
values.each do |rails_value, database_value|
|
67
|
+
define_boolean_method(rails_value, database_value, column)
|
68
|
+
define_scope(rails_value, database_value, column)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# def active?() status == "active" end
|
73
|
+
def define_boolean_method(rails_value, database_value, column)
|
74
|
+
method_name = "#{rails_value}?"
|
75
|
+
detect_method_conflict(column, method_name, class_method: false)
|
76
|
+
define_method(method_name) { self[column] == database_value }
|
77
|
+
end
|
78
|
+
|
79
|
+
# def active!() update!(status: :active) end
|
80
|
+
def define_update_method(rails_value, database_value, column)
|
81
|
+
method_name = "#{rails_value}!"
|
82
|
+
detect_method_conflict(column, method_name, class_method: false)
|
83
|
+
define_method(method_name) { update!(column => database_value) }
|
84
|
+
end
|
85
|
+
|
86
|
+
# scope :active, -> { where(status: :active) }
|
87
|
+
def define_scope(rails_value, database_value, column)
|
88
|
+
method_name = rails_value
|
89
|
+
detect_method_conflict(column, method_name, class_method: true)
|
90
|
+
scope method_name, -> { where(column => database_value) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def detect_method_conflict(column, method_name, class_method:)
|
94
|
+
send(
|
95
|
+
:detect_enum_conflict!,
|
96
|
+
column,
|
97
|
+
method_name,
|
98
|
+
class_method,
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def define_list_methods!(values, column:)
|
103
|
+
define_singleton_method("#{column}_rails_values") do
|
104
|
+
values.keys
|
105
|
+
end
|
106
|
+
|
107
|
+
define_singleton_method("#{column}_database_values") do
|
108
|
+
values.values
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def define_constants!(values)
|
113
|
+
values.each do |rails_value, database_value|
|
114
|
+
const_set(rails_value.upcase, database_value)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def enforce_validations!(values:, column:)
|
119
|
+
validates column, presence: true, inclusion: { in: values, message: "%{value} is not a valid #{column}" }
|
120
|
+
end
|
121
|
+
|
122
|
+
def format_values(values, options:)
|
123
|
+
prefix = generate_prefix_name(options[:prefix], column: options[:column])
|
124
|
+
suffix = generate_suffix_name(options[:suffix], column: options[:column])
|
125
|
+
|
126
|
+
values.map do |value|
|
127
|
+
formatted_value = value.to_s.demodulize.underscore
|
128
|
+
[
|
129
|
+
"#{prefix}#{formatted_value}#{suffix}",
|
130
|
+
value
|
131
|
+
]
|
132
|
+
end.to_h
|
133
|
+
end
|
134
|
+
|
135
|
+
def generate_prefix_name(prefix, column:)
|
136
|
+
enum_prefix = generate_nfix_name(prefix, column: column)
|
137
|
+
enum_prefix.present? ? "#{enum_prefix}_" : ''
|
138
|
+
end
|
139
|
+
|
140
|
+
def generate_suffix_name(suffix, column:)
|
141
|
+
enum_suffix = generate_nfix_name(suffix, column: column)
|
142
|
+
enum_suffix.present? ? "_#{enum_suffix}" : ''
|
143
|
+
end
|
144
|
+
|
145
|
+
def generate_nfix_name(nfix, column:)
|
146
|
+
if nfix == true
|
147
|
+
column
|
148
|
+
elsif nfix
|
149
|
+
nfix
|
150
|
+
else
|
151
|
+
''
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/taylors_enum.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'taylors_enum/version'
|
4
|
+
|
5
|
+
module TaylorsEnum
|
6
|
+
class Error < StandardError; end
|
7
|
+
require 'active_support'
|
8
|
+
require 'active_support/core_ext/hash'
|
9
|
+
require 'taylors_enum/active_record/active_record'
|
10
|
+
require 'taylors_enum/active_record/taylors_enum'
|
11
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/taylors_enum/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'taylors_enum'
|
7
|
+
spec.version = TaylorsEnum::VERSION
|
8
|
+
spec.authors = ['Cassie Johnstone']
|
9
|
+
spec.email = ['peter.wdj@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'Better enums in Rails.'
|
12
|
+
spec.description = 'Helper methods around enumerable values in Rails, including enums, polymorphic associations, and single-table inheritance.'
|
13
|
+
spec.homepage = 'https://github.com/isitpj/taylors_enum'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 2.6.0'
|
16
|
+
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
18
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
19
|
+
spec.metadata['changelog_uri'] = 'https://github.com/isitpj/taylors_enum/blob/main/CHANGELOG.md'
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.bindir = 'exe'
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ['lib']
|
31
|
+
|
32
|
+
spec.add_dependency 'activesupport', '>= 4.2'
|
33
|
+
spec.add_development_dependency 'activerecord', '>= 4.2'
|
34
|
+
spec.add_development_dependency 'pg', '~> 1.2.0'
|
35
|
+
spec.add_development_dependency 'pry'
|
36
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.9.0'
|
37
|
+
|
38
|
+
# For more information and examples about making a new gem, check out our
|
39
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: taylors_enum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cassie Johnstone
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pg
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.2.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.9.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.9.0
|
83
|
+
description: Helper methods around enumerable values in Rails, including enums, polymorphic
|
84
|
+
associations, and single-table inheritance.
|
85
|
+
email:
|
86
|
+
- peter.wdj@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".rubocop.yml"
|
92
|
+
- CHANGELOG.md
|
93
|
+
- Gemfile
|
94
|
+
- Gemfile.lock
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- lib/taylors_enum.rb
|
99
|
+
- lib/taylors_enum/active_record/active_record.rb
|
100
|
+
- lib/taylors_enum/active_record/taylors_enum.rb
|
101
|
+
- lib/taylors_enum/version.rb
|
102
|
+
- sig/taylors_enum.rbs
|
103
|
+
- taylors_enum.gemspec
|
104
|
+
homepage: https://github.com/isitpj/taylors_enum
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata:
|
108
|
+
homepage_uri: https://github.com/isitpj/taylors_enum
|
109
|
+
source_code_uri: https://github.com/isitpj/taylors_enum
|
110
|
+
changelog_uri: https://github.com/isitpj/taylors_enum/blob/main/CHANGELOG.md
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 2.6.0
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubygems_version: 3.3.3
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Better enums in Rails.
|
130
|
+
test_files: []
|