swifter_enum 0.9.0 → 0.9.2

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: 4faeac3f2e6714d5af882726817712536924044c725a0aa252de4f0e89072f43
4
- data.tar.gz: 5c818c9815c9e4e5165475260ffd42b503b815ca7eb92307ea98a703b8c2a933
3
+ metadata.gz: 4147b58f08c0633761d7721503972bf4478d7b6295a634186810ebe146416bf8
4
+ data.tar.gz: 9fa17a88143342a5637866c8ac599a5bc9adb6e7ff3f28293aefac6957ef3767
5
5
  SHA512:
6
- metadata.gz: 813389dc72d261ac9aa903484829009f8853ce4a0e6c017f8529996f2816858bdd13b4e5294f10b6a1c6dd93d3c1341e5c4e9a651f6b14712bf8fdddf49255a9
7
- data.tar.gz: 39941760574f2ac9438ab61537273ed593e0a813200169dcdb68f863251992b8973aada7f3b094ef0aeb6182e7f87fe5bd30d61303bbd643e5bb0313a7f0e1c5
6
+ metadata.gz: c322303bcf61cd899f66b0e444de08a4d4826cc787d2ef5fa53bda9f81b15130d4da4b6d63455c1215f5ef14b3cb523ac6112b8d62d4f61da069336e3d69c5e0
7
+ data.tar.gz: 7e53b29f10e6908f3f9bf3f282c98d6e40f9a5c6bd5103d1beee337870c2ac53430cc3c0d0818c021731178c19e236d261573aa65fe6ce9b0d1a1b9624563e8a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
- ## [Unreleased]
2
1
 
3
- ## [0.1.0] - 2024-01-22
2
+
3
+ ## [0.9.0] - 2024-03-10
4
4
 
5
5
  - Initial release
6
+
7
+
8
+ ## [0.9.1] - 2024-03-10
9
+
10
+ - Fix use of options to use current syntax. Use prefix: true, rather than _prefix: true
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
- Rather than simply having a key/value, enums are Classes, and can have defined methods.
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
- or `video.camera.default_exposure`
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 symbol values, they return an instance of your selected class
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
- def self.values
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
- def self.values
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
- def self.values
139
- {
140
- waiting_for_footage: 0,
141
- waiting_for_upload: 10,
142
- uploading: 20,
143
- processing_preview: 24,
144
- delivered_preview: 26,
145
- processing_paid: 30,
146
- delivered_paid: 50,
147
- processing_failed: 60
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
- def self.values
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]
@@ -1,11 +1,31 @@
1
1
  module SwifterEnum
2
2
  class Base
3
- attr_reader :value
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
- def self.values
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
- def self.values
7
- # Insert your values here as you would for a normal enum
8
- # { foo: 1, bar: 2 }.freeze
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
- { }.freeze
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 => enum_klass.values, **enum_options)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwifterEnum
4
- VERSION = "0.9.0"
4
+ VERSION = "0.9.2"
5
5
  end
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.0
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-09 00:00:00.000000000 Z
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 add logic to your enum definition. This is easy to drop-in as a
85
- replacement for regular rails enums, with minimal changes required. Once you switch,
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