nxt_state_machine 0.1.3 → 0.1.8

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: e9bf5b5563e13832c4dde4f772eca02272eec81d24cbc7f65b5d04d65b2a7c72
4
- data.tar.gz: 5cf98caf5c0deceb3b49cfb9290523f0feb5fac9959d8be9775734b1b3b05cb1
3
+ metadata.gz: 89b1ad3a07fcc60e4b3541b770f1e1f287713e973d3a038f3496be0a145006c5
4
+ data.tar.gz: f213f914ffe2ff39a0d90d8c61f574857b312c9065e1241e9e09dce16cf6cc3a
5
5
  SHA512:
6
- metadata.gz: b49ac744754bd5ec04521f1dce4e506c45269a5f68215a85d39f4b7304e0bb42e0b7d48bdabf2ccbbf9c3e088760b4ed820d2377e4332d2797489361b0bb4571
7
- data.tar.gz: b712cc23c728cabc29020fbafe36b5e5cd468fe671ee698c1ba1a5906b43f1036abcfe82579965f3f1316e907a2027e2510f6d27a8196cf2ecc2ed43b4cd9cc9
6
+ metadata.gz: 48b17f521db0a19ccc500fff321b459f4e962875792e047923185a45691c20b81bfec5bbab03b77cf6eaeb10be2b8191ec73bfbc4d4b05c9e518389b1d9cc497
7
+ data.tar.gz: 286382b6dd9512abc0a0b1c1f177196edab5aced50bc8888d0febf4a58a86697ac152b8a7617c238f3268cbbada15f9767248b333264cf1608421d6a9b9c2b93
@@ -16,11 +16,17 @@ jobs:
16
16
  steps:
17
17
  - checkout
18
18
 
19
+ - run:
20
+ name: Install apt dependencies
21
+ command: |
22
+ sudo apt update -q \
23
+ && sudo apt upgrade -q \
24
+ && sudo apt install -qq graphviz
19
25
  # Download and cache dependencies
20
26
  - restore_cache:
21
27
  keys:
22
28
  - v1-dependencies-{{ checksum "Gemfile.lock" }}
23
-
29
+
24
30
  - run: gem install bundler --version $BUNDLER_VERSION
25
31
 
26
32
  - run:
@@ -53,4 +59,4 @@ jobs:
53
59
  path: /tmp/test-results
54
60
  - store_artifacts:
55
61
  path: /tmp/test-results
56
- destination: test-results
62
+ destination: test-results
@@ -0,0 +1,7 @@
1
+ # v0.1.8 2020-0-05
2
+
3
+ ### Added
4
+
5
+ - [internal] Allow to draw state machine graph with rake task
6
+
7
+ [Compare v0.1.7...v0.1.8](https://github.com/nxt-insurance/nxt_state_machine/compare/v0.1.7...v0.1.8)
@@ -1,37 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_state_machine (0.1.3)
4
+ nxt_state_machine (0.1.8)
5
5
  activesupport
6
6
  nxt_registry (~> 0.1.3)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (6.0.2.1)
12
- activesupport (= 6.0.2.1)
13
- activerecord (6.0.2.1)
14
- activemodel (= 6.0.2.1)
15
- activesupport (= 6.0.2.1)
16
- activesupport (6.0.2.1)
11
+ activemodel (6.0.3.1)
12
+ activesupport (= 6.0.3.1)
13
+ activerecord (6.0.3.1)
14
+ activemodel (= 6.0.3.1)
15
+ activesupport (= 6.0.3.1)
16
+ activesupport (6.0.3.1)
17
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
18
  i18n (>= 0.7, < 2)
19
19
  minitest (~> 5.1)
20
20
  tzinfo (~> 1.1)
21
- zeitwerk (~> 2.2)
21
+ zeitwerk (~> 2.2, >= 2.2.2)
22
22
  coderay (1.1.2)
23
- concurrent-ruby (1.1.5)
23
+ concurrent-ruby (1.1.6)
24
24
  diff-lcs (1.3)
25
25
  i18n (1.8.2)
26
26
  concurrent-ruby (~> 1.0)
27
- method_source (0.9.2)
28
- minitest (5.14.0)
29
- nxt_registry (0.1.4)
27
+ method_source (1.0.0)
28
+ minitest (5.14.1)
29
+ nxt_registry (0.1.5)
30
30
  activesupport
31
- pry (0.12.2)
32
- coderay (~> 1.1.0)
33
- method_source (~> 0.9.0)
34
- rake (10.5.0)
31
+ pry (0.13.1)
32
+ coderay (~> 1.1)
33
+ method_source (~> 1.0)
34
+ rake (12.3.3)
35
+ rexml (3.2.4)
35
36
  rspec (3.9.0)
36
37
  rspec-core (~> 3.9.0)
37
38
  rspec-expectations (~> 3.9.0)
@@ -47,11 +48,13 @@ GEM
47
48
  rspec-support (3.9.0)
48
49
  rspec_junit_formatter (0.4.1)
49
50
  rspec-core (>= 2, < 4, != 2.12.0)
51
+ ruby-graphviz (1.2.5)
52
+ rexml
50
53
  sqlite3 (1.4.2)
51
54
  thread_safe (0.3.6)
52
- tzinfo (1.2.6)
55
+ tzinfo (1.2.7)
53
56
  thread_safe (~> 0.1)
54
- zeitwerk (2.2.2)
57
+ zeitwerk (2.3.0)
55
58
 
56
59
  PLATFORMS
57
60
  ruby
@@ -61,10 +64,11 @@ DEPENDENCIES
61
64
  bundler (~> 2.0)
62
65
  nxt_state_machine!
63
66
  pry
64
- rake (~> 10.0)
67
+ rake (~> 12.0)
65
68
  rspec (~> 3.0)
66
69
  rspec_junit_formatter
70
+ ruby-graphviz
67
71
  sqlite3
68
72
 
69
73
  BUNDLED WITH
70
- 2.0.2
74
+ 2.1.4
data/README.md CHANGED
@@ -83,6 +83,10 @@ class ArticleWorkflow
83
83
  puts 'around transition exit'
84
84
  end
85
85
 
86
+ on_success from: any_state, to: :approved do |transition|
87
+ # This is the last callback in the chain - It runs outside of the active record transaction
88
+ end
89
+
86
90
  on_error CustomError from: any_state, to: :approved do |error, transition|
87
91
  end
88
92
  end
@@ -277,10 +281,10 @@ Transitions can be halted in callbacks and during the transition itself simply b
277
281
 
278
282
  ### Callbacks
279
283
 
280
- You can register `before_transition`, `around_transition` and `after_transition` callbacks. By defining the
281
- :from and :to states you decide on which transitions the callback actually runs. Around callbacks need to call the
282
- proc object that they get passed in. Registering callbacks inside an event block or on the state_machine top level
283
- behaves exactly the same way and is only a matter of structure. The only thing that defines when callbacks run is
284
+ You can register `before_transition`, `around_transition`, `after_transition` and `on_success` callbacks.
285
+ By defining the :from and :to states you decide on which transitions the callback actually runs. Around callbacks need
286
+ to call the proc object that they get passed in. Registering callbacks inside an event block or on the state_machine top
287
+ level behaves exactly the same way and is only a matter of structure. The only thing that defines when callbacks run is
284
288
  the :from and :to parameters with which they are registered.
285
289
 
286
290
 
@@ -298,6 +302,11 @@ event :approve do
298
302
  block.call
299
303
  puts 'around transition exit'
300
304
  end
305
+
306
+ # Use this to trigger another event after the transaction around the transition completed
307
+ on_success from: any_state, to: :approved do |transition|
308
+ # This is the last callback in the chain - It runs outside of the active record transaction
309
+ end
301
310
  end
302
311
  ```
303
312
 
@@ -327,7 +336,42 @@ state_machine do
327
336
  end
328
337
  ```
329
338
 
330
- ### Multiple state machines in the same class
339
+ ### ActiveRecord transaction, rollback and locks - breaking the flow by defusing errors
340
+
341
+ You want to break out of your transition (which is wrapped inside a lock)?
342
+ You can raise an error, have everything rolled back and then have your error handler take over.
343
+ **NOTE:** Unless you reload your model all assignments you did, previous to the error, should still be available in your
344
+ error handler. You can also defuse errors. This means they will not cause a rollback of the transaction during the
345
+ transition and you can actually persist changes to your model before the defused error is raised and handled.
346
+
347
+ ```ruby
348
+ state_machine do
349
+ # ...
350
+ #
351
+ defuse CustomError, from: any_state, to: all_states
352
+
353
+ event :approve do
354
+ # You can also defuse on event level
355
+ # defuse CustomError, from: %i[written submitted deleted], to: :approved
356
+
357
+ transition from: %i[written submitted deleted], to: :approved do |headline:|
358
+ # This will be save to the database even if defused CustomError is raised after
359
+ article.update!(headline: headline)
360
+ raise CustomError, 'This does not rollback the headline update above'
361
+ end
362
+ end
363
+
364
+ on_error! CustomError from: any_state, to: :approved do |error, transition|
365
+ # You can still handle the defused Error if you want to
366
+ # You should probably reload your model here to not accidentally save changes that
367
+ # were made to the model during the transition before a non defused error was raised
368
+ article.reload
369
+ # The error callback does not run inside the transaction. No more strings attached here.
370
+ # You can now persist changes to your model again.
371
+ article.update!(error: error.message)
372
+ end
373
+ end
374
+ ```
331
375
 
332
376
  In theory you can also have multiple state_machines in the same class. To do so you have to give each
333
377
  state_machine a name. Events need to be unique globally in order to determine which state_machine will be called.
@@ -349,17 +393,6 @@ class Article < ApplicationRecord
349
393
  end
350
394
  ```
351
395
 
352
-
353
- ## TODO
354
- - Test implementations for Hash, AttrAccessor
355
- - Thread safety spec!
356
- - Spec locks?
357
- - Explain locking in readme!
358
- - Should we clone machines for each context?
359
- - What about inheritance? => What would be the expected behaviour? (dup vs. no dup)
360
- => Might also make sense to walk the ancestors chain and collect configure blocks
361
-
362
-
363
396
  ## Development
364
397
 
365
398
  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.
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -16,6 +16,7 @@ require "nxt_state_machine/callable"
16
16
  require "nxt_state_machine/state_registry"
17
17
  require "nxt_state_machine/callback_registry"
18
18
  require "nxt_state_machine/error_callback_registry"
19
+ require "nxt_state_machine/defuse_registry"
19
20
  require "nxt_state_machine/event_registry"
20
21
  require "nxt_state_machine/state"
21
22
  require "nxt_state_machine/event"
@@ -30,6 +31,7 @@ require "nxt_state_machine/state_machine"
30
31
  require "nxt_state_machine/integrations/active_record"
31
32
  require "nxt_state_machine/integrations/attr_accessor"
32
33
  require "nxt_state_machine/integrations/hash"
34
+ require "nxt_state_machine/graph"
33
35
 
34
36
  module NxtStateMachine
35
37
  module ClassMethods
@@ -0,0 +1,26 @@
1
+ module NxtStateMachine
2
+ class DefuseRegistry
3
+ include ::NxtRegistry
4
+
5
+ def register(from, to, kind)
6
+ Array(from).each do |from_state|
7
+ Array(to).each do |to_state|
8
+ defusing_errors = errors.from(from_state).to(to_state)
9
+ Array(kind).each_with_object(defusing_errors) { |error, acc| acc << error }
10
+ end
11
+ end
12
+ end
13
+
14
+ def resolve(transition)
15
+ errors.from(transition.from.enum).to(transition.to.enum)
16
+ end
17
+
18
+ private
19
+
20
+ def errors
21
+ @errors ||= registry :from do
22
+ nested :to, default: -> { [] }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -18,11 +18,13 @@ module NxtStateMachine
18
18
  delegate :before_transition,
19
19
  :after_transition,
20
20
  :around_transition,
21
+ :on_success,
21
22
  :on_error,
22
23
  :on_error!,
23
24
  :any_state,
24
25
  :all_states,
25
26
  :all_states_except,
27
+ :defuse,
26
28
  to: :state_machine
27
29
 
28
30
  def transitions(from:, to:, &block)
@@ -39,6 +41,10 @@ module NxtStateMachine
39
41
  event_transitions.resolve!(state).present?
40
42
  end
41
43
 
44
+ def to_s
45
+ "#{self.class.name}[:#{name}]"
46
+ end
47
+
42
48
  private
43
49
 
44
50
  def configure(&block)
@@ -0,0 +1,77 @@
1
+ module NxtStateMachine
2
+ class Graph
3
+ def initialize(state_machines, **options)
4
+ @state_machines = state_machines
5
+ @options = default_options.merge(**options)
6
+ end
7
+
8
+ def draw
9
+ require 'ruby-graphviz'
10
+
11
+ state_machines.each do |_, state_machine|
12
+ add_nodes(state_machine)
13
+ add_edges(state_machine)
14
+ end
15
+
16
+ filename = File.join(options[:path], "#{options[:name]}.#{options[:format]}")
17
+
18
+ graph.output options[:format] => filename
19
+
20
+ puts '----------------------------------------------'
21
+ puts 'Please run the following to open the generated file:'
22
+ puts "open '#{filename}'"
23
+ puts '----------------------------------------------'
24
+
25
+ graph
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :options, :state_machines
31
+
32
+ def graph
33
+ @graph ||= ::GraphViz.new(
34
+ 'G',
35
+ rankdir: options[:orientation] == 'landscape' ? 'LR' : 'TB',
36
+ ratio: options[:ratio]
37
+ )
38
+ end
39
+
40
+ def add_nodes(state_machine)
41
+ binding.pry
42
+ state_machine.states.values.each do |state|
43
+ add_node(state)
44
+ end
45
+ end
46
+
47
+ def add_node(state)
48
+ node_options = {
49
+ label: state.to_s,
50
+ width: '1',
51
+ height: '1',
52
+ shape: 'ellipse'
53
+ }
54
+
55
+ graph.add_nodes(state.to_s, node_options)
56
+ end
57
+
58
+ def add_edges(state_machine)
59
+ state_machine.events.values.each do |event|
60
+ event.event_transitions.values.each do |transition|
61
+ graph.add_edges(transition.from.to_s, transition.to.to_s, label: event.name)
62
+ end
63
+ end
64
+ end
65
+
66
+ def default_options
67
+ {
68
+ name: 'state_machine',
69
+ path: '.',
70
+ orientation: 'landscape',
71
+ ratio: 'fill',
72
+ format: 'png',
73
+ font: 'Helvetica'
74
+ }
75
+ end
76
+ end
77
+ end
@@ -21,34 +21,21 @@ module NxtStateMachine
21
21
  end
22
22
 
23
23
  machine.set_state_with do |target, transition|
24
- target.with_lock do
25
- transition.run_before_callbacks
26
- result = set_state(target, transition, state_attr, :save)
27
- transition.run_after_callbacks
28
-
29
- result
30
- end
31
- rescue StandardError => error
32
- target.assign_attributes(state_attr => transition.from.to_s)
33
-
34
- if error.is_a?(NxtStateMachine::Errors::TransitionHalted)
35
- false
36
- else
37
- raise
38
- end
24
+ set_state(machine, target, transition, state_attr, :save)
39
25
  end
40
26
 
41
27
  machine.set_state_with! do |target, transition|
42
- target.with_lock do
43
- transition.run_before_callbacks
44
- result = set_state(target, transition, state_attr, :save!)
45
- transition.run_after_callbacks
28
+ set_state(machine, target, transition, state_attr, :save!)
29
+ end
46
30
 
47
- result
31
+ machine.define_singleton_method :add_state_methods_to_model do |model_class|
32
+ model_class.class_eval do
33
+ machine.states.keys.each do |state_name|
34
+ define_method "#{state_name}?" do
35
+ send(machine.options.fetch(:state_attr)) == state_name
36
+ end
37
+ end
48
38
  end
49
- rescue StandardError
50
- target.assign_attributes(state_attr => transition.from.to_s)
51
- raise
52
39
  end
53
40
 
54
41
  machine
@@ -58,11 +45,40 @@ module NxtStateMachine
58
45
  module InstanceMethods
59
46
  private
60
47
 
61
- def set_state(target, transition, state_attr, method)
48
+ def set_state(machine, target, transition, state_attr, save_with_method)
49
+ result = nil
50
+ defused_error = nil
51
+
52
+ target.with_lock do
53
+ transition.run_before_callbacks
54
+ result = execute_transition(target, transition, state_attr, save_with_method)
55
+ transition.run_after_callbacks
56
+
57
+ result
58
+ rescue StandardError => error
59
+ if machine.defuse_registry.resolve(transition).find { |error_class| error.is_a?(error_class) }
60
+ defused_error = error
61
+ else
62
+ raise error
63
+ end
64
+ end
65
+
66
+ raise defused_error if defused_error
67
+
68
+ transition.run_success_callbacks || result
69
+ rescue StandardError => error
70
+ target.assign_attributes(state_attr => transition.from.to_s)
71
+
72
+ raise unless save_with_method == :save && error.is_a?(NxtStateMachine::Errors::TransitionHalted)
73
+
74
+ false
75
+ end
76
+
77
+ def execute_transition(target, transition, state_attr, save_with_method)
62
78
  transition.execute do |block|
63
79
  result = block ? block.call : nil
64
80
  target.assign_attributes(state_attr => transition.to.to_s)
65
- set_state_result = target.send(method) || halt_transition
81
+ set_state_result = target.send(save_with_method) || halt_transition
66
82
  block ? result : set_state_result
67
83
  end
68
84
  end
@@ -22,7 +22,7 @@ module NxtStateMachine
22
22
  result = set_state(target, transition, state_attr)
23
23
  transition.run_after_callbacks
24
24
 
25
- result
25
+ transition.run_success_callbacks || result
26
26
  rescue StandardError => error
27
27
  target.send("#{state_attr}=", transition.from.enum)
28
28
 
@@ -38,7 +38,7 @@ module NxtStateMachine
38
38
  result = set_state(target, transition, state_attr)
39
39
  transition.run_after_callbacks
40
40
 
41
- result
41
+ transition.run_success_callbacks || result
42
42
  rescue StandardError
43
43
  target.send("#{state_attr}=", transition.from.enum)
44
44
  raise
@@ -21,7 +21,7 @@ module NxtStateMachine
21
21
  transition.run_before_callbacks
22
22
  result = set_state(current_target, transition, state_attr)
23
23
  transition.run_after_callbacks
24
- result
24
+ transition.run_success_callbacks || result
25
25
  rescue StandardError => error
26
26
  current_target[state_attr] = transition.from.enum
27
27
 
@@ -37,7 +37,7 @@ module NxtStateMachine
37
37
  result = set_state(current_target, transition, state_attr)
38
38
  transition.run_after_callbacks
39
39
 
40
- result
40
+ transition.run_success_callbacks || result
41
41
  rescue StandardError
42
42
  current_target[state_attr] = transition.from.enum
43
43
  raise
@@ -10,11 +10,12 @@ module NxtStateMachine
10
10
  @events = event_registry
11
11
  @callbacks = CallbackRegistry.new
12
12
  @error_callback_registry = ErrorCallbackRegistry.new
13
+ @defuse_registry = DefuseRegistry.new
13
14
 
14
15
  @initial_state = nil
15
16
  end
16
17
 
17
- attr_reader :class_context, :transitions, :events, :options, :callbacks, :name, :error_callback_registry
18
+ attr_reader :class_context, :events, :options, :callbacks, :name, :error_callback_registry, :defuse_registry
18
19
  attr_accessor :initial_state
19
20
 
20
21
  def get_state_with(method = nil, &block)
@@ -89,6 +90,7 @@ module NxtStateMachine
89
90
  class_context.define_method event_name do |*args, **opts|
90
91
  event.state_machine.can_transition!(name, event.state_machine.current_state_name(self))
91
92
  transition = event.event_transitions.resolve(event.state_machine.current_state_name(self))
93
+ # Transition is build every time and thus should be thread safe!
92
94
  transition.build_transition(event_name, self, set_state_method, *args, **opts)
93
95
  end
94
96
  end
@@ -116,6 +118,14 @@ module NxtStateMachine
116
118
  callbacks.register(from, to, :after, run, block)
117
119
  end
118
120
 
121
+ def on_success(from:, to:, run: nil, &block)
122
+ callbacks.register(from, to, :success, run, block)
123
+ end
124
+
125
+ def defuse(errors = [], from:, to:)
126
+ defuse_registry.register(from, to, errors)
127
+ end
128
+
119
129
  def on_error(error = StandardError, from:, to:, run: nil, &block)
120
130
  error_callback_registry.register(from, to, error, run, block)
121
131
  end
@@ -142,16 +152,23 @@ module NxtStateMachine
142
152
  run_callbacks(transition, :after, context)
143
153
  end
144
154
 
155
+ def run_success_callbacks(transition, context)
156
+ run_callbacks(transition, :success, context)
157
+ end
158
+
145
159
  def find_error_callback(error, transition)
146
160
  error_callback_registry.resolve(error, transition)
147
161
  end
148
162
 
149
163
  def run_callbacks(transition, kind, context)
150
164
  current_callbacks = callbacks.resolve(transition, kind)
165
+ return unless current_callbacks.any?
151
166
 
152
167
  current_callbacks.each do |callback|
153
168
  Callable.new(callback).bind(context).call(transition)
154
169
  end
170
+
171
+ true
155
172
  end
156
173
 
157
174
  def current_state_name(context)
@@ -11,20 +11,18 @@ module NxtStateMachine
11
11
  @set_state_method = set_state_method
12
12
  @context = context
13
13
  @block = block
14
+ @result = nil
14
15
  end
15
16
 
16
- attr_reader :name, :from, :to, :block, :event
17
+ attr_reader :name, :from, :to, :block, :event, :result
17
18
 
18
- def prepare
19
+ # This triggers the set state method
20
+ def trigger
19
21
  Callable.new(
20
22
  state_machine.send(set_state_method)
21
23
  ).bind(
22
24
  context
23
25
  ).call(state_machine.target(context), self)
24
- end
25
-
26
- def execute(&block)
27
- Transition::Proxy.new(event, state_machine,self, context).call(&block)
28
26
  rescue StandardError => error
29
27
  callback = state_machine.find_error_callback(error, self)
30
28
  raise unless callback
@@ -32,6 +30,11 @@ module NxtStateMachine
32
30
  Callable.new(callback).bind(context).call(error, self)
33
31
  end
34
32
 
33
+ # This must be used in set_state method to actually execute the transition within the around callback chain
34
+ def execute(&block)
35
+ self.result = Transition::Proxy.new(event, state_machine,self, context).call(&block)
36
+ end
37
+
35
38
  alias_method :with_around_callbacks, :execute
36
39
 
37
40
  def run_before_callbacks
@@ -42,9 +45,13 @@ module NxtStateMachine
42
45
  state_machine.run_after_callbacks(self, context)
43
46
  end
44
47
 
48
+ def run_success_callbacks
49
+ state_machine.run_success_callbacks(self, context)
50
+ end
51
+
45
52
  private
46
53
 
47
54
  attr_reader :state_machine, :set_state_method, :context
48
- attr_writer :block
55
+ attr_writer :block, :result
49
56
  end
50
57
  end
@@ -39,7 +39,7 @@ module NxtStateMachine
39
39
  end)
40
40
  end
41
41
 
42
- transition.prepare
42
+ transition.trigger
43
43
  end
44
44
 
45
45
  private
@@ -1,3 +1,3 @@
1
1
  module NxtStateMachine
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -0,0 +1,8 @@
1
+ class Railtie < Rails::Railtie
2
+ railtie_name :nxt_state_machine
3
+
4
+ rake_tasks do
5
+ path = File.expand_path(__dir__)
6
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ namespace :graph do
2
+ desc 'draw the graph of a state machine'
3
+ task :draw, [:state_machine_class] => [:environment] do |_, args|
4
+ state_machine_class = Object.const_get(args.fetch(:state_machine_class))
5
+ state_machine = state_machine_class.state_machine
6
+ NxtStateMachine::Graph.new(state_machine).draw
7
+ end
8
+ end
@@ -38,9 +38,10 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency "nxt_registry", "~> 0.1.3"
39
39
 
40
40
  spec.add_development_dependency "bundler", "~> 2.0"
41
- spec.add_development_dependency "rake", "~> 10.0"
41
+ spec.add_development_dependency "rake", "~> 12.0"
42
42
  spec.add_development_dependency "rspec", "~> 3.0"
43
43
  spec.add_development_dependency "pry"
44
44
  spec.add_development_dependency "activerecord"
45
45
  spec.add_development_dependency "sqlite3"
46
+ spec.add_development_dependency "ruby-graphviz"
46
47
  end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nxt_state_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Robecke
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2020-01-26 00:00:00.000000000 Z
14
+ date: 2020-06-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -61,14 +61,14 @@ dependencies:
61
61
  requirements:
62
62
  - - "~>"
63
63
  - !ruby/object:Gem::Version
64
- version: '10.0'
64
+ version: '12.0'
65
65
  type: :development
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - "~>"
70
70
  - !ruby/object:Gem::Version
71
- version: '10.0'
71
+ version: '12.0'
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: rspec
74
74
  requirement: !ruby/object:Gem::Requirement
@@ -125,6 +125,20 @@ dependencies:
125
125
  - - ">="
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
+ - !ruby/object:Gem::Dependency
129
+ name: ruby-graphviz
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
128
142
  description: A state machine library that can be used with ActiveRecord or in plain
129
143
  ruby and should be easy to customize for other integrations
130
144
  email:
@@ -139,6 +153,7 @@ files:
139
153
  - ".rspec"
140
154
  - ".ruby-version"
141
155
  - ".travis.yml"
156
+ - CHANGELOG.md
142
157
  - Gemfile
143
158
  - Gemfile.lock
144
159
  - LICENSE.txt
@@ -149,6 +164,7 @@ files:
149
164
  - lib/nxt_state_machine.rb
150
165
  - lib/nxt_state_machine/callable.rb
151
166
  - lib/nxt_state_machine/callback_registry.rb
167
+ - lib/nxt_state_machine/defuse_registry.rb
152
168
  - lib/nxt_state_machine/error_callback_registry.rb
153
169
  - lib/nxt_state_machine/errors/error.rb
154
170
  - lib/nxt_state_machine/errors/event_already_registered.rb
@@ -165,6 +181,7 @@ files:
165
181
  - lib/nxt_state_machine/event.rb
166
182
  - lib/nxt_state_machine/event/names.rb
167
183
  - lib/nxt_state_machine/event_registry.rb
184
+ - lib/nxt_state_machine/graph.rb
168
185
  - lib/nxt_state_machine/integrations/active_record.rb
169
186
  - lib/nxt_state_machine/integrations/attr_accessor.rb
170
187
  - lib/nxt_state_machine/integrations/hash.rb
@@ -178,7 +195,10 @@ files:
178
195
  - lib/nxt_state_machine/transition/proxy.rb
179
196
  - lib/nxt_state_machine/transition/store.rb
180
197
  - lib/nxt_state_machine/version.rb
198
+ - lib/railtie.rb
199
+ - lib/tasks/draw_graph.rake
181
200
  - nxt_state_machine.gemspec
201
+ - state_machine.png
182
202
  homepage: https://github.com/nxt-insurance/nxt_state_machine
183
203
  licenses:
184
204
  - MIT