From 111c9ade29e13ca5295ab229719bac69381211e5 Mon Sep 17 00:00:00 2001 From: Gavin Stark Date: Tue, 21 Jul 2015 10:19:03 -0400 Subject: [PATCH 1/3] Adds a graph_label option to transitions. When present this label will be used in the graphviz output in place of the event label. --- README.md | 18 ++++++++++++++++++ lib/state_machine/branch.rb | 6 +++++- lib/state_machine/event.rb | 10 ++++++++-- state_machine.gemspec | 1 + test/unit/event_test.rb | 22 ++++++++++++++++++++++ 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 511c25a0..18007f5b 100644 --- a/README.md +++ b/README.md @@ -797,6 +797,24 @@ class Vehicle end ``` +#### Transition labels + +If you would prefer a custom label on a graphviz generated graph, specify +the `:graph_label` option on the transition statement. + +For example: + +```ruby + +class Vehicle + state_machine :initial => :parked do + + state :parked do + transition :to => :idling, :on => [:ignite, :shift_up], :if => :seatbelt_on?, :graph_label => "Seatbelt is ON" + end +end +``` + #### Transition context Some flexibility is provided around the context in which transitions can be diff --git a/lib/state_machine/branch.rb b/lib/state_machine/branch.rb index 56c5cafe..2d952acd 100644 --- a/lib/state_machine/branch.rb +++ b/lib/state_machine/branch.rb @@ -29,12 +29,16 @@ class Branch # * +from+ / +except_from+ # * +to+ / +except_to+ attr_reader :known_states - + + # An optional, custom, label to add to the graph when drawing the branch. + attr_reader :graph_label + # Creates a new branch def initialize(options = {}) #:nodoc: # Build conditionals @if_condition = options.delete(:if) @unless_condition = options.delete(:unless) + @graph_label = options.delete(:graph_label) # Build event requirement @event_requirement = build_matcher(options, :on, :except_on) diff --git a/lib/state_machine/event.rb b/lib/state_machine/event.rb index 6ddaa7db..c8efc720 100644 --- a/lib/state_machine/event.rb +++ b/lib/state_machine/event.rb @@ -194,7 +194,7 @@ def reset @branches = [] @known_states = [] end - + # Draws a representation of this event on the given graph. This will # create 1 or more edges on the graph for each branch (i.e. transition) # configured. @@ -205,12 +205,18 @@ def reset def draw(graph, options = {}) valid_states = machine.states.by_priority.map {|state| state.name} branches.each do |branch| - branch.draw(graph, options[:human_name] ? human_name : name, valid_states) + branch.draw(graph, graph_label(branch, options), valid_states) end true end + def graph_label(branch, options = {}) + graph_label_name = (options[:human_name] ? human_name : name).to_s + + branch.graph_label ? branch.graph_label : graph_label_name + end + # Generates a nicely formatted description of this event's contents. # # For example, diff --git a/state_machine.gemspec b/state_machine.gemspec index 1b7614b6..7f0a7cd7 100644 --- a/state_machine.gemspec +++ b/state_machine.gemspec @@ -18,5 +18,6 @@ Gem::Specification.new do |s| s.add_development_dependency("rake") s.add_development_dependency("simplecov") + s.add_development_dependency("ruby-graphviz") s.add_development_dependency("appraisal", "~> 0.5.0") end diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb index 1bf92cc4..7fe8306f 100644 --- a/test/unit/event_test.rb +++ b/test/unit/event_test.rb @@ -1170,6 +1170,28 @@ def test_should_use_event_name_for_edge_label end end + class EventDrawingWithCustomBranchLabelTest < Test::Unit::TestCase + def setup + states = [:parked, :idling] + + @machine = StateMachine::Machine.new(Class.new, :initial => :parked) + @machine.other_states(*states) + + graph = StateMachine::Graph.new('test') + states.each {|state| graph.add_nodes(state.to_s)} + + @machine.events << @event = StateMachine::Event.new(@machine , :park, :human_name => 'Park') + @event.transition :parked => :idling, :graph_label => "extra graph label" + + @event.draw(graph, :human_name => true) + @edge = graph.get_edge_at_index(0) + end + + def test_should_use_event_human_name_for_edge_label + assert_equal 'extra graph label', @edge['label'].to_s.gsub('"', '') + end + end + class EventDrawingWithHumanNameTest < Test::Unit::TestCase def setup states = [:parked, :idling] From d58289cef9013ac292fe889ed409032e9b08133a Mon Sep 17 00:00:00 2001 From: Gavin Stark Date: Tue, 21 Jul 2015 10:19:54 -0400 Subject: [PATCH 2/3] Fixes graphviz constant scope --- lib/state_machine/graph.rb | 2 +- test/unit/machine_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/state_machine/graph.rb b/lib/state_machine/graph.rb index c73a56ce..ef9497c0 100644 --- a/lib/state_machine/graph.rb +++ b/lib/state_machine/graph.rb @@ -86,7 +86,7 @@ def v0_api? # The ruby-graphviz version data def version - Constants::RGV_VERSION.split('.') + GraphViz::Constants::RGV_VERSION.split('.') end end end diff --git a/test/unit/machine_test.rb b/test/unit/machine_test.rb index 066fc1d5..8463f084 100644 --- a/test/unit/machine_test.rb +++ b/test/unit/machine_test.rb @@ -3261,7 +3261,7 @@ def test_should_allow_orientation_to_be_portrait assert_equal 'TB', graph['rankdir'].to_s.gsub('"', '') end - if Constants::RGV_VERSION != '0.9.0' + if GraphViz::Constants::RGV_VERSION != '0.9.0' def test_should_allow_human_names_to_be_displayed @machine.event :ignite, :human_name => 'Ignite' @machine.state :parked, :human_name => 'Parked' From 9c0417fed59cac5bc953ac62b081144b8de02640 Mon Sep 17 00:00:00 2001 From: Gavin Stark Date: Tue, 21 Jul 2015 10:20:27 -0400 Subject: [PATCH 3/3] Adds test-unit dependency so Test::Unit is present This was failing on my Ruby 2.2 installation --- state_machine.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/state_machine.gemspec b/state_machine.gemspec index 7f0a7cd7..164f4143 100644 --- a/state_machine.gemspec +++ b/state_machine.gemspec @@ -17,6 +17,7 @@ Gem::Specification.new do |s| s.extra_rdoc_files = %w(README.md CHANGELOG.md LICENSE) s.add_development_dependency("rake") + s.add_development_dependency("test-unit") s.add_development_dependency("simplecov") s.add_development_dependency("ruby-graphviz") s.add_development_dependency("appraisal", "~> 0.5.0")