queued_state_machine 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ee5afccef7f058cfd32f2c50641359447a77287c
4
+ data.tar.gz: 4125d5ef26e850d7854c3116f96e599cc1e1d0a0
5
+ SHA512:
6
+ metadata.gz: 3102ab88418edb28b591044971e0d26b7ae3afc6fb1bb60479d1659f62af425a90932cf343d95767ed93e06ffaaf5912675a95ea930485c7af3ec97c43c9fc49
7
+ data.tar.gz: f33a5a56f2c9aec627c8a967b478d03007b0347a57c529d4ac4cecaae5fa1b8f4891567efc02dd872772880db5d0e1fb9f00d6c8fca34b7d24c0e05f3bf07e95
@@ -0,0 +1,5 @@
1
+ module QueuedStateMachine
2
+ class InvalidTransition < StandardError
3
+
4
+ end
5
+ end
@@ -0,0 +1,151 @@
1
+ require 'queued_state_machine/invalid_transition'
2
+
3
+ module QueuedStateMachine
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ attr_reader :initial_state
12
+
13
+ def inherited(subclass)
14
+ subclass.instance_variable_set("@states", instance_variable_get("@states").dup)
15
+ subclass.instance_variable_set("@initial_state", instance_variable_get("@initial_state"))
16
+ subclass.instance_variable_set("@transitions", instance_variable_get("@transitions").dup)
17
+ subclass.instance_variable_set("@callbacks", instance_variable_get("@callbacks").dup)
18
+ end
19
+
20
+ def states
21
+ @states ||= []
22
+ end
23
+
24
+ def transitions
25
+ @transitions ||= []
26
+ end
27
+
28
+ def callbacks
29
+ @callbacks ||= []
30
+ end
31
+
32
+ def state(name, initial: false)
33
+ unless transitions.empty? && callbacks.empty?
34
+ raise 'Error: all states must be defined before any transitions of callbacks'
35
+ end
36
+ name = clean_state(name)
37
+ self.initial_state = name if initial
38
+ states << name
39
+ nil
40
+ end
41
+
42
+ def transition(from: nil, to: nil)
43
+ if block_given?
44
+ raise "Error: transitions do not accept blocks, use 'on_transition'"
45
+ end
46
+ from = clean_state_list(from)
47
+ to = clean_state_list(to)
48
+ missing_state = (from + to).find { |state| !states.include?(state) }
49
+ if missing_state
50
+ raise "Error: state #{missing_state} not defined"
51
+ end
52
+ transitions << {from: from, to: to}
53
+ nil
54
+ end
55
+
56
+ def on_transition(from: nil, to: nil, &block)
57
+ unless block_given?
58
+ 'Error: no callback defined'
59
+ end
60
+ from = clean_state_list(from)
61
+ to = clean_state_list(to)
62
+ missing_state = (from + to).find { |state| !states.include?(state) }
63
+ if missing_state
64
+ raise "Error: state #{missing_state} not defined"
65
+ end
66
+ callbacks << {from: from, to: to, callback: block}
67
+ nil
68
+ end
69
+
70
+ def clean_state(name)
71
+ name.to_s
72
+ end
73
+
74
+ def clean_state_list(arg)
75
+ case
76
+ when arg == nil
77
+ states
78
+ when arg.respond_to?(:to_a)
79
+ list = arg
80
+ list.map! {|name| clean_state(name) }
81
+ list
82
+ else
83
+ name = arg
84
+ [clean_state(name)]
85
+ end
86
+ end
87
+
88
+ def initial_state
89
+ raise 'Error: no initial state set' unless @initial_state
90
+ @initial_state
91
+ end
92
+
93
+ def initial_state=(name)
94
+ raise 'Error: initial state already set' if @initial_state
95
+ @initial_state = name
96
+ end
97
+
98
+ end
99
+
100
+ def initialize
101
+ super
102
+ @state = self.class.initial_state
103
+ @pending_transitions = []
104
+ end
105
+
106
+ def to(state, quiet: false)
107
+ from = @state
108
+ to = self.class.clean_state(state)
109
+ @pending_transitions << {from: from, to: to, quiet: quiet}
110
+ return if @pending_transitions.length > 1
111
+ loop do
112
+ next_transition = @pending_transitions.first
113
+ break unless next_transition
114
+ @state = next_transition[:to]
115
+ unless next_transition[:quiet]
116
+ process_transition(next_transition[:from], next_transition[:to])
117
+ end
118
+ @pending_transitions.shift
119
+ end
120
+ end
121
+
122
+ def quietly_to(state)
123
+ to(state, quiet: true)
124
+ end
125
+
126
+ def at
127
+ @state
128
+ end
129
+
130
+ def at?(arg)
131
+ list = self.class.clean_state_list(arg)
132
+ raise if list == nil
133
+ list.include?(@state)
134
+ end
135
+
136
+ private
137
+
138
+ def process_transition(from, to)
139
+ valid_transitions = self.class.transitions.select do |transition|
140
+ transition[:from].include?(from) && transition[:to].include?(to)
141
+ end
142
+ if valid_transitions.empty?
143
+ raise InvalidTransition, "Error: no valid transition from '#{from}' to '#{to}'"
144
+ end
145
+ valid_callbacks = self.class.callbacks.select do |transition|
146
+ transition[:from].include?(from) && transition[:to].include?(to)
147
+ end
148
+ valid_callbacks.each { |callback| instance_eval(&callback[:callback]) }
149
+ end
150
+
151
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: queued_state_machine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Fors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A state machine that supports queuing any callbacks that are triggered
14
+ during a callback.
15
+ email: mail@robfors.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/queued_state_machine.rb
21
+ - lib/queued_state_machine/invalid_transition.rb
22
+ homepage: https://github.com/robfors/queued_state_machine
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 2.4.8
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: A state machine supporting reentry.
46
+ test_files: []