swifter_enum 0.9.0 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -2
- data/README.md +71 -30
- data/Rakefile +29 -0
- data/lib/swifter_enum/base.rb +23 -3
- data/lib/swifter_enum/generators/enum/templates/enum.rb.tt +7 -5
- data/lib/swifter_enum/swifter_enum.rb +1 -1
- data/lib/swifter_enum/swifter_enum_validator.rb +7 -2
- data/lib/swifter_enum/version.rb +1 -1
- metadata +19 -6
- data/swifter_enum.gemspec +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4147b58f08c0633761d7721503972bf4478d7b6295a634186810ebe146416bf8
|
4
|
+
data.tar.gz: 9fa17a88143342a5637866c8ac599a5bc9adb6e7ff3f28293aefac6957ef3767
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c322303bcf61cd899f66b0e444de08a4d4826cc787d2ef5fa53bda9f81b15130d4da4b6d63455c1215f5ef14b3cb523ac6112b8d62d4f61da069336e3d69c5e0
|
7
|
+
data.tar.gz: 7e53b29f10e6908f3f9bf3f282c98d6e40f9a5c6bd5103d1beee337870c2ac53430cc3c0d0818c021731178c19e236d261573aa65fe6ce9b0d1a1b9624563e8a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# SwifterEnum
|
2
2
|
|
3
3
|
SwifterEnum is a Ruby gem for creating enumerated types (enums) in Ruby on Rails applications.
|
4
|
-
It is inspired by Swift's enums, and allows for more expressive and feature-rich enums in your models.
|
5
4
|
|
6
|
-
|
5
|
+
It is inspired by Swift's enums, and allows you to keep logic related to your enum directly in your enum class.
|
7
6
|
|
8
7
|
so - after defining
|
9
8
|
|
@@ -14,7 +13,41 @@ so - after defining
|
|
14
13
|
you can then define and access methods on your enum like
|
15
14
|
|
16
15
|
`video.camera.icon`
|
17
|
-
|
16
|
+
|
17
|
+
This avoids helper methods which distribute your enum logic around your application.
|
18
|
+
|
19
|
+
**Before**
|
20
|
+
|
21
|
+
helper method somewhere in the app
|
22
|
+
|
23
|
+
#app/helpers/controller_helper.rb
|
24
|
+
|
25
|
+
def icon_for(camera:)
|
26
|
+
...
|
27
|
+
end
|
28
|
+
|
29
|
+
called with
|
30
|
+
|
31
|
+
icon_for(camera:my_model.camera)
|
32
|
+
|
33
|
+
**After**
|
34
|
+
|
35
|
+
logic encapsluated within the enum class
|
36
|
+
|
37
|
+
#app/models/swifter_enum/camera_enum.rb
|
38
|
+
class CameraEnum < SwifterEnum::Base
|
39
|
+
set_values ({ videographer: 0, handcam: 1 })
|
40
|
+
|
41
|
+
def icon
|
42
|
+
...
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
called with
|
47
|
+
|
48
|
+
my_model.camera.icon
|
49
|
+
|
50
|
+
I was prompted to create this gem by reading about enum approaches in [the RailsNotes Newsletter](https://railsnotes.beehiiv.com/p/issue-17-enums-value-objects-field-guide-enum-sort-in-order-of). Like any good programmer, none of those solutions *quite* met my requirements. Hopefully it will be useful. I welcome feedback, fixes and pull requests.
|
18
51
|
|
19
52
|
|
20
53
|
## Installation
|
@@ -23,16 +56,14 @@ Add this line to your application's Gemfile:
|
|
23
56
|
|
24
57
|
gem 'swifter_enum'
|
25
58
|
|
26
|
-
And then execute:
|
27
|
-
|
28
|
-
bundle install
|
29
|
-
|
30
59
|
## Usage
|
31
60
|
|
32
61
|
### Overview
|
33
62
|
|
34
63
|
|
35
|
-
SwifterEnums act like a normal Rails enum - except that instead of returning
|
64
|
+
SwifterEnums act like a normal Rails enum - except that instead of returning string values, they return an instance of your selected class.
|
65
|
+
|
66
|
+
They also have various affordances so that in many cases, you can treat them as if they return symbol values.
|
36
67
|
|
37
68
|
We have a Video ActiveModel with an enum defined by
|
38
69
|
|
@@ -43,9 +74,7 @@ We have a Video ActiveModel with an enum defined by
|
|
43
74
|
CameraEnum is a class like the following
|
44
75
|
|
45
76
|
class CameraEnum < SwifterEnum::Base
|
46
|
-
|
47
|
-
{ videographer: 0, handcam: 1 }.freeze
|
48
|
-
end
|
77
|
+
set_values ({ videographer: 0, handcam: 1 })
|
49
78
|
|
50
79
|
def icon
|
51
80
|
case @value
|
@@ -92,9 +121,7 @@ Models are by convention stored in `/models/swifter_enum/your_model_enum.rb`
|
|
92
121
|
Example:
|
93
122
|
|
94
123
|
class CameraEnum < SwifterEnum::Base
|
95
|
-
|
96
|
-
{ videographer: 0, handcam: 1 }.freeze
|
97
|
-
end
|
124
|
+
set_values ({ videographer: 0, handcam: 1 })
|
98
125
|
|
99
126
|
def icon
|
100
127
|
case @value
|
@@ -135,24 +162,24 @@ run the generator to create an appropriate enum class
|
|
135
162
|
Insert the values of your enum into `models/swifter_enum_album_status_enum.rb`
|
136
163
|
|
137
164
|
class AlbumStatusEnum < SwifterEnum::Base
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
}.freeze
|
149
|
-
end
|
165
|
+
set_values ({
|
166
|
+
waiting_for_footage: 0,
|
167
|
+
waiting_for_upload: 10,
|
168
|
+
uploading: 20,
|
169
|
+
processing_preview: 24,
|
170
|
+
delivered_preview: 26,
|
171
|
+
processing_paid: 30,
|
172
|
+
delivered_paid: 50,
|
173
|
+
processing_failed: 60
|
174
|
+
})
|
150
175
|
end
|
151
176
|
|
152
177
|
Now replace the definition in your model file with
|
153
178
|
|
154
179
|
swifter_enum :album_status, AlbumStatusEnum, prefix: true
|
155
180
|
|
181
|
+
(note - prefix: optional. I'm adding it here because it was an option I used on my original standard Rails enum)
|
182
|
+
|
156
183
|
Optionally, add
|
157
184
|
|
158
185
|
validates :album_status, swifter_enum: true
|
@@ -205,10 +232,7 @@ For example, to create a `CameraEnum`, run:
|
|
205
232
|
This command will generate a file `app/models/swifter_enum/camera_enum.rb` with the following structure:
|
206
233
|
|
207
234
|
class CameraEnum < SwifterEnum::Base
|
208
|
-
|
209
|
-
# Insert your values here. e.g. { foo: 1, bar: 2 }.freeze
|
210
|
-
{ }.freeze
|
211
|
-
end
|
235
|
+
set_values <<Your Values Here>>
|
212
236
|
end
|
213
237
|
|
214
238
|
After generating your enum, you can add your specific enum values and use it in your ActiveRecord models.
|
@@ -229,6 +253,23 @@ Locale file example (`config/locales/en.yml`):
|
|
229
253
|
#example usage
|
230
254
|
v.camera.t => "Videographer"
|
231
255
|
|
256
|
+
### Using string values to store Enum
|
257
|
+
|
258
|
+
DHH has described using integer values for enums as a mistake he regrets.
|
259
|
+
|
260
|
+
He has shown code like
|
261
|
+
|
262
|
+
enum direction: %w[ up down left right ].index_by(&:itself)
|
263
|
+
|
264
|
+
which uses string values in the db by generating the hash `{"up"=>"up", "down"=>"down", "left"=>"left", "right"=>"right"}`
|
265
|
+
|
266
|
+
Swifter enum allows the same - but lets you simply set your values using an array of strings or symbols
|
267
|
+
|
268
|
+
set_values %w[ up down left right]
|
269
|
+
#or
|
270
|
+
set_values [:up,:down,:left,:right]
|
271
|
+
|
272
|
+
|
232
273
|
### Raw Value Escape Hatch
|
233
274
|
|
234
275
|
SwifterEnum is built on top of the normal Rails enum functionality.
|
data/Rakefile
CHANGED
@@ -12,4 +12,33 @@ Rake::TestTask.new do |t|
|
|
12
12
|
t.verbose = true
|
13
13
|
end
|
14
14
|
|
15
|
+
# publish with rake release:publish
|
16
|
+
namespace :release do
|
17
|
+
desc "Read version, build gem, tag and push release"
|
18
|
+
task :publish do
|
19
|
+
# Read version
|
20
|
+
version_file_path = File.expand_path("../lib/swifter_enum/version.rb", __FILE__)
|
21
|
+
version_file_content = File.read(version_file_path)
|
22
|
+
version_match = version_file_content.match(/VERSION = "(\d+\.\d+\.\d+)"/)
|
23
|
+
unless version_match
|
24
|
+
puts "Version could not be found in #{version_file_path}"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
version = version_match[1]
|
28
|
+
gem_name = "swifter_enum-#{version}.gem"
|
29
|
+
|
30
|
+
# Build gem
|
31
|
+
Rake::Task["build"].invoke
|
32
|
+
|
33
|
+
# Git tag
|
34
|
+
system("git add .")
|
35
|
+
system("git commit -m 'Release version #{version}'")
|
36
|
+
system("git tag -a #{version} -m 'Version #{version} release'")
|
37
|
+
system("git push origin main --tags")
|
38
|
+
|
39
|
+
# Push gem to RubyGems
|
40
|
+
system("gem push pkg/#{gem_name}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
15
44
|
task default: [:standard, :test]
|
data/lib/swifter_enum/base.rb
CHANGED
@@ -1,11 +1,31 @@
|
|
1
1
|
module SwifterEnum
|
2
2
|
class Base
|
3
|
-
|
3
|
+
class << self
|
4
|
+
attr_accessor :values
|
5
|
+
|
6
|
+
def set_values(input)
|
7
|
+
case input
|
8
|
+
when Hash
|
9
|
+
@values = input
|
10
|
+
when Array
|
11
|
+
validate_array_elements!(input)
|
12
|
+
@values = input.map { |item| [item.to_sym, item.to_s] }.to_h
|
13
|
+
else
|
14
|
+
raise ArgumentError, "Input must be a Hash or an Array of symbols or strings"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
4
19
|
|
5
|
-
|
6
|
-
|
20
|
+
def validate_array_elements!(array)
|
21
|
+
unless array.all? { |item| item.is_a?(Symbol) || item.is_a?(String) }
|
22
|
+
raise ArgumentError, "Array elements must all be symbols or strings"
|
23
|
+
end
|
24
|
+
end
|
7
25
|
end
|
8
26
|
|
27
|
+
attr_reader :value
|
28
|
+
|
9
29
|
def initialize(value)
|
10
30
|
@value = value&.to_sym
|
11
31
|
end
|
@@ -3,12 +3,14 @@
|
|
3
3
|
|
4
4
|
class <%= class_name %>Enum < SwifterEnum::Base
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
#set your values using a hash, or array of symbols
|
7
|
+
#if you're using a hash with symbol:integer, then your database column should be of integer type
|
8
|
+
# e.g. set_values ({active: 10, inactive: 20})
|
9
|
+
# or set_values active: 10, inactive: 20
|
10
|
+
#if you're using an array of symbols (or strings), then your database column should be of string type
|
11
|
+
# e.g. set_values [:active,:passive]
|
9
12
|
|
10
|
-
|
11
|
-
end
|
13
|
+
set_values <<Your Values Here>>
|
12
14
|
|
13
15
|
# you can now define methods on the enum
|
14
16
|
# this would allow you to access YourModel.<%= file_name %>.squared
|
@@ -6,7 +6,7 @@ module SwifterEnum
|
|
6
6
|
class_methods do
|
7
7
|
def swifter_enum(enum_name, enum_klass, enum_options = {})
|
8
8
|
# Define the enum using values from the enum class
|
9
|
-
enum(enum_name
|
9
|
+
enum(enum_name, enum_klass.values, **enum_options)
|
10
10
|
|
11
11
|
# Define getter method
|
12
12
|
define_method(enum_name) do
|
@@ -3,13 +3,18 @@ require "active_model"
|
|
3
3
|
module SwifterEnum
|
4
4
|
class SwifterEnumValidator < ActiveModel::EachValidator
|
5
5
|
def validate_each(record, attribute, a_value)
|
6
|
-
return if options[:allow_nil] && a_value.nil?
|
7
|
-
|
8
6
|
if !a_value.is_a?(SwifterEnum::Base) || a_value.instance_of?(SwifterEnum::Base)
|
9
7
|
record.errors.add(attribute, "#{a_value.value} is not a valid subclass of SwifterEnum")
|
10
8
|
end
|
11
9
|
|
10
|
+
if a_value.value.nil?
|
11
|
+
return if options[:allow_nil]
|
12
|
+
|
13
|
+
record.errors.add(attribute, "nil value for #{attribute} is not allowed")
|
14
|
+
end
|
15
|
+
|
12
16
|
unless a_value.class.values.key?(a_value.value)
|
17
|
+
# binding.b
|
13
18
|
record.errors.add(attribute, "#{a_value.value} is not a valid #{attribute} type")
|
14
19
|
end
|
15
20
|
end
|
data/lib/swifter_enum/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swifter_enum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Jonson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,10 +80,24 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '5.22'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: debug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
description: Simple enum for active record that takes inspiration from Swift's enums
|
84
|
-
to allow you to
|
85
|
-
replacement for regular rails enums, with minimal changes required. Once you
|
86
|
-
then you can easily extend your enums with methods.
|
98
|
+
to allow you to encapsulate enum logic within an enum class. This is easy to drop-in
|
99
|
+
as a replacement for regular rails enums, with minimal changes required. Once you
|
100
|
+
switch, then you can easily extend your enums with methods.
|
87
101
|
email:
|
88
102
|
- rob@hobbyistsoftware.com
|
89
103
|
executables: []
|
@@ -104,7 +118,6 @@ files:
|
|
104
118
|
- lib/swifter_enum/swifter_enum_validator.rb
|
105
119
|
- lib/swifter_enum/version.rb
|
106
120
|
- sig/swifter_enum.rbs
|
107
|
-
- swifter_enum.gemspec
|
108
121
|
homepage: https://github.com/ConfusedVorlon/SwifterEnum
|
109
122
|
licenses:
|
110
123
|
- MIT
|
data/swifter_enum.gemspec
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "lib/swifter_enum/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "swifter_enum"
|
7
|
-
spec.version = SwifterEnum::VERSION
|
8
|
-
spec.authors = ["Rob Jonson"]
|
9
|
-
spec.email = ["rob@hobbyistsoftware.com"]
|
10
|
-
|
11
|
-
spec.summary = "Active Record enum that uses a class, so you can add methods."
|
12
|
-
spec.description = "Simple enum for active record that takes inspiration from Swift's enums to allow you to add logic to your enum definition. This is easy to drop-in as a replacement for regular rails enums, with minimal changes required. Once you switch, then you can easily extend your enums with methods."
|
13
|
-
spec.homepage = "https://github.com/ConfusedVorlon/SwifterEnum"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
#I'm using 3.2 and above. If you're willing/able to test on lower rubies, then please let me know and feel free to change this.
|
17
|
-
spec.required_ruby_version = ">= 3.2.0"
|
18
|
-
|
19
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
-
spec.metadata["source_code_uri"] = "https://github.com/ConfusedVorlon/SwifterEnum"
|
21
|
-
spec.metadata["changelog_uri"] = "https://github.com/ConfusedVorlon/SwifterEnum"
|
22
|
-
|
23
|
-
# Specify which files should be added to the gem when it is released.
|
24
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
-
spec.files = Dir.chdir(__dir__) do
|
26
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
27
|
-
(File.expand_path(f) == __FILE__) ||
|
28
|
-
f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
|
29
|
-
end
|
30
|
-
end
|
31
|
-
spec.bindir = "exe"
|
32
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
-
spec.require_paths = ["lib"]
|
34
|
-
|
35
|
-
spec.add_dependency "activerecord", "~> 7.0"
|
36
|
-
spec.add_dependency "activesupport", "~> 7.0"
|
37
|
-
spec.add_dependency "activemodel", "~> 7.0"
|
38
|
-
|
39
|
-
# Specify development dependencies
|
40
|
-
spec.add_development_dependency "sqlite3", "~> 1.4" # For using SQL
|
41
|
-
spec.add_development_dependency "minitest", "~> 5.22"
|
42
|
-
|
43
|
-
# For more information and examples about making a new gem, check out our
|
44
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
45
|
-
end
|