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 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