stateful_enum 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/README.md +32 -0
- data/gemfiles/Gemfile-rails.6.0.x +6 -0
- data/lib/generators/stateful_enum/plantuml_generator.rb +1 -2
- data/lib/stateful_enum/active_record_extension.rb +2 -2
- data/lib/stateful_enum/machine.rb +21 -18
- data/lib/stateful_enum/railtie.rb +6 -2
- data/lib/stateful_enum/state_inspection.rb +44 -0
- data/lib/stateful_enum/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d0d82f2cf13496a059030aac0a34a998e47997bcbf6605637fa488c5363454d
|
4
|
+
data.tar.gz: 69fc206ccfc3d4290ad0961cac0d011e92ed1fa5421c0064bd881213d52082d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3f5cec3415b7401c36acf28d5dda810d75818cc88b38a768e721757aaf508714ee0613b7926bb0b5e05832df83e6d7deadc3cc0b816eb3e7ab9a6286f6b1399
|
7
|
+
data.tar.gz: 6a8d8196552d59c696c42872ae3a9decb62ddef4e75b42566af8e45cd2d3887e3fe6688808ac230f3d35ba7501f4e06328a4fad93462d3e8aee4fca985da4720
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -122,6 +122,38 @@ end
|
|
122
122
|
|
123
123
|
You can define `before` and `after` event hooks inside of an `event` block.
|
124
124
|
|
125
|
+
### Inspecting All Defined Events And Current Possible Events
|
126
|
+
|
127
|
+
You can get the list of defined events from the model class:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
Bug.stateful_enum.events
|
131
|
+
#=> an Array of all defined StatefulEnum::Machine::Event objects
|
132
|
+
```
|
133
|
+
|
134
|
+
And you can get the list of possible event definitions from the model instance:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Bug.new(status: :assigned).stateful_enum.possible_events
|
138
|
+
#=> an Array of StatefulEnum::Machine::Event objects that are callable from the receiver object
|
139
|
+
```
|
140
|
+
|
141
|
+
Maybe what you really need for your app is the list of possible event "names":
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
Bug.new(status: :assigned).stateful_enum.possible_event_names
|
145
|
+
#=> [:resolve, :close]
|
146
|
+
```
|
147
|
+
|
148
|
+
You can get the list of next possible state names as well:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
Bug.new(status: :assigned).stateful_enum.possible_states
|
152
|
+
#=> [:resolved, :closed]
|
153
|
+
```
|
154
|
+
|
155
|
+
These features would help some kind of metaprogramming over state transitions.
|
156
|
+
|
125
157
|
|
126
158
|
## Generating State Machine Diagrams
|
127
159
|
|
@@ -10,13 +10,13 @@ module StatefulEnum
|
|
10
10
|
# end
|
11
11
|
# end
|
12
12
|
def enum(definitions, &block)
|
13
|
-
prefix, suffix = definitions[:_prefix], definitions[:_suffix] if Rails::VERSION::
|
13
|
+
prefix, suffix = definitions[:_prefix], definitions[:_suffix] if Rails::VERSION::MAJOR >= 5
|
14
14
|
enum = super definitions
|
15
15
|
|
16
16
|
if block
|
17
17
|
definitions.each_key do |column|
|
18
18
|
states = enum[column]
|
19
|
-
StatefulEnum::Machine.new
|
19
|
+
(@_defined_stateful_enums ||= []) << StatefulEnum::Machine.new(self, column, (states.is_a?(Hash) ? states.keys : states), prefix, suffix, &block)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module StatefulEnum
|
4
4
|
class Machine
|
5
|
+
attr_reader :events
|
6
|
+
|
5
7
|
def initialize(model, column, states, prefix, suffix, &block)
|
6
|
-
@model, @column, @states, @
|
8
|
+
@model, @column, @states, @events = model, column, states, []
|
7
9
|
@prefix = if prefix
|
8
10
|
prefix == true ? "#{column}_" : "#{prefix}_"
|
9
11
|
end
|
@@ -20,40 +22,41 @@ module StatefulEnum
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def event(name, &block)
|
23
|
-
raise ArgumentError, "event: :#{name} has already been defined." if @
|
24
|
-
Event.new
|
25
|
-
@event_names << name
|
25
|
+
raise ArgumentError, "event: :#{name} has already been defined." if @events.map(&:name).include? name
|
26
|
+
@events << Event.new(@model, @column, @states, @prefix, @suffix, name, &block)
|
26
27
|
end
|
27
28
|
|
28
29
|
class Event
|
30
|
+
attr_reader :name, :value_method_name
|
31
|
+
|
29
32
|
def initialize(model, column, states, prefix, suffix, name, &block)
|
30
33
|
@states, @name, @transitions, @before, @after = states, name, {}, [], []
|
31
34
|
|
32
35
|
instance_eval(&block) if block
|
33
36
|
|
34
37
|
transitions, before, after = @transitions, @before, @after
|
35
|
-
|
38
|
+
@value_method_name = value_method_name = :"#{prefix}#{name}#{suffix}"
|
36
39
|
|
37
40
|
# defining event methods
|
38
41
|
model.class_eval do
|
39
42
|
# def assign()
|
40
|
-
detect_enum_conflict! column,
|
43
|
+
detect_enum_conflict! column, value_method_name
|
41
44
|
|
42
45
|
# defining callbacks
|
43
|
-
define_callbacks
|
46
|
+
define_callbacks value_method_name
|
44
47
|
before.each do |before_callback|
|
45
|
-
model.set_callback
|
48
|
+
model.set_callback value_method_name, :before, before_callback
|
46
49
|
end
|
47
50
|
after.each do |after_callback|
|
48
|
-
model.set_callback
|
51
|
+
model.set_callback value_method_name, :after, after_callback
|
49
52
|
end
|
50
53
|
|
51
|
-
define_method
|
54
|
+
define_method value_method_name do
|
52
55
|
to, condition = transitions[send(column).to_sym]
|
53
56
|
#TODO better error
|
54
57
|
if to && (!condition || instance_exec(&condition))
|
55
58
|
#TODO transaction?
|
56
|
-
run_callbacks
|
59
|
+
run_callbacks value_method_name do
|
57
60
|
original_method = self.class.send(:_enum_methods_module).instance_method "#{prefix}#{to}#{suffix}!"
|
58
61
|
original_method.bind(self).call
|
59
62
|
end
|
@@ -63,14 +66,14 @@ module StatefulEnum
|
|
63
66
|
end
|
64
67
|
|
65
68
|
# def assign!()
|
66
|
-
detect_enum_conflict! column, "#{
|
67
|
-
define_method "#{
|
68
|
-
send(
|
69
|
+
detect_enum_conflict! column, "#{value_method_name}!"
|
70
|
+
define_method "#{value_method_name}!" do
|
71
|
+
send(value_method_name) || raise('Invalid transition')
|
69
72
|
end
|
70
73
|
|
71
74
|
# def can_assign?()
|
72
|
-
detect_enum_conflict! column, "can_#{
|
73
|
-
define_method "can_#{
|
75
|
+
detect_enum_conflict! column, "can_#{value_method_name}?"
|
76
|
+
define_method "can_#{value_method_name}?" do
|
74
77
|
state = send(column).to_sym
|
75
78
|
return false unless transitions.key? state
|
76
79
|
_to, condition = transitions[state]
|
@@ -78,8 +81,8 @@ module StatefulEnum
|
|
78
81
|
end
|
79
82
|
|
80
83
|
# def assign_transition()
|
81
|
-
detect_enum_conflict! column, "#{
|
82
|
-
define_method "#{
|
84
|
+
detect_enum_conflict! column, "#{value_method_name}_transition"
|
85
|
+
define_method "#{value_method_name}_transition" do
|
83
86
|
transitions[send(column).to_sym].try! :first
|
84
87
|
end
|
85
88
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'stateful_enum/active_record_extension'
|
4
|
+
require 'stateful_enum/state_inspection'
|
4
5
|
|
5
6
|
module StatefulEnum
|
6
7
|
class Railtie < ::Rails::Railtie
|
7
|
-
|
8
|
-
|
8
|
+
initializer 'stateful_enum' do
|
9
|
+
ActiveSupport.on_load :active_record do
|
10
|
+
::ActiveRecord::Base.extend StatefulEnum::ActiveRecordEnumExtension
|
11
|
+
::ActiveRecord::Base.include StatefulEnum::StateInspection
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stateful_enum/machine'
|
4
|
+
|
5
|
+
module StatefulEnum
|
6
|
+
module StateInspection
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def stateful_enum
|
11
|
+
@_defined_stateful_enums
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def stateful_enum
|
16
|
+
StateInspector.new(self.class.stateful_enum, self)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class StateInspector
|
21
|
+
def initialize(defined_stateful_enums, model_instance)
|
22
|
+
@defined_stateful_enums, @model_instance = defined_stateful_enums, model_instance
|
23
|
+
end
|
24
|
+
|
25
|
+
# List of possible events from the current state
|
26
|
+
def possible_events
|
27
|
+
@defined_stateful_enums.flat_map {|se| se.events.select {|e| @model_instance.send("can_#{e.value_method_name}?") } }
|
28
|
+
end
|
29
|
+
|
30
|
+
# List of possible event names from the current state
|
31
|
+
def possible_event_names
|
32
|
+
possible_events.map(&:value_method_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
# List of transitionable states from the current state
|
36
|
+
def possible_states
|
37
|
+
@defined_stateful_enums.flat_map do |stateful_enum|
|
38
|
+
col = stateful_enum.instance_variable_get :@column
|
39
|
+
pe = stateful_enum.events.select {|e| @model_instance.send("can_#{e.value_method_name}?") }
|
40
|
+
pe.flat_map {|e| e.instance_variable_get(:@transitions)[@model_instance.send(col).to_sym].first }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stateful_enum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akira Matsuda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- gemfiles/Gemfile-rails.5.0.x
|
115
115
|
- gemfiles/Gemfile-rails.5.1.x
|
116
116
|
- gemfiles/Gemfile-rails.5.2.x
|
117
|
+
- gemfiles/Gemfile-rails.6.0.x
|
117
118
|
- gemfiles/Gemfile-rails.edge
|
118
119
|
- lib/generators/stateful_enum/graph_generator.rb
|
119
120
|
- lib/generators/stateful_enum/plantuml_generator.rb
|
@@ -121,6 +122,7 @@ files:
|
|
121
122
|
- lib/stateful_enum/active_record_extension.rb
|
122
123
|
- lib/stateful_enum/machine.rb
|
123
124
|
- lib/stateful_enum/railtie.rb
|
125
|
+
- lib/stateful_enum/state_inspection.rb
|
124
126
|
- lib/stateful_enum/version.rb
|
125
127
|
- stateful_enum.gemspec
|
126
128
|
homepage: https://github.com/amatsuda/stateful_enum
|
@@ -142,8 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
144
|
- !ruby/object:Gem::Version
|
143
145
|
version: '0'
|
144
146
|
requirements: []
|
145
|
-
|
146
|
-
rubygems_version: 2.7.8
|
147
|
+
rubygems_version: 3.0.3
|
147
148
|
signing_key:
|
148
149
|
specification_version: 4
|
149
150
|
summary: A state machine plugin on top of ActiveRecord::Enum
|