enum_machine 0.1.0 → 2.0.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: e3e8eb3957fd71860a322260031d255c8034c53a0d263bd43d68911bcf97507f
4
- data.tar.gz: 05306e2ad610425b729a1716ee854614e697acc4dbd0cf6a9d85a476dd1f5209
3
+ metadata.gz: 29c5cbbb67a385d43e3410de9b1d2974b5a5878bad25c51eca631785870389e6
4
+ data.tar.gz: adbf98313f00d208194b20899373d7ec2561ec99f94b23974efe226538c7c63d
5
5
  SHA512:
6
- metadata.gz: ea4de98d78c4cb4d0a67655f6c6bcce58f3168696e43b311a5e23873caf49fa4624745de266c852ab34f5edc892c5a7d4459803e772669522d6cf04fa63dff28
7
- data.tar.gz: 9233aa651cd9efb8ed0c2cbb16172da70d99fb1b919ba0d4a9146b6c8c312ec85d0d12fc183af82bb3b90f0cdfb4af78c55305f3f53b78a73cd546bb41ac0b7a
6
+ metadata.gz: 32c418e7ff59bbcc33b4a00e4fea58533077409609e4125f226fdbbdf676522cadfa2977ce90100132bec76536ff0920691ecf98b3a713fff9ebbf7c63794b9c
7
+ data.tar.gz: 55656e3c4903039bb40f7807c3abdd141c57ddc566c34bab59e8d57c08b7dd70a97d7cf3e7654b21d488230b4aaa9575ebcb8feeab8470c16ba847c31a78fe95
data/.rubocop.yml CHANGED
@@ -3,11 +3,14 @@ inherit_gem:
3
3
  - ./config/default.yml
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 2.6
6
+ TargetRubyVersion: 3.0
7
7
 
8
8
  Rails/ApplicationRecord:
9
9
  Enabled: false
10
10
 
11
+ Rails/Output:
12
+ Enabled: false
13
+
11
14
  Metrics/ParameterLists:
12
15
  CountKeywordArgs: false
13
16
 
data/Gemfile CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'dry-types'
8
- gem 'priscilla', github: 'corp-gp/priscilla'
9
- gem 'pry', '~> 0.12'
10
- gem 'rake', '~> 13.0'
11
- gem 'rspec', '~> 3.9'
12
- gem 'rubocop-gp', github: 'corp-gp/rubocop-gp'
13
- gem 'sqlite3', '~> 1.4'
7
+ gem "dry-types"
8
+ gem "priscilla", github: "corp-gp/priscilla"
9
+ gem "pry", "~> 0.12"
10
+ gem "rake", "~> 13.0"
11
+ gem "rspec", "~> 3.9"
12
+ gem "rubocop-gp", github: "corp-gp/rubocop-gp"
13
+ gem "sqlite3", "~> 1.4"
data/Gemfile.lock CHANGED
@@ -8,116 +8,148 @@ GIT
8
8
 
9
9
  GIT
10
10
  remote: https://github.com/corp-gp/rubocop-gp.git
11
- revision: 4d390b6cdd2b27f151fe0535bd266525fbf8f25d
11
+ revision: 867f7e1351c3730897cacdc20ce2d727604de245
12
12
  specs:
13
- rubocop-gp (0.0.2)
13
+ rubocop-gp (0.0.4)
14
14
  rubocop
15
+ rubocop-capybara
16
+ rubocop-factory_bot
15
17
  rubocop-performance
16
18
  rubocop-rails
17
19
  rubocop-rspec
20
+ rubocop-rspec_rails
18
21
 
19
22
  PATH
20
23
  remote: .
21
24
  specs:
22
- enum_machine (0.1.0)
23
- activemodel (~> 6.0)
24
- activerecord (~> 6.0)
25
- activesupport (~> 6.0)
25
+ enum_machine (2.0.0)
26
+ activemodel
27
+ activerecord
28
+ activesupport
26
29
 
27
30
  GEM
28
31
  remote: https://rubygems.org/
29
32
  specs:
30
- activemodel (6.1.4.6)
31
- activesupport (= 6.1.4.6)
32
- activerecord (6.1.4.6)
33
- activemodel (= 6.1.4.6)
34
- activesupport (= 6.1.4.6)
35
- activesupport (6.1.4.6)
36
- concurrent-ruby (~> 1.0, >= 1.0.2)
33
+ activemodel (7.2.1)
34
+ activesupport (= 7.2.1)
35
+ activerecord (7.2.1)
36
+ activemodel (= 7.2.1)
37
+ activesupport (= 7.2.1)
38
+ timeout (>= 0.4.0)
39
+ activesupport (7.2.1)
40
+ base64
41
+ bigdecimal
42
+ concurrent-ruby (~> 1.0, >= 1.3.1)
43
+ connection_pool (>= 2.2.5)
44
+ drb
37
45
  i18n (>= 1.6, < 2)
46
+ logger (>= 1.4.2)
38
47
  minitest (>= 5.1)
39
- tzinfo (~> 2.0)
40
- zeitwerk (~> 2.3)
48
+ securerandom (>= 0.3)
49
+ tzinfo (~> 2.0, >= 2.0.5)
41
50
  ast (2.4.2)
51
+ base64 (0.2.0)
52
+ bigdecimal (3.1.8)
42
53
  coderay (1.1.3)
43
54
  colorize (0.8.1)
44
- concurrent-ruby (1.1.9)
45
- diff-lcs (1.5.0)
46
- dry-configurable (0.14.0)
55
+ concurrent-ruby (1.3.4)
56
+ connection_pool (2.4.1)
57
+ diff-lcs (1.5.1)
58
+ drb (2.2.1)
59
+ dry-core (1.0.1)
47
60
  concurrent-ruby (~> 1.0)
48
- dry-core (~> 0.6)
49
- dry-container (0.9.0)
61
+ zeitwerk (~> 2.6)
62
+ dry-inflector (1.1.0)
63
+ dry-logic (1.5.0)
50
64
  concurrent-ruby (~> 1.0)
51
- dry-configurable (~> 0.13, >= 0.13.0)
52
- dry-core (0.7.1)
65
+ dry-core (~> 1.0, < 2)
66
+ zeitwerk (~> 2.6)
67
+ dry-types (1.7.2)
68
+ bigdecimal (~> 3.0)
53
69
  concurrent-ruby (~> 1.0)
54
- dry-inflector (0.2.1)
55
- dry-logic (1.2.0)
70
+ dry-core (~> 1.0)
71
+ dry-inflector (~> 1.0)
72
+ dry-logic (~> 1.4)
73
+ zeitwerk (~> 2.6)
74
+ i18n (1.14.6)
56
75
  concurrent-ruby (~> 1.0)
57
- dry-core (~> 0.5, >= 0.5)
58
- dry-types (1.5.1)
59
- concurrent-ruby (~> 1.0)
60
- dry-container (~> 0.3)
61
- dry-core (~> 0.5, >= 0.5)
62
- dry-inflector (~> 0.1, >= 0.1.2)
63
- dry-logic (~> 1.0, >= 1.0.2)
64
- i18n (1.9.1)
65
- concurrent-ruby (~> 1.0)
66
- method_source (1.0.0)
67
- minitest (5.15.0)
68
- parallel (1.21.0)
69
- parser (3.1.0.0)
76
+ json (2.8.2)
77
+ language_server-protocol (3.17.0.3)
78
+ logger (1.6.1)
79
+ method_source (1.1.0)
80
+ minitest (5.25.2)
81
+ parallel (1.26.3)
82
+ parser (3.3.6.0)
70
83
  ast (~> 2.4.1)
71
- pry (0.14.1)
84
+ racc
85
+ pry (0.14.2)
72
86
  coderay (~> 1.1)
73
87
  method_source (~> 1.0)
74
- rack (2.2.3)
88
+ racc (1.8.1)
89
+ rack (3.1.8)
75
90
  rainbow (3.1.1)
76
- rake (13.0.6)
77
- regexp_parser (2.2.1)
78
- rexml (3.2.5)
79
- rspec (3.11.0)
80
- rspec-core (~> 3.11.0)
81
- rspec-expectations (~> 3.11.0)
82
- rspec-mocks (~> 3.11.0)
83
- rspec-core (3.11.0)
84
- rspec-support (~> 3.11.0)
85
- rspec-expectations (3.11.0)
91
+ rake (13.2.1)
92
+ regexp_parser (2.9.2)
93
+ rspec (3.13.0)
94
+ rspec-core (~> 3.13.0)
95
+ rspec-expectations (~> 3.13.0)
96
+ rspec-mocks (~> 3.13.0)
97
+ rspec-core (3.13.1)
98
+ rspec-support (~> 3.13.0)
99
+ rspec-expectations (3.13.3)
86
100
  diff-lcs (>= 1.2.0, < 2.0)
87
- rspec-support (~> 3.11.0)
88
- rspec-mocks (3.11.0)
101
+ rspec-support (~> 3.13.0)
102
+ rspec-mocks (3.13.1)
89
103
  diff-lcs (>= 1.2.0, < 2.0)
90
- rspec-support (~> 3.11.0)
91
- rspec-support (3.11.0)
92
- rubocop (1.25.1)
104
+ rspec-support (~> 3.13.0)
105
+ rspec-support (3.13.1)
106
+ rubocop (1.69.0)
107
+ json (~> 2.3)
108
+ language_server-protocol (>= 3.17.0)
93
109
  parallel (~> 1.10)
94
- parser (>= 3.1.0.0)
110
+ parser (>= 3.3.0.2)
95
111
  rainbow (>= 2.2.2, < 4.0)
96
- regexp_parser (>= 1.8, < 3.0)
97
- rexml
98
- rubocop-ast (>= 1.15.1, < 2.0)
112
+ regexp_parser (>= 2.4, < 3.0)
113
+ rubocop-ast (>= 1.36.1, < 2.0)
99
114
  ruby-progressbar (~> 1.7)
100
- unicode-display_width (>= 1.4.0, < 3.0)
101
- rubocop-ast (1.15.1)
102
- parser (>= 3.0.1.1)
103
- rubocop-performance (1.13.2)
104
- rubocop (>= 1.7.0, < 2.0)
105
- rubocop-ast (>= 0.4.0)
106
- rubocop-rails (2.13.2)
115
+ unicode-display_width (>= 2.4.0, < 4.0)
116
+ rubocop-ast (1.36.1)
117
+ parser (>= 3.3.1.0)
118
+ rubocop-capybara (2.21.0)
119
+ rubocop (~> 1.41)
120
+ rubocop-factory_bot (2.26.1)
121
+ rubocop (~> 1.61)
122
+ rubocop-performance (1.23.0)
123
+ rubocop (>= 1.48.1, < 2.0)
124
+ rubocop-ast (>= 1.31.1, < 2.0)
125
+ rubocop-rails (2.27.0)
107
126
  activesupport (>= 4.2.0)
108
127
  rack (>= 1.1)
109
- rubocop (>= 1.7.0, < 2.0)
110
- rubocop-rspec (2.8.0)
111
- rubocop (~> 1.19)
112
- ruby-progressbar (1.11.0)
128
+ rubocop (>= 1.52.0, < 2.0)
129
+ rubocop-ast (>= 1.31.1, < 2.0)
130
+ rubocop-rspec (3.2.0)
131
+ rubocop (~> 1.61)
132
+ rubocop-rspec_rails (2.30.0)
133
+ rubocop (~> 1.61)
134
+ rubocop-rspec (~> 3, >= 3.0.1)
135
+ ruby-progressbar (1.13.0)
113
136
  rumoji (0.5.0)
114
- sqlite3 (1.4.2)
115
- tzinfo (2.0.4)
137
+ securerandom (0.3.2)
138
+ sqlite3 (1.7.3-arm64-darwin)
139
+ sqlite3 (1.7.3-x86_64-darwin)
140
+ sqlite3 (1.7.3-x86_64-linux)
141
+ timeout (0.4.2)
142
+ tzinfo (2.0.6)
116
143
  concurrent-ruby (~> 1.0)
117
- unicode-display_width (2.1.0)
118
- zeitwerk (2.5.4)
144
+ unicode-display_width (3.1.2)
145
+ unicode-emoji (~> 4.0, >= 4.0.4)
146
+ unicode-emoji (4.0.4)
147
+ zeitwerk (2.6.18)
119
148
 
120
149
  PLATFORMS
150
+ arm64-darwin-21
151
+ arm64-darwin-23
152
+ x86_64-darwin-21
121
153
  x86_64-linux
122
154
 
123
155
  DEPENDENCIES
@@ -131,4 +163,4 @@ DEPENDENCIES
131
163
  sqlite3 (~> 1.4)
132
164
 
133
165
  BUNDLED WITH
134
- 2.2.29
166
+ 2.3.15
data/README.md CHANGED
@@ -1,38 +1,260 @@
1
- # EnumMachine
1
+ # Enum Machine
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/enum_machine`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ `Enum Machine` is a library for defining enums and setting state machines for attributes in ActiveRecord models and plain Ruby classes.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ You can visualize transitions map with [enum_machine-contrib](https://github.com/corp-gp/enum_machine-contrib)
6
+
7
+ ## Why is `enum_machine` better then [state_machines](https://github.com/state-machines/state_machines) / [aasm](https://github.com/aasm/aasm)?
8
+
9
+ - faster [5x](#Benchmarks)
10
+ - code lines: `enum_machine` - 348, `AASM` - 2139
11
+ - namespaced (via attr) by default: `order.state.to_collected`
12
+ - [aliases](Aliases)
13
+ - guarantees of existing transitions
14
+ - simple run transitions with callbacks `order.update(state: "collected")` or `order.state.to_collected`
15
+ - `aasm` / `state_machines` **event driven**, `enum_machine` **state driven**
16
+
17
+ ```ruby
18
+ # aasm
19
+ event :complete do # complete/collected - dichotomy between states and events
20
+ before { puts "event complete" }
21
+ transitions from: :collecting, to: :collected
22
+ end
23
+
24
+ # pay/archived difficult to remember the relationship between statuses and events
25
+ # try to explain this to the logic of business stakeholders
26
+ event :pay do
27
+ transitions from: [:created, :collected], to: :archived
28
+ end
29
+
30
+ order = Order.create(state: "collecting")
31
+ order.update(state: "archived") # not check transitions, invalid logic
32
+ order.update(state: "collected") # not run callbacks
33
+ order.complete # need use event for transition, but your object in UI and DB have only states
34
+
35
+ # enum_machine
36
+ transitions( # simple readable transitions map
37
+ "collecting" => "collected",
38
+ "collected" => "archived",
39
+ )
40
+ before_transition("collecting" => "collected") { puts "event complete" }
41
+
42
+ order = Order.create(state: "collecting")
43
+ order.update(state: "archived") # checked transitions, raise exception
44
+ order.update(state: "collected") # run callbacks
45
+ ```
6
46
 
7
47
  ## Installation
8
48
 
9
- Add this line to your application's Gemfile:
49
+ Add to your Gemfile:
10
50
 
11
51
  ```ruby
12
- gem 'enum_machine'
52
+ gem "enum_machine"
13
53
  ```
14
54
 
15
- And then execute:
55
+ ## Usage
16
56
 
17
- $ bundle install
57
+ ### Enums
18
58
 
19
- Or install it yourself as:
59
+ ```ruby
60
+ # With ActiveRecord
61
+ class Product < ActiveRecord::Base
62
+ enum_machine :color, %w[red green]
63
+ end
20
64
 
21
- $ gem install enum_machine
65
+ # Or with plain class
66
+ class Product
67
+ # attributes must be defined before including the EnumMachine module
68
+ attr_accessor :color
22
69
 
23
- ## Usage
70
+ include EnumMachine[color: { enum: %w[red green] }]
71
+ # or reuse from model
72
+ Product::COLOR.enum_decorator
73
+ end
74
+
75
+ Product::COLOR.values # => ["red", "green"]
76
+ Product::COLOR::RED # => "red"
77
+ Product::COLOR::RED__GREEN # => ["red", "green"]
78
+
79
+ Product::COLOR["red"].red? # => true
80
+ Product::COLOR["red"].human_name # => "Красный"
81
+
82
+ product = Product.new
83
+ product.color # => nil
84
+ product.color = "red"
85
+ product.color.red? # => true
86
+ product.color.human_name # => "Красный"
87
+ ```
88
+
89
+ ### Aliases
90
+
91
+ ```ruby
92
+ class Product < ActiveRecord::Base
93
+ enum_machine :state, %w[created approved published] do
94
+ aliases(
95
+ "forming" => %w[created approved],
96
+ )
97
+ end
98
+ end
99
+
100
+ Product::STATE.forming # => %w[created approved]
101
+
102
+ product = Product.new(state: "created")
103
+ product.state.forming? # => true
104
+ ```
105
+
106
+ ### Value decorator
107
+
108
+ You can extend value object with decorator
109
+
110
+ ```ruby
111
+ # Value classes nested from base class
112
+ module ColorDecorator
113
+ def hex
114
+ case self
115
+ when Product::COLOR::RED then "#ff0000"
116
+ when Product::COLOR::GREEN then "#00ff00"
117
+ end
118
+ end
119
+ end
120
+
121
+ class Product
122
+ attr_accessor :color
123
+
124
+ include EnumMachine[color: {
125
+ enum: %w[red green],
126
+ value_decorator: ColorDecorator
127
+ }]
128
+ end
24
129
 
25
- TODO: Write usage instructions here
130
+ product = Product.new
131
+ product.color = "red"
132
+ product.color.hex # => "#ff0000"
133
+ ```
134
+
135
+ ### Transitions
136
+
137
+ ```ruby
138
+ class Product < ActiveRecord::Base
139
+ enum_machine :color, %w[red green blue]
140
+ enum_machine :state, %w[created approved cancelled activated] do
141
+ # transitions(any => any) - allow all transitions
142
+ transitions(
143
+ nil => "created",
144
+ "created" => [nil, "approved"],
145
+ %w[cancelled approved] => "activated",
146
+ "activated" => %w[created cancelled],
147
+ )
148
+
149
+ # Will be executed in `before_save` callback
150
+ before_transition "created" => "approved" do |product|
151
+ product.color = "green" if product.color.red?
152
+ end
153
+
154
+ # Will be executed in `after_save` callback
155
+ after_transition %w[created] => %w[approved] do |product|
156
+ product.color = "red"
157
+ end
158
+
159
+ after_transition any => "cancelled" do |product|
160
+ product.cancelled_at = Time.zone.now
161
+ end
162
+ end
163
+ end
164
+
165
+ product = Product.create(state: "created")
166
+ product.state.possible_transitions # => [nil, "approved"]
167
+ product.state.can_activated? # => false
168
+ product.state.to_activated! # => EnumMachine::Error: transition "created" => "activated" not defined in enum_machine
169
+ product.state.to_approved! # => true; equal to `product.update!(state: "approve")`
170
+ ```
171
+
172
+ #### Skip transitions
173
+ ```ruby
174
+ product = Product.new(state: "created")
175
+ product.skip_state_transitions { product.save }
176
+ ```
177
+
178
+ method generated as `skip_#{enum_name}_transitions`
179
+
180
+ #### Skip in factories
181
+ ```ruby
182
+ FactoryBot.define do
183
+ factory :product do
184
+ name { Faker::Commerce.product_name }
185
+ to_create { |product| product.skip_state_transitions { product.save! } }
186
+ end
187
+ end
188
+ ```
189
+
190
+ ### I18n
191
+
192
+ **ru.yml**
193
+ ```yml
194
+ ru:
195
+ enums:
196
+ product:
197
+ color:
198
+ red: Красный
199
+ green: Зеленый
200
+ ```
201
+
202
+ ```ruby
203
+ # ActiveRecord
204
+ class Product < ActiveRecord::Base
205
+ enum_machine :color, %w[red green]
206
+ end
26
207
 
27
- ## Development
208
+ # Plain class
209
+ class Product
210
+ # attributes must be defined before including the EnumMachine module
211
+ attr_accessor :color
212
+ # `i18n_scope` option must be explicitly set to use methods below
213
+ include EnumMachine[color: { enum: %w[red green], i18n_scope: "product" }]
214
+ end
28
215
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
216
+ Product::COLOR.human_name_for("red") # => "Красный"
217
+ Product::COLOR.values_for_form # => [["Красный", "red"], ["Зеленый", "green"]]
218
+
219
+ product = Product.new(color: "red")
220
+ product.color.human_name # => "Красный"
221
+ ```
222
+
223
+ I18n scope can be changed with `i18n_scope` option:
224
+
225
+ ```ruby
226
+ # For AciveRecord
227
+ class Product < ActiveRecord::Base
228
+ enum_machine :color, %w[red green], i18n_scope: "users.product"
229
+ end
230
+
231
+ # For plain class
232
+ class Product
233
+ include EnumMachine[color: { enum: %w[red green], i18n_scope: "users.product" }]
234
+ end
235
+ ```
30
236
 
31
- 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
237
+ ## Benchmarks
238
+ [test/performance.rb](../master/test/performance.rb)
32
239
 
33
- ## Contributing
240
+ | Gem | Method | |
241
+ | :--- | ---: | :--- |
242
+ | enum_machine | order.state.forming? | 894921.3 i/s |
243
+ | state_machines | order.forming? | 189901.8 i/s - 4.71x slower |
244
+ | aasm | order.forming? | 127073.7 i/s - 7.04x slower |
245
+ | | | |
246
+ | enum_machine | order.state.can_closed? | 473150.4 i/s |
247
+ | aasm | order.may_to_closed? | 24459.1 i/s - 19.34x slower |
248
+ | state_machines | order.can_to_closed? | 12136.8 i/s - 38.98x slower |
249
+ | | | |
250
+ | enum_machine | Order::STATE.values | 6353820.4 i/s |
251
+ | aasm | Order.aasm(:state).states.map(&:name) | 131390.5 i/s - 48.36x slower |
252
+ | state_machines | Order.state_machines[:state].states.map(&:value) | 108449.7 i/s - 58.59x slower |
253
+ | | | |
254
+ | enum_machine | order.state = "forming" and order.valid? | 13873.4 i/s |
255
+ | state_machines | order.state_event = "to_forming" and order.valid? | 6173.6 i/s - 2.25x slower |
256
+ | aasm | order.to_forming | 3095.9 i/s - 4.48x slower |
34
257
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/enum_machine.
36
258
 
37
259
  ## License
38
260
 
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require 'rubocop/rake_task'
8
+ require "rubocop/rake_task"
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
@@ -0,0 +1,54 @@
1
+ # Переход с `rails_string_enum` на `enum_machine`
2
+
3
+ ### 1. Объявление в классе
4
+ ```ruby
5
+ class Product
6
+ string_enum :color, %w[red green] # Было
7
+ enum_machine :color, %w[red green] # Стало
8
+ end
9
+ ```
10
+
11
+ ### 2. Константы
12
+
13
+ Все константы находятся в Product::COLOR
14
+
15
+ * `Product::RED` => `Product::COLOR::RED`
16
+ * `Product::RED__GREEN` => `Product::COLOR::RED__GREEN`
17
+ * `Product::COLORS` => `Product::COLOR.values`
18
+
19
+ ### 3. Методы инстанса
20
+
21
+ * `@product.red?` => `@product.color.red?`
22
+
23
+ ### 4. I18n хелперы
24
+
25
+ * `Product.colors_i18n` => `Product::COLOR.values_for_form`
26
+ * `Product.color_i18n_for('red')` => `Product::COLOR.human_name_for('red')`
27
+ * `@product.color_i18n` => `@product.color.human_name`
28
+
29
+ ### 5. scopes
30
+
31
+ В `enum_machine` нет опции `scopes`, нужно задать необходимые вручную
32
+
33
+ ```ruby
34
+ class Product
35
+ # Было
36
+ string_enum :color, %w[red green], scopes: true
37
+
38
+ # Стало
39
+ enum_machine :color, %w[red green]
40
+ scope :only_red, -> { where(color: COLOR::RED) }
41
+ end
42
+ ```
43
+
44
+ ### 6. Интеграция с `simple_form`
45
+
46
+ `enum_machine` не предоставляет интеграцию с `simple_form`, тип инпута и коллекцию нужно передавать самостоятельно
47
+
48
+ ```ruby
49
+ # Было
50
+ f.input :color
51
+
52
+ # Стало
53
+ f.input :color, as: :select, collection: Product::COLOR.values_for_form
54
+ ```
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EnumMachine
4
+ module AttributePersistenceMethods
5
+ def self.[](attr, enum_values)
6
+ Module.new do
7
+ define_singleton_method(:extended) do |klass|
8
+ klass.attr_accessor :parent
9
+
10
+ enum_values.each do |enum_value|
11
+ enum_name = enum_value.underscore
12
+
13
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
14
+ # def to_created!
15
+ # parent.update!('state' => 'created')
16
+ # end
17
+
18
+ def to_#{enum_name}!
19
+ parent.update!('#{attr}' => '#{enum_value}')
20
+ end
21
+ RUBY
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end