enum_state_machine 0.0.2 → 0.1.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 +4 -4
- data/.gitignore +0 -12
- data/.ruby-version +1 -1
- data/.ruby-version.orig +5 -0
- data/Gemfile +0 -1
- data/Rakefile +0 -18
- data/enum_state_machine.gemspec +35 -0
- data/enum_state_machine.gemspec.orig +43 -0
- data/lib/enum_state_machine/assertions.rb +36 -0
- data/lib/enum_state_machine/branch.rb +225 -0
- data/lib/enum_state_machine/callback.rb +232 -0
- data/lib/enum_state_machine/core.rb +12 -0
- data/lib/enum_state_machine/core_ext/class/state_machine.rb +5 -0
- data/lib/enum_state_machine/core_ext.rb +2 -0
- data/lib/enum_state_machine/error.rb +13 -0
- data/lib/enum_state_machine/eval_helpers.rb +87 -0
- data/lib/enum_state_machine/event.rb +257 -0
- data/lib/enum_state_machine/event_collection.rb +141 -0
- data/lib/enum_state_machine/extensions.rb +149 -0
- data/lib/enum_state_machine/graph.rb +93 -0
- data/lib/enum_state_machine/helper_module.rb +17 -0
- data/lib/enum_state_machine/initializers/rails.rb +22 -0
- data/lib/enum_state_machine/initializers.rb +4 -0
- data/lib/enum_state_machine/integrations/active_model/locale.rb +11 -0
- data/lib/enum_state_machine/integrations/active_model/observer.rb +33 -0
- data/lib/enum_state_machine/integrations/active_model/observer_update.rb +42 -0
- data/lib/enum_state_machine/integrations/active_model/versions.rb +31 -0
- data/lib/enum_state_machine/integrations/active_model.rb +585 -0
- data/lib/enum_state_machine/integrations/active_record/locale.rb +20 -0
- data/lib/enum_state_machine/integrations/active_record/versions.rb +123 -0
- data/lib/enum_state_machine/integrations/active_record.rb +548 -0
- data/lib/enum_state_machine/integrations/base.rb +100 -0
- data/lib/enum_state_machine/integrations.rb +97 -0
- data/lib/enum_state_machine/machine.rb +2292 -0
- data/lib/enum_state_machine/machine_collection.rb +86 -0
- data/lib/enum_state_machine/macro_methods.rb +518 -0
- data/lib/enum_state_machine/matcher.rb +123 -0
- data/lib/enum_state_machine/matcher_helpers.rb +54 -0
- data/lib/enum_state_machine/node_collection.rb +222 -0
- data/lib/enum_state_machine/path.rb +120 -0
- data/lib/enum_state_machine/path_collection.rb +90 -0
- data/lib/enum_state_machine/state.rb +297 -0
- data/lib/enum_state_machine/state_collection.rb +112 -0
- data/lib/enum_state_machine/state_context.rb +138 -0
- data/lib/enum_state_machine/state_enum.rb +23 -0
- data/lib/enum_state_machine/transition.rb +470 -0
- data/lib/enum_state_machine/transition_collection.rb +245 -0
- data/lib/enum_state_machine/version.rb +3 -0
- data/lib/enum_state_machine/yard/handlers/base.rb +32 -0
- data/lib/enum_state_machine/yard/handlers/event.rb +25 -0
- data/lib/enum_state_machine/yard/handlers/machine.rb +344 -0
- data/lib/enum_state_machine/yard/handlers/state.rb +25 -0
- data/lib/enum_state_machine/yard/handlers/transition.rb +47 -0
- data/lib/enum_state_machine/yard/handlers.rb +12 -0
- data/lib/enum_state_machine/yard/templates/default/class/html/setup.rb +30 -0
- data/lib/enum_state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
- data/lib/enum_state_machine/yard/templates.rb +3 -0
- data/lib/enum_state_machine/yard.rb +8 -0
- data/lib/enum_state_machine.rb +9 -0
- data/lib/tasks/enum_state_machine.rake +1 -0
- data/lib/tasks/enum_state_machine.rb +24 -0
- data/lib/yard-enum_state_machine.rb +2 -0
- data/test/functional/state_machine_test.rb +1066 -0
- data/test/unit/graph_test.rb +9 -5
- data/test/unit/integrations/active_model_test.rb +1245 -0
- data/test/unit/integrations/active_record_test.rb +2551 -0
- data/test/unit/integrations/base_test.rb +104 -0
- data/test/unit/integrations_test.rb +71 -0
- data/test/unit/invalid_event_test.rb +20 -0
- data/test/unit/invalid_parallel_transition_test.rb +18 -0
- data/test/unit/invalid_transition_test.rb +115 -0
- data/test/unit/machine_collection_test.rb +603 -0
- data/test/unit/machine_test.rb +3395 -0
- data/test/unit/state_machine_test.rb +31 -0
- metadata +212 -44
- data/Appraisals +0 -28
- data/gemfiles/active_model_4.0.4.gemfile +0 -9
- data/gemfiles/active_model_4.0.4.gemfile.lock +0 -51
- data/gemfiles/active_record_4.0.4.gemfile +0 -11
- data/gemfiles/active_record_4.0.4.gemfile.lock +0 -61
- data/gemfiles/default.gemfile +0 -7
- data/gemfiles/default.gemfile.lock +0 -27
- data/gemfiles/graphviz_1.0.9.gemfile +0 -7
- data/gemfiles/graphviz_1.0.9.gemfile.lock +0 -30
@@ -0,0 +1,93 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'ruby-graphviz', '>=0.9.17'
|
4
|
+
require 'graphviz'
|
5
|
+
rescue LoadError => ex
|
6
|
+
$stderr.puts "Cannot draw the machine (#{ex.message}). `gem install ruby-graphviz` >= v0.9.17 and try again."
|
7
|
+
raise
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'enum_state_machine/assertions'
|
11
|
+
|
12
|
+
module EnumStateMachine
|
13
|
+
# Provides a set of higher-order features on top of the raw GraphViz graphs
|
14
|
+
class Graph < GraphViz
|
15
|
+
include Assertions
|
16
|
+
|
17
|
+
# The name of the font to draw state names in
|
18
|
+
attr_reader :font
|
19
|
+
|
20
|
+
# The graph's full filename
|
21
|
+
attr_reader :file_path
|
22
|
+
|
23
|
+
# The image format to generate the graph in
|
24
|
+
attr_reader :file_format
|
25
|
+
|
26
|
+
# Creates a new graph with the given name.
|
27
|
+
#
|
28
|
+
# Configuration options:
|
29
|
+
# * <tt>:path</tt> - The path to write the graph file to. Default is the
|
30
|
+
# current directory (".").
|
31
|
+
# * <tt>:format</tt> - The image format to generate the graph in.
|
32
|
+
# Default is "png'.
|
33
|
+
# * <tt>:font</tt> - The name of the font to draw state names in.
|
34
|
+
# Default is "Arial".
|
35
|
+
# * <tt>:orientation</tt> - The direction of the graph ("portrait" or
|
36
|
+
# "landscape"). Default is "portrait".
|
37
|
+
def initialize(name, options = {})
|
38
|
+
font = (RUBY_PLATFORM =~ /darwin/) ? 'ArialMT' : 'Arial'
|
39
|
+
options = {:path => '.', :format => 'png', :font => font, :orientation => 'portrait'}.merge(options)
|
40
|
+
assert_valid_keys(options, :path, :format, :font, :orientation)
|
41
|
+
|
42
|
+
@font = options[:font]
|
43
|
+
@file_path = File.join(options[:path], "#{name}.#{options[:format]}")
|
44
|
+
@file_format = options[:format]
|
45
|
+
|
46
|
+
super('G', :rankdir => options[:orientation] == 'landscape' ? 'LR' : 'TB')
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generates the actual image file based on the nodes / edges added to the
|
50
|
+
# graph. The path to the file is based on the configuration options for
|
51
|
+
# this graph.
|
52
|
+
def output
|
53
|
+
super(@file_format => @file_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Adds a new node to the graph. The font for the node will be automatically
|
57
|
+
# set based on the graph configuration. The generated node will be returned.
|
58
|
+
#
|
59
|
+
# For example,
|
60
|
+
#
|
61
|
+
# graph = EnumStateMachine::Graph.new('test')
|
62
|
+
# graph.add_nodes('parked', :label => 'Parked', :width => '1', :height => '1', :shape => 'ellipse')
|
63
|
+
def add_nodes(*args)
|
64
|
+
node = v0_api? ? add_node(*args) : super
|
65
|
+
node.fontname = @font
|
66
|
+
node
|
67
|
+
end
|
68
|
+
|
69
|
+
# Adds a new edge to the graph. The font for the edge will be automatically
|
70
|
+
# set based on the graph configuration. The generated edge will be returned.
|
71
|
+
#
|
72
|
+
# For example,
|
73
|
+
#
|
74
|
+
# graph = EnumStateMachine::Graph.new('test')
|
75
|
+
# graph.add_edges('parked', 'idling', :label => 'ignite')
|
76
|
+
def add_edges(*args)
|
77
|
+
edge = v0_api? ? add_edge(*args) : super
|
78
|
+
edge.fontname = @font
|
79
|
+
edge
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
# Determines whether the old v0 api is in use
|
84
|
+
def v0_api?
|
85
|
+
version[0] == '0' || version[0] == '1' && version[1] == '0' && version[2] <= '2'
|
86
|
+
end
|
87
|
+
|
88
|
+
# The ruby-graphviz version data
|
89
|
+
def version
|
90
|
+
Constants::RGV_VERSION.split('.')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EnumStateMachine
|
2
|
+
# Represents a type of module that defines instance / class methods for a
|
3
|
+
# state machine
|
4
|
+
class HelperModule < Module #:nodoc:
|
5
|
+
def initialize(machine, kind)
|
6
|
+
@machine = machine
|
7
|
+
@kind = kind
|
8
|
+
end
|
9
|
+
|
10
|
+
# Provides a human-readable description of the module
|
11
|
+
def to_s
|
12
|
+
owner_class = @machine.owner_class
|
13
|
+
owner_class_name = owner_class.name && !owner_class.name.empty? ? owner_class.name : owner_class.to_s
|
14
|
+
"#{owner_class_name} #{@machine.name.inspect} #{@kind} helpers"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if defined?(Rails)
|
2
|
+
# Track all of the applicable locales to load
|
3
|
+
locale_paths = []
|
4
|
+
EnumStateMachine::Integrations.all.each do |integration|
|
5
|
+
locale_paths << integration.locale_path if integration.available? && integration.locale_path
|
6
|
+
end
|
7
|
+
|
8
|
+
if defined?(Rails::Engine)
|
9
|
+
# Rails 3.x
|
10
|
+
class EnumStateMachine::RailsEngine < Rails::Engine
|
11
|
+
rake_tasks do
|
12
|
+
load 'tasks/enum_state_machine.rb'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 0
|
17
|
+
EnumStateMachine::RailsEngine.paths.config.locales = locale_paths
|
18
|
+
else
|
19
|
+
EnumStateMachine::RailsEngine.paths['config/locales'] = locale_paths
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{:en => {
|
2
|
+
:activemodel => {
|
3
|
+
:errors => {
|
4
|
+
:messages => {
|
5
|
+
:invalid => EnumStateMachine::Machine.default_messages[:invalid],
|
6
|
+
:invalid_event => EnumStateMachine::Machine.default_messages[:invalid_event] % ['%{state}'],
|
7
|
+
:invalid_transition => EnumStateMachine::Machine.default_messages[:invalid_transition] % ['%{event}']
|
8
|
+
}
|
9
|
+
}
|
10
|
+
}
|
11
|
+
}}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module EnumStateMachine
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module ActiveModel
|
4
|
+
# Adds support for invoking callbacks on ActiveModel observers with more
|
5
|
+
# than one argument (e.g. the record *and* the state transition). By
|
6
|
+
# default, ActiveModel only supports passing the record into the
|
7
|
+
# callbacks.
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
#
|
11
|
+
# class VehicleObserver < ActiveModel::Observer
|
12
|
+
# # The default behavior: only pass in the record
|
13
|
+
# def after_save(vehicle)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # Custom behavior: allow the transition to be passed in as well
|
17
|
+
# def after_transition(vehicle, transition)
|
18
|
+
# Audit.log(vehicle, transition)
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
module Observer
|
22
|
+
def update_with_transition(observer_update)
|
23
|
+
method = observer_update.method
|
24
|
+
send(method, *observer_update.args) if respond_to?(method)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveModel::Observer.class_eval do
|
32
|
+
include EnumStateMachine::Integrations::ActiveModel::Observer
|
33
|
+
end if defined?(ActiveModel::Observer)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module EnumStateMachine
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module ActiveModel
|
4
|
+
# Represents the encapsulation of all of the details to be included in an
|
5
|
+
# update to state machine observers. This allows multiple arguments to
|
6
|
+
# get passed to an observer method (instead of just a single +object+)
|
7
|
+
# while still respecting the way in which ActiveModel checks for the
|
8
|
+
# object's list of observers.
|
9
|
+
class ObserverUpdate
|
10
|
+
# The method to invoke on the observer
|
11
|
+
attr_reader :method
|
12
|
+
|
13
|
+
# The object being transitioned
|
14
|
+
attr_reader :object
|
15
|
+
|
16
|
+
# The transition being run
|
17
|
+
attr_reader :transition
|
18
|
+
|
19
|
+
def initialize(method, object, transition) #:nodoc:
|
20
|
+
@method, @object, @transition = method, object, transition
|
21
|
+
end
|
22
|
+
|
23
|
+
# The arguments to pass into the method
|
24
|
+
def args
|
25
|
+
[object, transition]
|
26
|
+
end
|
27
|
+
|
28
|
+
# The class of the object being transitioned. Normally the object
|
29
|
+
# getting passed into observer methods is the actual instance of the
|
30
|
+
# ActiveModel class. ActiveModel uses that instance's class to check
|
31
|
+
# for enabled / disabled observers.
|
32
|
+
#
|
33
|
+
# Since state_machine is passing an ObserverUpdate instance into observer
|
34
|
+
# methods, +class+ needs to be overridden so that ActiveModel can still
|
35
|
+
# get access to the enabled / disabled observers.
|
36
|
+
def class
|
37
|
+
object.class
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module EnumStateMachine
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module ActiveModel
|
4
|
+
version '2.x' do
|
5
|
+
def self.active?
|
6
|
+
!defined?(::ActiveModel::VERSION) || ::ActiveModel::VERSION::MAJOR == 2
|
7
|
+
end
|
8
|
+
|
9
|
+
def define_validation_hook
|
10
|
+
define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
|
11
|
+
def valid?(*)
|
12
|
+
self.class.state_machines.transitions(self, #{action.inspect}, :after => false).perform { super }
|
13
|
+
end
|
14
|
+
end_eval
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
version '3.0.x' do
|
19
|
+
def self.active?
|
20
|
+
defined?(::ActiveModel::VERSION) && ::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def define_validation_hook
|
24
|
+
# +around+ callbacks don't have direct access to results until AS 3.1
|
25
|
+
owner_class.set_callback(:validation, :after, 'value', :prepend => true)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|