statum 0.3.0 → 0.3.1
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 +4 -4
- data/README.md +1 -0
- data/lib/statum.rb +9 -57
- data/lib/statum/class_methods.rb +35 -0
- data/lib/statum/event.rb +5 -5
- data/lib/statum/hook.rb +6 -1
- data/lib/statum/instance_methods.rb +37 -0
- data/lib/statum/machine.rb +14 -3
- data/lib/statum/state_definer.rb +3 -2
- data/lib/statum/version.rb +1 -1
- data/statum.gemspec +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d044edb13c46dc2a4ece61532eb8268c6dfa91f
|
4
|
+
data.tar.gz: 3c51404c5dc3281442ed7f4a7be5a34d2fbb7f57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8b8b6c598abfe37921b2edb85c1d55624d53074097ea8288b34d2a906c84c6c27369e624d98a4de598c1fadd18d9aa5af61aca9cfe594094242bb0961f0c8c7
|
7
|
+
data.tar.gz: 3a4f4e46b868a885e5138265d63a5d5ee5c8f0005e16bda19f2d815293c589f262a4c28f7c84f54b97fdc281f40bcc4604872000066b8122e0f55df2ab1df5c8
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|

|
4
4
|
[](https://coveralls.io/github/nulldef/statum?branch=master&v=1)
|
5
|
+
[](https://badge.fury.io/rb/statum)
|
5
6
|
|
6
7
|
Finite state machine for your objects
|
7
8
|
|
data/lib/statum.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
require "statum/version"
|
2
|
+
require "statum/class_methods"
|
3
|
+
require "statum/instance_methods"
|
2
4
|
require "statum/machine"
|
3
5
|
require "statum/hook"
|
4
6
|
require "statum/event"
|
5
7
|
require "statum/state_definer"
|
6
8
|
|
7
9
|
module Statum
|
10
|
+
# Error for unknown event
|
8
11
|
UnknownEventError = Class.new(ArgumentError)
|
12
|
+
|
13
|
+
# Error for wrong transition
|
9
14
|
ErrorTransitionError = Class.new(StandardError)
|
15
|
+
|
16
|
+
# Error for duplicated state machine
|
10
17
|
ExistingMachineError = Class.new(ArgumentError)
|
11
18
|
|
19
|
+
# Variable to store state machines
|
12
20
|
STATE_MACHINES_VARIABLE = '@__statum_machines'.freeze
|
13
21
|
|
22
|
+
# Any state identifier
|
14
23
|
ANY_STATE_NAME = :__statum_any_state
|
15
24
|
|
16
25
|
class << self
|
@@ -19,61 +28,4 @@ module Statum
|
|
19
28
|
base.include(Statum::InstanceMethods)
|
20
29
|
end
|
21
30
|
end
|
22
|
-
|
23
|
-
module ClassMethods
|
24
|
-
def statum(field, options = {}, &block)
|
25
|
-
definer = Statum::StateDefiner.new(self, field, options)
|
26
|
-
definer.instance_eval(&block) if block_given?
|
27
|
-
add_machine(definer.state_machine)
|
28
|
-
end
|
29
|
-
|
30
|
-
def state_machines
|
31
|
-
instance_variable_get(STATE_MACHINES_VARIABLE) || []
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def add_machine(machine)
|
37
|
-
if state_machines.any? { |m| m.name == machine.name }
|
38
|
-
raise ExistingMachineError, "State machine for #{machine.name} already exists"
|
39
|
-
end
|
40
|
-
instance_variable_set(STATE_MACHINES_VARIABLE, state_machines + [machine])
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module InstanceMethods
|
45
|
-
def method_missing(meth, *args)
|
46
|
-
if meth.to_s.end_with?('?') && (machine = find_machine_by_state(meth[0...-1]))
|
47
|
-
machine.current(self) == meth[0...-1].to_sym
|
48
|
-
elsif meth.to_s.end_with?('!') && (machine = find_machine_by_event(meth[0...-1]))
|
49
|
-
machine.fire!(self, meth[0...-1])
|
50
|
-
else
|
51
|
-
super
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def respond_to_missing?(meth, *args)
|
56
|
-
if meth.to_s.end_with?('?')
|
57
|
-
!find_machine_by_state(meth[0...-1]).nil?
|
58
|
-
elsif meth.to_s.end_with?('!')
|
59
|
-
!find_machine_by_event(meth[0...-1]).nil?
|
60
|
-
else
|
61
|
-
super
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def find_machine_by_event(name)
|
68
|
-
state_machines.select { |machine| machine.event?(name) }.first
|
69
|
-
end
|
70
|
-
|
71
|
-
def find_machine_by_state(name)
|
72
|
-
state_machines.select { |machine| machine.state?(name) }.first
|
73
|
-
end
|
74
|
-
|
75
|
-
def state_machines
|
76
|
-
self.class.state_machines
|
77
|
-
end
|
78
|
-
end
|
79
31
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Statum
|
2
|
+
module ClassMethods
|
3
|
+
# Define new state machine
|
4
|
+
#
|
5
|
+
# @param [Symbol] field Field to store state
|
6
|
+
# @param [Hash] options Options
|
7
|
+
# @option options [Symbol] initial Initial value
|
8
|
+
# @param [Block] block Bloc with DSL
|
9
|
+
def statum(field, options = {}, &block)
|
10
|
+
definer = Statum::StateDefiner.new(self, field, options)
|
11
|
+
definer.instance_eval(&block) if block_given?
|
12
|
+
add_machine(definer.state_machine)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns defined state machines
|
16
|
+
#
|
17
|
+
# @return [Array<Statum::Machine>]
|
18
|
+
def state_machines
|
19
|
+
instance_variable_get(STATE_MACHINES_VARIABLE) || []
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Add new state machine
|
25
|
+
#
|
26
|
+
# @param [Statum::Machine] machine New state machine
|
27
|
+
# @raise Statum::ExistingMachineError
|
28
|
+
def add_machine(machine)
|
29
|
+
if state_machines.any? { |m| m.name == machine.name }
|
30
|
+
raise Statum::ExistingMachineError, "State machine for #{machine.name} already exists"
|
31
|
+
end
|
32
|
+
instance_variable_set(STATE_MACHINES_VARIABLE, state_machines + [machine])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/statum/event.rb
CHANGED
@@ -3,18 +3,18 @@ module Statum
|
|
3
3
|
#
|
4
4
|
# @attr [Statum::Hook] before Before hook object
|
5
5
|
# @attr [Statum::Hook] after After hook object
|
6
|
-
# @attr [Symbol
|
6
|
+
# @attr [Symbol, Array] from From state name (or names)
|
7
7
|
# @attr [Symbol] to To state name
|
8
8
|
class Event
|
9
9
|
attr_reader :from, :to, :before, :after
|
10
10
|
|
11
11
|
# Creates an event class
|
12
12
|
#
|
13
|
-
# @param [
|
14
|
-
# @param [
|
13
|
+
# @param [Symbol, Array<Symbol>] from From state name
|
14
|
+
# @param [Symbol] to To state name
|
15
15
|
# @param [Hash] options Options for event
|
16
16
|
def initialize(from, to, options = {})
|
17
|
-
@from = from.is_a?(Array) ? from : from.to_sym
|
17
|
+
@from = from.is_a?(Array) ? from.map(&:to_sym) : from.to_sym
|
18
18
|
@to = to.to_sym
|
19
19
|
@before = Statum::Hook.new(options.fetch(:before, nil))
|
20
20
|
@after = Statum::Hook.new(options.fetch(:after, nil))
|
@@ -22,7 +22,7 @@ module Statum
|
|
22
22
|
|
23
23
|
# Returns true if event can be fired from current state
|
24
24
|
#
|
25
|
-
# @param [
|
25
|
+
# @param [Symbol] current_state Current state
|
26
26
|
#
|
27
27
|
# @return [Boolean]
|
28
28
|
def can_fire?(current_state)
|
data/lib/statum/hook.rb
CHANGED
@@ -3,7 +3,7 @@ module Statum
|
|
3
3
|
class Hook
|
4
4
|
# Creates new Hook instance
|
5
5
|
#
|
6
|
-
# @param [Symbol
|
6
|
+
# @param [Symbol, Proc] hook Callable object or symbol that represents instance method
|
7
7
|
def initialize(hook)
|
8
8
|
@hook = hook
|
9
9
|
end
|
@@ -23,6 +23,11 @@ module Statum
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
+
# Finds hook on instance
|
27
|
+
#
|
28
|
+
# @param [Object] instance Instance of class that included Statum
|
29
|
+
#
|
30
|
+
# @return [Proc]
|
26
31
|
def find_hook(instance)
|
27
32
|
@hook.respond_to?(:call) ? @hook : instance.method(@hook)
|
28
33
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Statum
|
2
|
+
module InstanceMethods
|
3
|
+
def method_missing(meth, *args)
|
4
|
+
if meth.to_s.end_with?('?') && (machine = find_machine_by_state(meth[0...-1]))
|
5
|
+
machine.current(self) == meth[0...-1].to_sym
|
6
|
+
elsif meth.to_s.end_with?('!') && (machine = find_machine_by_event(meth[0...-1]))
|
7
|
+
machine.fire!(self, meth[0...-1])
|
8
|
+
else
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to_missing?(meth, *args)
|
14
|
+
if meth.to_s.end_with?('?')
|
15
|
+
!find_machine_by_state(meth[0...-1]).nil?
|
16
|
+
elsif meth.to_s.end_with?('!')
|
17
|
+
!find_machine_by_event(meth[0...-1]).nil?
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_machine_by_event(name)
|
26
|
+
state_machines.select { |machine| machine.event?(name) }.first
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_machine_by_state(name)
|
30
|
+
state_machines.select { |machine| machine.state?(name) }.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def state_machines
|
34
|
+
self.class.state_machines
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/statum/machine.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Statum
|
2
2
|
# Class for representing event machine
|
3
|
+
#
|
4
|
+
# @attr_reader [Hash] events Events
|
5
|
+
# @attr_reader [Array<Symbol>] states States
|
6
|
+
# @attr_reader [Symbol] field State field
|
3
7
|
class Machine
|
4
8
|
attr_reader :events, :states, :field
|
5
9
|
|
@@ -9,6 +13,10 @@ module Statum
|
|
9
13
|
# Creates machine instance
|
10
14
|
#
|
11
15
|
# @param [Hash] options options hash
|
16
|
+
# @option options [Symbol] field Field to store state
|
17
|
+
# @option options [Symbol] initial Initial state
|
18
|
+
# @option options [Array<Symbol>] states States
|
19
|
+
# @option options [Hash] events Events
|
12
20
|
def initialize(options)
|
13
21
|
@field = options.delete(:field)
|
14
22
|
@initial = options.delete(:initial)
|
@@ -18,7 +26,7 @@ module Statum
|
|
18
26
|
|
19
27
|
# Checks if state present
|
20
28
|
#
|
21
|
-
# @param [
|
29
|
+
# @param [Symbol] name state name
|
22
30
|
#
|
23
31
|
# @return [Boolean]
|
24
32
|
def state?(name)
|
@@ -27,7 +35,7 @@ module Statum
|
|
27
35
|
|
28
36
|
# Checks if event present
|
29
37
|
#
|
30
|
-
# @param [
|
38
|
+
# @param [Symbol] name event name
|
31
39
|
#
|
32
40
|
# @return [Boolean]
|
33
41
|
def event?(name)
|
@@ -37,7 +45,10 @@ module Statum
|
|
37
45
|
# Execute an event
|
38
46
|
#
|
39
47
|
# @param [Object] instance Instance of class, that includes Statum
|
40
|
-
# @param [
|
48
|
+
# @param [Symbol] name Event name
|
49
|
+
#
|
50
|
+
# @raise Statum::UnknownEventError
|
51
|
+
# @raise Statum::ErrorTransitionError
|
41
52
|
def fire!(instance, name)
|
42
53
|
raise Statum::UnknownEventError, "Event #{name} not found" unless event?(name)
|
43
54
|
|
data/lib/statum/state_definer.rb
CHANGED
@@ -6,6 +6,7 @@ module Statum
|
|
6
6
|
# @param [Class] klass Class that includes Statum
|
7
7
|
# @param [String|Symbol] field Field that will be used for storing current state
|
8
8
|
# @param [Hash] options Hash options
|
9
|
+
# @option options [Symbol] initial Initial value
|
9
10
|
def initialize(klass, field, options)
|
10
11
|
@klass = klass
|
11
12
|
@field = field.to_sym
|
@@ -16,7 +17,7 @@ module Statum
|
|
16
17
|
state(@initial) unless @initial.nil?
|
17
18
|
end
|
18
19
|
|
19
|
-
# Returns state
|
20
|
+
# Returns state machine
|
20
21
|
#
|
21
22
|
# @return [Statum::Machine]
|
22
23
|
def state_machine
|
@@ -30,7 +31,7 @@ module Statum
|
|
30
31
|
|
31
32
|
# Define a new state
|
32
33
|
#
|
33
|
-
# @param [
|
34
|
+
# @param [Symbol] name State name
|
34
35
|
def state(name)
|
35
36
|
@states << name.to_sym unless @states.include?(name.to_sym)
|
36
37
|
end
|
data/lib/statum/version.rb
CHANGED
data/statum.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.bindir = "exe"
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
|
+
spec.required_ruby_version = ">= 2.0"
|
22
23
|
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.16"
|
24
25
|
spec.add_development_dependency "coveralls", "~> 0.8"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Bespalov
|
@@ -99,8 +99,10 @@ files:
|
|
99
99
|
- bin/console
|
100
100
|
- bin/setup
|
101
101
|
- lib/statum.rb
|
102
|
+
- lib/statum/class_methods.rb
|
102
103
|
- lib/statum/event.rb
|
103
104
|
- lib/statum/hook.rb
|
105
|
+
- lib/statum/instance_methods.rb
|
104
106
|
- lib/statum/machine.rb
|
105
107
|
- lib/statum/state_definer.rb
|
106
108
|
- lib/statum/version.rb
|
@@ -117,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
119
|
requirements:
|
118
120
|
- - ">="
|
119
121
|
- !ruby/object:Gem::Version
|
120
|
-
version: '0'
|
122
|
+
version: '2.0'
|
121
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
124
|
requirements:
|
123
125
|
- - ">="
|