finity 0.0.3 → 0.0.4
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.
- data/LICENSE +1 -1
- data/README.md +35 -28
- data/lib/finity.rb +4 -5
- data/lib/finity/event.rb +1 -1
- data/lib/finity/machine.rb +27 -16
- data/lib/finity/state.rb +1 -1
- data/lib/finity/transition.rb +1 -1
- data/lib/finity/version.rb +1 -1
- metadata +38 -36
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,28 @@
|
|
1
1
|
# Finity
|
2
2
|
|
3
|
-
**Finity** tries to be an extremly lightweight state machine implementation
|
4
|
-
which is essential if you have tens or hundreds
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
The goal of **Finity** is to provide a state machine implementation which is as
|
10
|
-
while maintaining a beautiful and readable syntax. If
|
11
|
-
[transitions][] is your weapon of
|
12
|
-
|
3
|
+
**Finity** tries to be an extremly lightweight state machine implementation
|
4
|
+
with an easily readable syntax which is essential if you have tens or hundreds
|
5
|
+
of transitions. It is inspired by [transitions][], a great state machine
|
6
|
+
implementation tightly integrated with ActiveRecord by Jakub Kuźma and
|
7
|
+
Timo Rößner.
|
8
|
+
|
9
|
+
The goal of **Finity** is to provide a state machine implementation which is as
|
10
|
+
slim and fast as possible while maintaining a beautiful and readable syntax. If
|
11
|
+
you need ActiveModel/ActiveRecord integration,[transitions][] is your weapon of
|
12
|
+
choice. However, if you only need a plain state machine implementation which is
|
13
|
+
optimized for readability and efficiency, give **Finity** a spin.
|
13
14
|
|
14
15
|
## Installation
|
15
16
|
|
16
|
-
If you use Rails, include this into your Gemfile and run `bundle install` via
|
17
|
+
If you use Rails, include this into your Gemfile and run `bundle install` via
|
18
|
+
command line:
|
17
19
|
|
18
|
-
```
|
20
|
+
``` ruby
|
19
21
|
gem 'finity'
|
20
22
|
```
|
21
23
|
|
22
|
-
If you're not using Rails, you can install **Finity** with `gem` via command
|
24
|
+
If you're not using Rails, you can install **Finity** with `gem` via command
|
25
|
+
line:
|
23
26
|
|
24
27
|
```
|
25
28
|
gem install finity
|
@@ -27,11 +30,12 @@ gem install finity
|
|
27
30
|
|
28
31
|
## Usage
|
29
32
|
|
30
|
-
**Finity** can transform any class into a state machine. The only thing you
|
31
|
-
and define some transitions. For example, consider
|
32
|
-
the contents of a
|
33
|
+
**Finity** can transform any class into a state machine. The only thing you
|
34
|
+
have to do is to include it and define some transitions. For example, consider
|
35
|
+
a state machine modelling the different states of reading the contents of a
|
36
|
+
file:
|
33
37
|
|
34
|
-
```
|
38
|
+
``` ruby
|
35
39
|
class Readfile
|
36
40
|
include Finity
|
37
41
|
|
@@ -65,10 +69,11 @@ end
|
|
65
69
|
|
66
70
|
## States
|
67
71
|
|
68
|
-
A state is defined by its name and can define transition functions upon
|
69
|
-
These functions can be either referenced as
|
72
|
+
A state is defined by its name and can define transition functions upon
|
73
|
+
entering and leaving the state. These functions can be either referenced as
|
74
|
+
Symbols, Strings, Procs or Lambda:
|
70
75
|
|
71
|
-
```
|
76
|
+
``` ruby
|
72
77
|
state :some_state,
|
73
78
|
:enter => proc { do_something and some_other_thing },
|
74
79
|
:leave => :execute_leave_action!
|
@@ -76,11 +81,12 @@ state :some_state,
|
|
76
81
|
|
77
82
|
## Events and Transitions
|
78
83
|
|
79
|
-
Events are like states defined by their names and can trigger several
|
80
|
-
to other states. The transitions are evaluated
|
81
|
-
|
84
|
+
Events are like states defined by their names and can trigger several
|
85
|
+
transitions from several states to other states. The transitions are evaluated
|
86
|
+
in the order they are defined. If a valid transition is found, the execution is
|
87
|
+
stopped and the transition performed:
|
82
88
|
|
83
|
-
```
|
89
|
+
``` ruby
|
84
90
|
event :some_event do
|
85
91
|
transitions :from => [:some_state, :another_state], :to => :another_state,
|
86
92
|
:if => proc { is_some_condition_true? },
|
@@ -91,12 +97,13 @@ event :some_event do
|
|
91
97
|
end
|
92
98
|
```
|
93
99
|
|
94
|
-
Transitions can be guarded by decision functions (`:if`) and execute another
|
95
|
-
matching (`:do`). Transitions are triggered by the
|
96
|
-
|
100
|
+
Transitions can be guarded by decision functions (`:if`) and execute another
|
101
|
+
function upon successful matching (`:do`). Transitions are triggered by the
|
102
|
+
method `event!` which is defined for the including object. Many other state
|
103
|
+
machine implementations define one method for each event and for each state,
|
97
104
|
however, **Finity** tries to be as minimally invasive as possible:
|
98
105
|
|
99
|
-
```
|
106
|
+
``` ruby
|
100
107
|
object = SomeClassIncludingFinity.new
|
101
108
|
if object.state? :some_state
|
102
109
|
object.event! :some_event
|
data/lib/finity.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2012 Martin Donath
|
1
|
+
# Copyright (c) 2012 Martin Donath <md@struct.cc>
|
2
2
|
|
3
3
|
# Permission is hereby granted, free of charge, to any person
|
4
4
|
# obtaining a copy of this software and associated documentation files
|
@@ -33,22 +33,21 @@ module Finity
|
|
33
33
|
|
34
34
|
# Class methods to be injected into the including class upon inclusion.
|
35
35
|
module ClassMethods
|
36
|
-
attr_accessor :machine
|
37
36
|
|
38
37
|
# Instantiate a new state machine for the including class by accepting a
|
39
38
|
# block with state and event (and subsequent transition) definitions.
|
40
39
|
def finity options = {}, &block
|
41
|
-
@
|
40
|
+
@finity ||= Machine.new self, options, &block
|
42
41
|
end
|
43
42
|
|
44
43
|
# Return the names of all registered states.
|
45
44
|
def states
|
46
|
-
@
|
45
|
+
@finity.states.map { |name, _| name }
|
47
46
|
end
|
48
47
|
|
49
48
|
# Return the names of all registered events.
|
50
49
|
def events
|
51
|
-
@
|
50
|
+
@finity.events.map { |name, _| name }
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
data/lib/finity/event.rb
CHANGED
data/lib/finity/machine.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2012 Martin Donath
|
1
|
+
# Copyright (c) 2012 Martin Donath <md@struct.cc>
|
2
2
|
|
3
3
|
# Permission is hereby granted, free of charge, to any person
|
4
4
|
# obtaining a copy of this software and associated documentation files
|
@@ -22,25 +22,35 @@
|
|
22
22
|
|
23
23
|
module Finity
|
24
24
|
class Machine
|
25
|
-
attr_accessor :states, :events
|
25
|
+
attr_accessor :states, :events
|
26
26
|
|
27
27
|
# Initialize a new state machine within the provided class and define
|
28
28
|
# methods for querying the current state and initiating transitions.
|
29
|
+
# The current state must be bound to the including instance, otherwise
|
30
|
+
# there may be problems due to caching between requests.
|
29
31
|
def initialize klass, options = {}, &block
|
30
|
-
@klass, @states, @events
|
32
|
+
@klass, @states, @events = klass, {}, {}
|
33
|
+
instance_eval &block if block_given?
|
34
|
+
@initial = current = options.delete(:initial) || initial
|
35
|
+
@klass.send :define_method, :current do |*args|
|
36
|
+
unless self.instance_variable_defined? :@current
|
37
|
+
self.instance_variable_set :@current, current
|
38
|
+
end
|
39
|
+
self.instance_variable_get :@current
|
40
|
+
end
|
31
41
|
@klass.send :define_method, :event! do |*args|
|
32
|
-
|
42
|
+
self.instance_variable_set :@current, (
|
43
|
+
klass.finity.update self, self.current, *args
|
44
|
+
)
|
33
45
|
end
|
34
46
|
@klass.send :define_method, :state? do |*args|
|
35
|
-
klass.
|
47
|
+
klass.finity.current.name.eql? *args
|
36
48
|
end
|
37
|
-
instance_eval &block if block_given?
|
38
|
-
@current = inital
|
39
49
|
end
|
40
50
|
|
41
51
|
# Return the name of the initial state.
|
42
|
-
def
|
43
|
-
@
|
52
|
+
def initial
|
53
|
+
@initial ||= @states.keys.first unless @states.first.nil?
|
44
54
|
end
|
45
55
|
|
46
56
|
# Register a state.
|
@@ -55,16 +65,17 @@ module Finity
|
|
55
65
|
|
56
66
|
# An event occured, so update the state machine by evaluating the
|
57
67
|
# transition functions and notify the left and entered state.
|
58
|
-
def update object, event
|
59
|
-
|
60
|
-
if state = @events[event].handle(object,
|
68
|
+
def update object, current, event
|
69
|
+
now ||= @states[current]
|
70
|
+
if state = @events[event].handle(object, now)
|
61
71
|
if @states[state].nil?
|
62
|
-
raise InvalidState, "Invalid state
|
72
|
+
raise InvalidState, "Invalid state #{state}"
|
63
73
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
74
|
+
now.leave object
|
75
|
+
now = @states[current = state]
|
76
|
+
now.enter object
|
67
77
|
end
|
78
|
+
current
|
68
79
|
end
|
69
80
|
end
|
70
81
|
end
|
data/lib/finity/state.rb
CHANGED
data/lib/finity/transition.rb
CHANGED
data/lib/finity/version.rb
CHANGED
metadata
CHANGED
@@ -1,39 +1,36 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: finity
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Martin Donath
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
|
12
|
+
date: 2012-07-17 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
15
16
|
name: bundler
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '1'
|
22
17
|
type: :development
|
23
|
-
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
|
26
|
-
requirements:
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
27
21
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
|
31
|
-
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "1"
|
24
|
+
version:
|
25
|
+
description: Extremly lightweight state machine implementation with an easily readable syntax, which is essential if you have tens or hundreds of transitions.
|
32
26
|
email: md@struct.cc
|
33
27
|
executables: []
|
28
|
+
|
34
29
|
extensions: []
|
30
|
+
|
35
31
|
extra_rdoc_files: []
|
36
|
-
|
32
|
+
|
33
|
+
files:
|
37
34
|
- Gemfile
|
38
35
|
- LICENSE
|
39
36
|
- README.md
|
@@ -44,28 +41,33 @@ files:
|
|
44
41
|
- lib/finity/state.rb
|
45
42
|
- lib/finity/transition.rb
|
46
43
|
- lib/finity/version.rb
|
44
|
+
has_rdoc: true
|
47
45
|
homepage: http://github.com/squidfunk/finity
|
48
46
|
licenses: []
|
47
|
+
|
49
48
|
post_install_message:
|
50
49
|
rdoc_options: []
|
51
|
-
|
50
|
+
|
51
|
+
require_paths:
|
52
52
|
- lib
|
53
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
- !ruby/object:Gem::Version
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
64
63
|
version: 1.3.6
|
64
|
+
version:
|
65
65
|
requirements: []
|
66
|
+
|
66
67
|
rubyforge_project:
|
67
|
-
rubygems_version: 1.
|
68
|
+
rubygems_version: 1.3.5
|
68
69
|
signing_key:
|
69
70
|
specification_version: 3
|
70
71
|
summary: Slim and more readable state machine for Ruby
|
71
72
|
test_files: []
|
73
|
+
|