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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -12
  3. data/.ruby-version +1 -1
  4. data/.ruby-version.orig +5 -0
  5. data/Gemfile +0 -1
  6. data/Rakefile +0 -18
  7. data/enum_state_machine.gemspec +35 -0
  8. data/enum_state_machine.gemspec.orig +43 -0
  9. data/lib/enum_state_machine/assertions.rb +36 -0
  10. data/lib/enum_state_machine/branch.rb +225 -0
  11. data/lib/enum_state_machine/callback.rb +232 -0
  12. data/lib/enum_state_machine/core.rb +12 -0
  13. data/lib/enum_state_machine/core_ext/class/state_machine.rb +5 -0
  14. data/lib/enum_state_machine/core_ext.rb +2 -0
  15. data/lib/enum_state_machine/error.rb +13 -0
  16. data/lib/enum_state_machine/eval_helpers.rb +87 -0
  17. data/lib/enum_state_machine/event.rb +257 -0
  18. data/lib/enum_state_machine/event_collection.rb +141 -0
  19. data/lib/enum_state_machine/extensions.rb +149 -0
  20. data/lib/enum_state_machine/graph.rb +93 -0
  21. data/lib/enum_state_machine/helper_module.rb +17 -0
  22. data/lib/enum_state_machine/initializers/rails.rb +22 -0
  23. data/lib/enum_state_machine/initializers.rb +4 -0
  24. data/lib/enum_state_machine/integrations/active_model/locale.rb +11 -0
  25. data/lib/enum_state_machine/integrations/active_model/observer.rb +33 -0
  26. data/lib/enum_state_machine/integrations/active_model/observer_update.rb +42 -0
  27. data/lib/enum_state_machine/integrations/active_model/versions.rb +31 -0
  28. data/lib/enum_state_machine/integrations/active_model.rb +585 -0
  29. data/lib/enum_state_machine/integrations/active_record/locale.rb +20 -0
  30. data/lib/enum_state_machine/integrations/active_record/versions.rb +123 -0
  31. data/lib/enum_state_machine/integrations/active_record.rb +548 -0
  32. data/lib/enum_state_machine/integrations/base.rb +100 -0
  33. data/lib/enum_state_machine/integrations.rb +97 -0
  34. data/lib/enum_state_machine/machine.rb +2292 -0
  35. data/lib/enum_state_machine/machine_collection.rb +86 -0
  36. data/lib/enum_state_machine/macro_methods.rb +518 -0
  37. data/lib/enum_state_machine/matcher.rb +123 -0
  38. data/lib/enum_state_machine/matcher_helpers.rb +54 -0
  39. data/lib/enum_state_machine/node_collection.rb +222 -0
  40. data/lib/enum_state_machine/path.rb +120 -0
  41. data/lib/enum_state_machine/path_collection.rb +90 -0
  42. data/lib/enum_state_machine/state.rb +297 -0
  43. data/lib/enum_state_machine/state_collection.rb +112 -0
  44. data/lib/enum_state_machine/state_context.rb +138 -0
  45. data/lib/enum_state_machine/state_enum.rb +23 -0
  46. data/lib/enum_state_machine/transition.rb +470 -0
  47. data/lib/enum_state_machine/transition_collection.rb +245 -0
  48. data/lib/enum_state_machine/version.rb +3 -0
  49. data/lib/enum_state_machine/yard/handlers/base.rb +32 -0
  50. data/lib/enum_state_machine/yard/handlers/event.rb +25 -0
  51. data/lib/enum_state_machine/yard/handlers/machine.rb +344 -0
  52. data/lib/enum_state_machine/yard/handlers/state.rb +25 -0
  53. data/lib/enum_state_machine/yard/handlers/transition.rb +47 -0
  54. data/lib/enum_state_machine/yard/handlers.rb +12 -0
  55. data/lib/enum_state_machine/yard/templates/default/class/html/setup.rb +30 -0
  56. data/lib/enum_state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  57. data/lib/enum_state_machine/yard/templates.rb +3 -0
  58. data/lib/enum_state_machine/yard.rb +8 -0
  59. data/lib/enum_state_machine.rb +9 -0
  60. data/lib/tasks/enum_state_machine.rake +1 -0
  61. data/lib/tasks/enum_state_machine.rb +24 -0
  62. data/lib/yard-enum_state_machine.rb +2 -0
  63. data/test/functional/state_machine_test.rb +1066 -0
  64. data/test/unit/graph_test.rb +9 -5
  65. data/test/unit/integrations/active_model_test.rb +1245 -0
  66. data/test/unit/integrations/active_record_test.rb +2551 -0
  67. data/test/unit/integrations/base_test.rb +104 -0
  68. data/test/unit/integrations_test.rb +71 -0
  69. data/test/unit/invalid_event_test.rb +20 -0
  70. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  71. data/test/unit/invalid_transition_test.rb +115 -0
  72. data/test/unit/machine_collection_test.rb +603 -0
  73. data/test/unit/machine_test.rb +3395 -0
  74. data/test/unit/state_machine_test.rb +31 -0
  75. metadata +212 -44
  76. data/Appraisals +0 -28
  77. data/gemfiles/active_model_4.0.4.gemfile +0 -9
  78. data/gemfiles/active_model_4.0.4.gemfile.lock +0 -51
  79. data/gemfiles/active_record_4.0.4.gemfile +0 -11
  80. data/gemfiles/active_record_4.0.4.gemfile.lock +0 -61
  81. data/gemfiles/default.gemfile +0 -7
  82. data/gemfiles/default.gemfile.lock +0 -27
  83. data/gemfiles/graphviz_1.0.9.gemfile +0 -7
  84. 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,4 @@
1
+ # Load each application initializer
2
+ Dir["#{File.dirname(__FILE__)}/initializers/*.rb"].sort.each do |path|
3
+ require "enum_state_machine/initializers/#{File.basename(path)}"
4
+ 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