enumy 0.9.0 → 0.10.0

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: 442bf1f2f59d96452645b89c7050dabc6a40b409a069ef098a7cc7b6b2161db6
4
- data.tar.gz: 63c4ea47062fe225c8b06ea89354fcd3c6b7f5207bff4dadaf443288e32054f4
3
+ metadata.gz: 5ca792d4165a95092a74b557d88a61d7a7a6e0d7315ec1e75e22a3f82505a1ca
4
+ data.tar.gz: b092cc6b1eb561643dd0da92153921e2683d1dafb1dcd2003e919a7b95d649de
5
5
  SHA512:
6
- metadata.gz: ae1f353d6694670d47a309ee080bbe1f76728efddec79aeedaeba7e7e852721c034773adb59278c0c81f2b996edea81696991855cb7689fb957b4855a4f191cd
7
- data.tar.gz: 351549b732f4a112eff6926cd6cea4a17a82467c3803d85621cb7cba442a5dd014802eb3eda386b61f6057b834e3ba504395099dc2333786219317b7ab4889cc
6
+ metadata.gz: 4e939f579145cf979a8575cfdf62498aa3ba6917fbf78f6f1c8df5ddd959892ed8dc5c1d1a04f7c96e332a5bbb44bf087b66c8d1044114802dcc8e5d6a0f37d2
7
+ data.tar.gz: 139d995c55b5f2f8cfe3d8a3d40a5c97a5712ba2678bfef187370c14c4b5ad702f48df6b64c9fa454b2963d17ed7a0013463d6d7aeadb82ea2bcfeb0fb4c79ec
data/CHANGELOG.md ADDED
@@ -0,0 +1,102 @@
1
+ ## [Unreleased]
2
+
3
+ ## 0.10.0 - 2026-09-10
4
+
5
+ ### Added
6
+
7
+ - Add `enum_select` Rails helpers — a plain ActionView helper and a `FormBuilder` mixin — for rendering `<select>` inputs from an enum class [17](https://gitlab.com/BevanHolborn/enumy/-/issues/17)
8
+
9
+ ### Changed
10
+
11
+ - **BREAKING CHANGE**: `Enumy::Model#has_enum` now accepts `class_name:` instead of `enum_class:`, accepting a Class/Module directly or a String/Symbol resolved to a constant, and defaulting to the attribute name when omitted [15](https://gitlab.com/BevanHolborn/enumy/-/issues/15)
12
+
13
+ ### Fixed
14
+
15
+ - `Enumy::Enum.define` no longer raises `DuplicateEnumInstanceError` when the same source location redefines a key [16](https://gitlab.com/BevanHolborn/enumy/-/issues/16)
16
+ - `Enumy::Rails::Model#has_enum` no longer relies on `classify`/`safe_constantize` round-tripping when a Class is passed directly as `class_name:` [15](https://gitlab.com/BevanHolborn/enumy/-/issues/15)
17
+ - The packaged gem now ships `README.md`, `LICENSE.txt`, `CHANGELOG.md`, and every file under `lib/` (not just `.rb` files), instead of only `.rb` files under `lib/` [14](https://gitlab.com/BevanHolborn/enumy/-/issues/14)
18
+
19
+ ## 0.9.0 - 2026-09-08
20
+
21
+ ### Fixed
22
+
23
+ - Make `EnumSerializer#klass` public to avoid a Rails 8.2 deprecation warning [18](https://gitlab.com/BevanHolborn/enumy/-/issues/18)
24
+
25
+ ## 0.8.0 - 2025-11-29
26
+
27
+ ### Added
28
+
29
+ - Added support for using Ruby only enums as an attribute on objects [13](https://gitlab.com/BevanHolborn/enumy/-/issues/13)
30
+
31
+ ### Changed
32
+
33
+ - **BREAKING CHANGE**: Rename `Enumy::RailsEnum` to `Enumy::Rails::Enum` [13](https://gitlab.com/BevanHolborn/enumy/-/issues/13)
34
+ - Updated rake test script to properly set up the dummy Rails app [13](https://gitlab.com/BevanHolborn/enumy/-/issues/13)
35
+
36
+ ### Fixed
37
+
38
+ - Fix `Enumy::Enum` referencing the `ActiveModel` `attributes` method in `inspect` [13](https://gitlab.com/BevanHolborn/enumy/-/issues/13)
39
+ - Fix `Enumy::Rails::Model` referencing the removed `Enumy::Base` instead of `Enumy::Enum` [13](https://gitlab.com/BevanHolborn/enumy/-/issues/13)
40
+
41
+ ## 0.7.0 - 2025-11-25
42
+
43
+ ### Added
44
+
45
+ - Add support for Enums in non-Rails Ruby applications [6](https://gitlab.com/BevanHolborn/enumy/-/issues/6)
46
+
47
+ ### Changed
48
+
49
+ - **BREAKING CHANGE**: Rename `Enumy::Base` to `Enumy::RailsEnum` [6](https://gitlab.com/BevanHolborn/enumy/-/issues/6)
50
+
51
+ ## 0.6.0 - 2025-06-24
52
+
53
+ ### Changed
54
+
55
+ - Only require files for Rails initializers if they are supported [10](https://gitlab.com/BevanHolborn/enumy/-/issues/10)
56
+ - For Enumy::Base methods that wrap String methods for the `key`, follow the same name as the String method [9](https://gitlab.com/BevanHolborn/enumy/-/issues/9)
57
+ - Add CI/CD stage for Rspec tests [12](https://gitlab.com/BevanHolborn/enumy/-/issues/12)
58
+
59
+ ## 0.5.1 - 2025-06-23
60
+
61
+ ### Changed
62
+
63
+ - Change the minimum Ruby version to 2.7.0 [8](https://gitlab.com/BevanHolborn/enumy/-/issues/8)
64
+
65
+ ## 0.5.0 - 2025-06-23
66
+
67
+ ### Changed
68
+
69
+ - `Enumy::Base#name` now returns the I18n translation for the `key` attributes [7](https://gitlab.com/BevanHolborn/enumy/-/issues/7)
70
+
71
+ ### Added
72
+
73
+ - `Enumy::Base#title`: Return the titleized `key` attribute [7](https://gitlab.com/BevanHolborn/enumy/-/issues/7)
74
+
75
+ ## 0.4.0 - 2025-04-17
76
+
77
+ ### Changed
78
+
79
+ - Downgrade Dockerfile ruby version to 3.1 [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
80
+ - Explicitly cast key to string in the ActiveJob serializer [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
81
+ - Explicitly define the serialize? method in the ActiveJob serializer [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
82
+ - Serialize invalid Enum keys to nil [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
83
+ - Only register the ActiveJob serializer if the Rails version supports it [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
84
+ - Applied proper module scoping across the project [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
85
+ - Moved the Dummy app to /spec. It is now regenerated with each test run. [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
86
+ - Gemspec dependencies [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
87
+
88
+ ### Added
89
+
90
+ - Rake [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
91
+ - Rspec Tests [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
92
+ - DuplicateEnumInstanceError for clearer errors [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
93
+ - Additional safety checks in Enumy::Base#find_by [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
94
+ - Changelog [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
95
+
96
+ ### Removed
97
+
98
+ - Various unused Dockerfile dependencies [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
99
+
100
+ ### Fixed
101
+
102
+ - Enumy::Model#assert_valid_enum_type! referencing a value on a nil object [5](https://gitlab.com/BevanHolborn/enumy/-/issues/5)
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Bevan Holborn
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,286 @@
1
+ # Enumy
2
+
3
+ Rich Enumeration objects in Ruby and Rails.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Usage](#usage)
9
+ - [Enums](#enums)
10
+ - [Attributes](#attributes)
11
+ - [Customization](#customization)
12
+ - [Rails Integration](#rails-integration)
13
+ - [Enums](#enums-1)
14
+ - [Attributes](#attributes-1)
15
+ - [Associating Enums with Models](#associating-enums-with-models)
16
+ - [Migrations](#migrations)
17
+ - [Usage](#usage-1)
18
+ - [Additional Methods](#additional-methods)
19
+ - [Form Helpers](#form-helpers)
20
+ - [License](#license)
21
+ - [Contributing](#contributing)
22
+
23
+
24
+ ## Installation
25
+
26
+ ```ruby
27
+ bundle add enumy
28
+ ```
29
+
30
+ ## Enums
31
+
32
+ Create a class that inherits from `Enumy::Enum` and define your enums as follows:
33
+
34
+ ```ruby
35
+ class RoleType < Enumy::Enum
36
+ define FREE = self.new(:free)
37
+ define PAID = self.new(:paid)
38
+ define ADMIN = self.new(:admin)
39
+ end
40
+ ```
41
+
42
+ ```ruby
43
+ RoleType.all # => [RoleType::FREE, RoleType::PAID, RoleType::ADMIN]
44
+
45
+ RoleType.find(:free) #=> RoleType::FREE
46
+ RoleType.find(:invalid) #=> raises EnumNotFoundError
47
+
48
+ RoleType.find_by(key: :paid) # => RoleType::PAID
49
+ RoleType.find_by(key: :invalid) # => nil
50
+ ```
51
+
52
+ ### Attributes
53
+
54
+ All enums have a required, unique `key` attribute by default.
55
+ You can add additional attributes as needed the same way you would with a regular PORO
56
+
57
+ ```ruby
58
+ class RoleType < Enumy::Enum
59
+
60
+ attr_reader :color
61
+
62
+ def initialize(key, color:)
63
+ super(key)
64
+ @color = color
65
+ end
66
+
67
+ define FREE = self.new(:free, color: :blue)
68
+ define PAID = self.new(:paid, color: :purple)
69
+ define ADMIN = self.new(:admin, color: :red)
70
+ end
71
+ ```
72
+
73
+ ```ruby
74
+ RoleType::FREE.key #=> :free
75
+ RoleType::FREE.color #=> :blue
76
+
77
+ RoleType.find_by(color: :purple) # => RoleType::PAID
78
+ RoleType.find_by(key: :admin, color: :gray) # => nil
79
+ ```
80
+
81
+ ### Customization
82
+
83
+ Because Enums are POROs, you can add methods to them as needed:
84
+
85
+ ```ruby
86
+ class RoleType < Enumy::Enum
87
+
88
+ attr_reader :color
89
+
90
+ def initialize(key, color:)
91
+ super(key)
92
+ @color = color
93
+ end
94
+
95
+ define FREE = self.new(:free, color: :blue)
96
+ define PAID = self.new(:paid, color: :purple)
97
+ define ADMIN = self.new(:admin, color: :red)
98
+
99
+ def admin?
100
+ self == ADMIN
101
+ end
102
+
103
+ class << self
104
+
105
+ def customer
106
+ [FREE, PAID]
107
+ end
108
+
109
+ end
110
+ end
111
+ ```
112
+
113
+ ```ruby
114
+ RoleType::ADMIN.admin? # => true
115
+ RoleType::FREE.admin? # => false
116
+ RoleType.customer # => [RoleType::FREE, RoleType::PAID]
117
+ ```
118
+
119
+ ## Rails integration
120
+
121
+ Enumy integrates with Rails applications to leverage ActiveModel as well as provide a way to associate enums with models.
122
+
123
+ Run the generator, which will set up an application enum and add the required concern to ApplicationRecord.
124
+ ```ruby
125
+ rails generate enumy:install
126
+ ```
127
+
128
+ Rails enums usually live in `app/enums`. Create a class that inherits from `ApplicationEnum` and define your enum as follows:
129
+
130
+ ```ruby
131
+ class RoleType < ApplicationEnum
132
+ define FREE = self.new(:free)
133
+ define PAID = self.new(:paid)
134
+ define ADMIN = self.new(:admin)
135
+ end
136
+ ```
137
+
138
+ ```ruby
139
+ RoleType.all # => [RoleType::FREE, RoleType::PAID, RoleType::ADMIN]
140
+
141
+ RoleType.find(:free) #=> RoleType::FREE
142
+ RoleType.find(:invalid) #=> raises EnumNotFoundError
143
+
144
+ RoleType.find_by(key: :paid) # => RoleType::PAID
145
+ RoleType.find_by(key: :invalid) # => nil
146
+ ```
147
+
148
+ So far it's exactly the same as a regular enum.
149
+
150
+ ### Attributes
151
+
152
+ All enums have a required, unique `key` attribute by default.
153
+ Because this is a ActiveModel backed PORO, you can add additional attributes simply as follows:
154
+
155
+ ```ruby
156
+ class RoleType < ApplicationEnum
157
+
158
+ attribute :color
159
+
160
+ define FREE = self.new(:free, color: :blue)
161
+ define PAID = self.new(:paid, color: :purple)
162
+ define ADMIN = self.new(:admin, color: :red)
163
+ end
164
+ ```
165
+
166
+ ```ruby
167
+ RoleType::FREE.key #=> :free
168
+ RoleType::FREE.color #=> :blue
169
+
170
+ RoleType.find_by(color: :purple) # => RoleType::PAID
171
+ RoleType.find_by(key: :admin, color: :gray) # => nil
172
+ ```
173
+
174
+ ### Additional methods
175
+
176
+ In addition to the standard Enumy methods, the Rails implementation supports the following Rails-specific methods:
177
+
178
+ **titleize**
179
+ Returns the titleized version of the enum's key.
180
+
181
+ **human_attribute_name**
182
+ Looks up human-readable attribute names for the enum using I18n translations.
183
+ The lookup path is `enum.attributes.models.{enum_class_name}.{enum_key}.{attribute_name}`.
184
+
185
+ **name**
186
+ An alias for human_attribute_name(:key)
187
+
188
+ **model_name**
189
+ Returns an ActiveModel::Name instance for the enum class
190
+
191
+ ### Associating enums with models
192
+
193
+ Enums can be associated with ActiveRecord models using the `has_enum` method provided by Enumy.
194
+
195
+ Enable this by including the `Enumy::Model` concern in your `ApplicationRecord`:
196
+
197
+ ```ruby
198
+ class ApplicationRecord
199
+ include Enumy::Rails::Model
200
+ end
201
+ ```
202
+
203
+ Then in any model, you can define an enum association as follows:
204
+
205
+ ```ruby
206
+ class User < ApplicationRecord
207
+ has_enum :role_type
208
+ end
209
+ ```
210
+
211
+ `has_enum` requires a name (e.g. `has_enum :role_type`)
212
+ You can also the following kwargs:
213
+ - `class_name`: The enum class to use (e.g. class_name: "RoleType"). If not set, it is derived from the name
214
+ - `optional`: If true, the enum can be `nil`. If false, validations are added - `validates :role_type, presence: true, inclusion: { in: RoleType.all }`
215
+ - `default`: Sets a default enum value (e.g. default: RoleType::FREE).
216
+
217
+
218
+ #### Migrations
219
+
220
+ Enumy stores the key of the enum in the model's table, and then attaches the enum to the model when it is loaded into memory.
221
+ This means that a table column is required when adding an enum to a model:
222
+
223
+ ```ruby
224
+ class AddRoleTypeToUsers < ActiveRecord::Migration
225
+ def change
226
+ add_column :users, :role_type, :string
227
+ end
228
+ end
229
+ ```
230
+
231
+ #### Usage
232
+
233
+ With the enum set up on your model you can use it as follows:
234
+
235
+ ```ruby
236
+ user = User.new(role_type: RoleType::FREE)
237
+ user.role_type # => RoleType::FREE
238
+
239
+ user.role_type = RoleType::PAID
240
+ user.role_type # => RoleType::PAID
241
+
242
+ User.where(role_type: RoleType::ADMIN) # SELECT * FROM users WHERE role_type = 'admin'
243
+ ```
244
+
245
+ ### Form helpers
246
+
247
+ Enumy provides two helpers for rendering `<select>` inputs from an enum class. Neither is auto-registered, so include them where you need them:
248
+
249
+ ```ruby
250
+ module ApplicationHelper
251
+ include Enumy::Rails::Helpers::FormHelper
252
+ end
253
+ ```
254
+
255
+ ```ruby
256
+ class ApplicationFormBuilder < ActionView::Helpers::FormBuilder
257
+ include Enumy::Rails::Helpers::FormBuilder
258
+ end
259
+ ```
260
+
261
+ **`enum_select`** is a plain ActionView helper, following the same `object`/`method`/`collection` convention as Rails' own `select`/`collection_select`:
262
+
263
+ ```ruby
264
+ enum_select(:user, :role_type, RoleType.all)
265
+ ```
266
+
267
+ `collection` is required — the plain helper has no model context to derive one from. It also accepts the following kwargs:
268
+ - `value_method`: The method (or callable) used to compute each option's value. Defaults to `:key`
269
+ - `text_method`: The method (or callable) used to compute each option's text. Defaults to `:name`
270
+ - `options`: Passed through to the underlying `select` tag
271
+ - `html_options`: Passed through to the underlying `select` tag
272
+
273
+ **`f.enum_select`** is a FormBuilder method that delegates to the plain helper above:
274
+
275
+ ```ruby
276
+ f.enum_select(:role_type)
277
+ f.enum_select(:role_type, RoleType.customer)
278
+ ```
279
+
280
+ `collection` is an optional second positional argument. When omitted, it's derived from the field's declared `has_enum` class (`RoleType.all`) — this requires `:role_type` to have been set up with `has_enum` on the model. It also accepts `options` and `html_options`, both passed through unchanged.
281
+
282
+ ## License
283
+ This project is licensed under the MIT License. See the LICENSE file for details.
284
+
285
+ ## Contributing
286
+ Contributions are welcome! Please open issues or submit merge requests via GitLab.
data/lib/enumy/enum.rb CHANGED
@@ -28,10 +28,14 @@ module Enumy
28
28
  def define(enum)
29
29
  raise ArgumentError, "Expected an object of type `Enumy::Enum`, got #{enum.class.name}" unless enum.is_a?(Enumy::Enum)
30
30
 
31
- if instances[enum.key]
32
- raise Errors::DuplicateEnumInstanceError, "Enum `#{enum.key.to_s.upcase}` is using a duplicate key `#{enum.key}` for Enum '#{enum.class.name}'."
31
+ call_site = caller_locations(1..1).first
32
+ existing_location = definition_locations[enum.key]
33
+
34
+ if instances[enum.key] && !locations_match?(existing_location, call_site)
35
+ raise Errors::DuplicateEnumInstanceError.new(enum, existing_location, call_site)
33
36
  else
34
37
  instances[enum.key] = enum
38
+ definition_locations[enum.key] = call_site
35
39
  end
36
40
  end
37
41
 
@@ -59,6 +63,14 @@ module Enumy
59
63
  @instances ||= {}
60
64
  end
61
65
 
66
+ def definition_locations
67
+ @definition_locations ||= {}
68
+ end
69
+
70
+ def locations_match?(location_a, location_b)
71
+ !location_a.nil? && location_a.path == location_b.path && location_a.lineno == location_b.lineno
72
+ end
73
+
62
74
  end
63
75
 
64
76
  end
data/lib/enumy/errors.rb CHANGED
@@ -3,7 +3,16 @@ module Enumy
3
3
 
4
4
  class EnumNotFoundError < StandardError; end
5
5
  class InvalidEnumClassError < NameError; end
6
- class DuplicateEnumInstanceError < ArgumentError; end
6
+ class DuplicateEnumInstanceError < ArgumentError
7
+ def initialize(enum, existing_location, conflicting_location)
8
+ message = <<~MESSAGE.chomp
9
+ Enum `#{enum.key.to_s.upcase}` is using a duplicate key `#{enum.key}` for Enum '#{enum.class.name}'.
10
+ First defined at #{existing_location.path}:#{existing_location.lineno}, redefined at #{conflicting_location.path}:#{conflicting_location.lineno}.
11
+ MESSAGE
12
+
13
+ super(message)
14
+ end
15
+ end
7
16
 
8
17
  class KeyMissingError < ArgumentError
9
18
  def initialize(enum)
data/lib/enumy/model.rb CHANGED
@@ -4,8 +4,9 @@ require 'enumy/errors'
4
4
  module Enumy
5
5
  module Model
6
6
 
7
- def has_enum(name, enum_class:, **options)
8
- assert_valid_enum_type!(enum_class)
7
+ def has_enum(name, class_name: name, **options)
8
+ enum_class = resolve_enum_class(class_name)
9
+ assert_valid_enum_type!(enum_class, class_name)
9
10
  define_enum_methods(name, enum_class, default: options[:default])
10
11
  end
11
12
 
@@ -38,9 +39,37 @@ module Enumy
38
39
  end
39
40
  end
40
41
 
41
- def assert_valid_enum_type!(enum_class)
42
- raise Errors::InvalidEnumClassError, "`#{enum_class}` is not a constant" unless enum_class.is_a?(Module)
43
- raise Errors::InvalidEnumClassError, "`#{enum_class.name}` does not inherit from `#{Enumy::Enum.name}`" unless enum_class.ancestors.include?(Enumy::Enum)
42
+ def resolve_enum_class(class_name)
43
+ if class_name.is_a?(Module)
44
+ class_name
45
+ else
46
+ resolve_constant(class_name)
47
+ end
48
+ end
49
+
50
+ def resolve_constant(class_name)
51
+ constant_name = class_name.to_s.split('::').map do |namespace_segment|
52
+ namespace_segment.split('_').map { |word| word[0].upcase + word[1..] }.join
53
+ end.join('::')
54
+
55
+ constant = Object.const_get(constant_name)
56
+
57
+ if constant.is_a?(Module)
58
+ constant
59
+ else
60
+ nil
61
+ end
62
+
63
+ rescue NameError
64
+ nil
65
+ end
66
+
67
+ def assert_valid_enum_type!(enum_class, class_name)
68
+ if enum_class.nil?
69
+ raise Errors::InvalidEnumClassError, "Could not resolve class `#{class_name}`"
70
+ elsif !enum_class.ancestors.include?(Enumy::Enum)
71
+ raise Errors::InvalidEnumClassError, "`#{class_name}` does not inherit from `#{Enumy::Enum.name}`"
72
+ end
44
73
  end
45
74
 
46
75
  end
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Generates an ApplicationEnum class and extends ApplicationRecord as a starting point for your application.
3
+
4
+ Example:
5
+ bin/rails generate enumy:install
6
+
7
+ This will create:
8
+ app/enums/application_enum.rb
9
+
10
+ This will modify:
11
+ app/models/application_record.rb
@@ -0,0 +1,12 @@
1
+ module Enumy
2
+ module Rails
3
+ module Helpers
4
+ module FormBuilder
5
+ def enum_select(method, collection = nil, options: {}, html_options: {})
6
+ collection ||= @object.class.public_send("#{method}_class").all
7
+ @template.enum_select(@object_name, method, collection, options: options, html_options: html_options)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Enumy
2
+ module Rails
3
+ module Helpers
4
+ module FormHelper
5
+ def enum_select(object, method, collection, value_method: :key, text_method: :name, options: {}, html_options: {})
6
+ collection_select(object, method, collection, value_method, text_method, options, html_options)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -5,15 +5,34 @@ module Enumy
5
5
  module Rails
6
6
  module Model
7
7
  def has_enum(name, class_name: name, **options)
8
- enum_class = class_name.to_s.classify.safe_constantize
8
+ enum_class = resolve_enum_class(class_name)
9
9
 
10
10
  assert_valid_enum_type!(enum_class, class_name)
11
11
  define_enum_attributes(name, enum_class, default: options[:default])
12
12
  define_enum_validations(name, enum_class) unless options[:optional]
13
+ define_enum_class_reader(name, enum_class)
13
14
  end
14
15
 
15
16
  private
16
17
 
18
+ def define_enum_class_reader(name, enum_class)
19
+ define_singleton_method("#{name}_class") { enum_class }
20
+ end
21
+
22
+ def resolve_enum_class(class_name)
23
+ if class_name.is_a?(Module)
24
+ class_name
25
+ else
26
+ constant = class_name.to_s.classify.safe_constantize
27
+
28
+ if constant.is_a?(Module)
29
+ constant
30
+ else
31
+ nil
32
+ end
33
+ end
34
+ end
35
+
17
36
  def define_enum_attributes(name, enum_class, **options)
18
37
  attribute name, ActiveModel::Type::Enum.new(enum_class), default: -> { options[:default] }
19
38
  end
@@ -24,9 +43,9 @@ module Enumy
24
43
 
25
44
  def assert_valid_enum_type!(enum_class, class_name)
26
45
  if enum_class.nil?
27
- raise Errors::InvalidEnumClassError, "Could not resolve class `#{class_name.to_s.classify}`"
46
+ raise Errors::InvalidEnumClassError, "Could not resolve class `#{class_name}`"
28
47
  elsif !enum_class.ancestors.include?(Enumy::Enum)
29
- raise Errors::InvalidEnumClassError, "`#{enum_class.name}` does not inherit from `#{Enumy::Enum.name}`"
48
+ raise Errors::InvalidEnumClassError, "`#{class_name}` does not inherit from `#{Enumy::Enum.name}`"
30
49
  end
31
50
  end
32
51
  end
data/lib/enumy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumy
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
data/lib/enumy.rb CHANGED
@@ -7,5 +7,7 @@ if defined?(Rails)
7
7
  require 'enumy/rails/model'
8
8
  require 'enumy/rails/generators/enumy/install/install_generator'
9
9
  require 'enumy/rails/active_model/type/enum'
10
+ require 'enumy/rails/helpers/form_helper'
11
+ require 'enumy/rails/helpers/form_builder'
10
12
  require 'enumy/rails/railtie'
11
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bevan Holborn
@@ -56,6 +56,9 @@ executables: []
56
56
  extensions: []
57
57
  extra_rdoc_files: []
58
58
  files:
59
+ - CHANGELOG.md
60
+ - LICENSE.txt
61
+ - README.md
59
62
  - lib/enumy.rb
60
63
  - lib/enumy/enum.rb
61
64
  - lib/enumy/errors.rb
@@ -63,8 +66,11 @@ files:
63
66
  - lib/enumy/rails/active_job/serializers/enum_serializer.rb
64
67
  - lib/enumy/rails/active_model/type/enum.rb
65
68
  - lib/enumy/rails/enum.rb
69
+ - lib/enumy/rails/generators/enumy/install/USAGE
66
70
  - lib/enumy/rails/generators/enumy/install/install_generator.rb
67
71
  - lib/enumy/rails/generators/enumy/install/templates/app/enums/application_enum.rb
72
+ - lib/enumy/rails/helpers/form_builder.rb
73
+ - lib/enumy/rails/helpers/form_helper.rb
68
74
  - lib/enumy/rails/initializer_interceptor.rb
69
75
  - lib/enumy/rails/model.rb
70
76
  - lib/enumy/rails/railtie.rb