enu 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +169 -6
- data/enu.gemspec +1 -1
- data/lib/enu.rb +2 -0
- data/lib/enu/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc1b4752d455a471be538cbdfef720a49b96d56d2f56ae5dedfa7a34ccfa25f6
|
4
|
+
data.tar.gz: 35fa945c3a4859a18460fb5cbe71babd6eae2a9dc12e7ef2ad509685592bc28a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52dc8a9a2703e01f62b9fc1d2e09d3f9cc80c96b6cedfcfe4ff6c65c4949b9bb92b3bd96f6c7026e7f30625386223aaa24e021479d8b00e1c8b00b14d7ce7cce
|
7
|
+
data.tar.gz: 610af50ee26962f456e885b42475fc2831d396d1b5cd738df1b30ea43dbb40c62517b474e5eb819d0cee572dd1be21b2209cc9cec99c4907b84e80950ee9ef00
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Enu
|
2
2
|
|
3
|
-
|
3
|
+
⚠️ WARNING! This implementation is experimental. Please do not use in production before stable release is announced.
|
4
4
|
|
5
|
-
This gem
|
5
|
+
This gem introduces missing [enumerated type](https://en.wikipedia.org/wiki/Enumerated_type) for Ruby and Rails.
|
6
6
|
|
7
7
|
Purpose and features:
|
8
8
|
|
9
9
|
- Unify enum types definition for Rails model attributes, compatible with ActiveRecord's [enum declarations](https://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html).
|
10
|
-
- Use constants instead of magic strings or numbers to define enum values.
|
11
|
-
- Support explicit and implicit enum options definition.
|
10
|
+
- Use structured constants instead of magic strings or numbers to define enum values.
|
12
11
|
- Keep track on enum references to simplify refactoring.
|
12
|
+
- Support explicit and implicit enum options definition.
|
13
13
|
- Provide a standardized way to export enum definitions to client-side JavaScript modules, managed by either Webpack or Rails Assets Pipeline.
|
14
14
|
|
15
15
|
## Installation
|
@@ -34,11 +34,174 @@ $ gem install enu
|
|
34
34
|
|
35
35
|
## Usage
|
36
36
|
|
37
|
-
|
37
|
+
### Enum types definition
|
38
|
+
|
39
|
+
Here is a basic example:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# app/enums/post_status.rb
|
43
|
+
class PostStatus < Enu
|
44
|
+
option :draft
|
45
|
+
option :published
|
46
|
+
option :moderated
|
47
|
+
option :deleted
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
This class defines an enum type for a blog post status which four optional states: `draft`, `published`, `moderated` and `deleted`. Each state automatically receives integer representation: 0 for `draft`, 1 for `published`, and so on. The first option will be treated as `default`.
|
52
|
+
|
53
|
+
### Using enums
|
54
|
+
|
55
|
+
After enum type is defined, it is possible to use it in a Rails model:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# app/models/post.rb
|
59
|
+
#
|
60
|
+
# Table name: posts
|
61
|
+
#
|
62
|
+
# id :integer not null, primary key
|
63
|
+
# user_id :integer not null
|
64
|
+
# status :integer default(0), not null
|
65
|
+
# ...
|
66
|
+
#
|
67
|
+
class Post < ApplicationRecord
|
68
|
+
enum status: PostStatus.options
|
69
|
+
# ...
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
`options` class method will return enum representation in the form of a `Hash`, compatible with [ActiveRecord::Enum](https://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html) declaration:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
PostStatus.options # {"draft"=>0, "published"=>1, "moderated" => 2, "deleted"=>3}
|
77
|
+
```
|
78
|
+
|
79
|
+
Use [enum helpers](https://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html) as usual:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Post.new.draft? # true
|
83
|
+
Post.new.published? # false
|
84
|
+
|
85
|
+
post = Post.create! # #<Post:...>
|
86
|
+
post.draft? # true
|
87
|
+
post.published! # true
|
88
|
+
post.status # "published"
|
89
|
+
|
90
|
+
Post.published.to_sql # "SELECT "posts".* FROM "posts" WHERE "posts"."status" = 1"
|
91
|
+
```
|
92
|
+
|
93
|
+
### Scoped constants
|
94
|
+
|
95
|
+
Sometimes native helper methods are not enough, and you need to address enum values directly. If this is the case, use scoped constants instead of magic strings values. Say, you need to update multiple attributes for a set of DB records with a single query:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# app/models/user.rb
|
99
|
+
#
|
100
|
+
# Table name: posts
|
101
|
+
#
|
102
|
+
# id :integer not null, primary key
|
103
|
+
# user_id :integer not null
|
104
|
+
# ...
|
105
|
+
#
|
106
|
+
class User < ApplicationRecord
|
107
|
+
has_many :posts
|
108
|
+
|
109
|
+
def nasty_spammer?
|
110
|
+
# ...
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
use = User.first
|
115
|
+
|
116
|
+
if user.nasty_spammer?
|
117
|
+
user.posts.update_all(
|
118
|
+
status: PostStatus.moderated,
|
119
|
+
moderated_by: current_user,
|
120
|
+
moderated_at: Time.new.utc,
|
121
|
+
moderation_reason: 'being a nasty spammer'
|
122
|
+
)
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
Another example is a state machine definition with [aasm](https://github.com/aasm/aasm) gem:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
class Post < ApplicationRecord
|
130
|
+
include AASM
|
131
|
+
|
132
|
+
enum status: PostStatus.options
|
133
|
+
|
134
|
+
aasm column: :status, enum: true do
|
135
|
+
state PostStatus.draft, initial: true
|
136
|
+
state PostStatus.published
|
137
|
+
state PostStatus.moderated
|
138
|
+
state PostStatus.deleted
|
139
|
+
|
140
|
+
# Draft posts can be published
|
141
|
+
event :publish do
|
142
|
+
transitions from: PostStatus.draft, to: PostStatus.published
|
143
|
+
end
|
144
|
+
|
145
|
+
# Published posts can be moderated
|
146
|
+
event :moderate do
|
147
|
+
transitions from: PostStatus.published, to: PostStatus.moderated
|
148
|
+
end
|
149
|
+
|
150
|
+
# Any post can be deleted (but only once)
|
151
|
+
event :dump do
|
152
|
+
transitions from: PostStatus.keys.without(:deleted), to: PostStatus.deleted
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
Notice that `dump` event is using `PostStatus.keys` shortcut, instead of declaring a separate transition for each available post status. `Enu` provides `keys` and `values` class methods for each enum type.
|
159
|
+
|
160
|
+
Now the `Post#state` field has transition rules:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
post = Post.create! # new record status will be initialized with "draft" value
|
164
|
+
post.status # => "draft"
|
165
|
+
|
166
|
+
post.publish! # performs sample transition and persist the new status
|
167
|
+
post.status # => "published"
|
168
|
+
|
169
|
+
post.dump!
|
170
|
+
post.moderate! # will raise an AASM::InvalidTransition, because deleted
|
171
|
+
# posts are not supposed to be moderated
|
172
|
+
```
|
173
|
+
|
174
|
+
### Code base navigation
|
175
|
+
|
176
|
+
Scoped constants will help to track enum type references in your codebase. Looking up an enum class name or a specific value, like `PostStatus.draft`, is a more efficient way to navigate your codebase, comparing to a situation when you use plain string literals or symbols, like in the [Rails Guides examples](https://guides.rubyonrails.org/active_record_querying.html#enums). Chances are search results for `draft` will be much noisier in a large codebase.
|
177
|
+
|
178
|
+
Notice the source file location. Keeping enum type definitions in a separate location is not mandatory, though, it will help to keep the source code organized. In a typical Rails application project [autoload](https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoload-paths-and-eager-load-paths) mechanism will resolve all constants in `app` subdirectories, so there is no need to worry about requiring anything manually.
|
179
|
+
|
180
|
+
This readme uses `PostStatus` for the sake of brevity. In a larger real-life code base, though, it is worth considering to organize sibling classes with a module, instead of polluting root namespace:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
# app/enums/post_status.rb
|
184
|
+
module Enums
|
185
|
+
class PostStatus < Enu
|
186
|
+
# ...
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
Default Rails autoload configuration will successfully resolve `Enums::PostStatus` constant.
|
192
|
+
|
193
|
+
#### Spring gotcha
|
194
|
+
|
195
|
+
There is a known issue with using custom directories in a Rails application. If you running your app with [Spring preloader](https://github.com/rails/spring) (which is true for default configuration), make sure to restart the preloader. Otherwise, Rails autoload will not resolve any constants under `app/enums/` or any other custom paths, and will keep raising `NameError`. This command will help:
|
196
|
+
|
197
|
+
```bash
|
198
|
+
> bin/spring stop
|
199
|
+
Spring stopped.
|
200
|
+
```
|
38
201
|
|
39
202
|
## Development
|
40
203
|
|
41
|
-
After checking out the
|
204
|
+
After checking out the repository, 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.
|
42
205
|
|
43
206
|
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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
44
207
|
|
data/enu.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Alex Musayev"]
|
9
9
|
spec.email = ["alex.musayev@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "Missing enum type for Ruby and Rails"
|
11
|
+
spec.summary = "[Experimental] Missing enum type for Ruby and Rails"
|
12
12
|
spec.description = ""
|
13
13
|
spec.homepage = "https://github.com/dreikanter/enu"
|
14
14
|
spec.license = "MIT"
|
data/lib/enu.rb
CHANGED
data/lib/enu/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Musayev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -223,5 +223,5 @@ requirements: []
|
|
223
223
|
rubygems_version: 3.0.3
|
224
224
|
signing_key:
|
225
225
|
specification_version: 4
|
226
|
-
summary: Missing enum type for Ruby and Rails
|
226
|
+
summary: "[Experimental] Missing enum type for Ruby and Rails"
|
227
227
|
test_files: []
|