Skip to content

Commit

Permalink
Allow access to human state / event names in transitions and for the …
Browse files Browse the repository at this point in the history
…current state
  • Loading branch information
obrie committed Jun 26, 2010
1 parent d4ae362 commit baba531
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
== master

* Allow access to human state / event names in transitions and for the current state
* Use human state / event names in error messages
* Fix event names being used inconsistently in error messages
* Allow access to the humanized version of state / event names via human_state_name / human_state_event_name
Expand Down
1 change: 1 addition & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ like so:
vehicle = Vehicle.new # => #<Vehicle:0xb7cf4eac @state="parked", @seatbelt_on=false>
vehicle.state # => "parked"
vehicle.state_name # => :parked
vehicle.human_state_name # => "parked"
vehicle.parked? # => true
vehicle.can_ignite? # => true
vehicle.ignite_transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
Expand Down
4 changes: 2 additions & 2 deletions examples/merb-rest/view_edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@

<p>
<%= label :state %><br />
<%= select :state_event, :selected => @user.state_event.to_s, :collection => @user.state_transitions, :value_method => :event, :text_method => :to_name, :prompt => @user.state_name.to_s %>
<%= select :state_event, :selected => @user.state_event.to_s, :collection => @user.state_transitions, :value_method => :event, :text_method => :human_to_name, :prompt => @user.human_state_name %>
</p>

<p>
<%= label :access_state %><br />
<%= select :access_state_event, :selected => @user.access_state_event.to_s, :collection => @user.access_state_transitions, :value_method => :event, :text_method => :event, :prompt => "don't change" %>
<%= select :access_state_event, :selected => @user.access_state_event.to_s, :collection => @user.access_state_transitions, :value_method => :event, :text_method => :human_event, :prompt => "don't change" %>
</p>

<p><%= submit 'Update' %></p>
Expand Down
4 changes: 2 additions & 2 deletions examples/merb-rest/view_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<% @users.each do |user| %>
<tr>
<td><%=h user.name %></td>
<td><%=h user.state %></td>
<td><%=h user.access_state %></td>
<td><%=h user.human_state_name %></td>
<td><%=h user.human_access_state_name %></td>
<td><%= link_to 'Show', resource(user) %></td>
<td><%= link_to 'Edit', resource(user, :edit) %></td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions examples/merb-rest/view_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<p>
<b>State:</b>
<%=h @user.state %>
<%=h @user.human_state_name %>
</p>

<p>
<b>Access State:</b>
<%=h @user.access_state %>
<%=h @user.human_access_state_name %>
</p>

<%= link_to 'Edit', resource(@user, :edit) %> |
Expand Down
4 changes: 2 additions & 2 deletions examples/rails-rest/view_edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@

<p>
<%= f.label :state %><br />
<%= f.collection_select :state_event, @user.state_transitions, :event, :to_name, :include_blank => @user.state_name.to_s %>
<%= f.collection_select :state_event, @user.state_transitions, :event, :human_to_name, :include_blank => @user.human_state_name %>
</p>

<p>
<%= f.label :access_state %><br />
<%= f.collection_select :access_state_event, @user.access_state_transitions, :event, :event, :include_blank => "don't change" %>
<%= f.collection_select :access_state_event, @user.access_state_transitions, :event, :human_event, :include_blank => "don't change" %>
</p>

<p><%= f.submit 'Update' %></p>
Expand Down
4 changes: 2 additions & 2 deletions examples/rails-rest/view_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<% @users.each do |user| %>
<tr>
<td><%=h user.name %></td>
<td><%=h user.state %></td>
<td><%=h user.access_state %></td>
<td><%=h user.human_state_name %></td>
<td><%=h user.human_access_state_name %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions examples/rails-rest/view_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<p>
<b>State:</b>
<%=h @user.state %>
<%=h @user.human_state_name %>
</p>

<p>
<b>Access State:</b>
<%=h @user.access_state %>
<%=h @user.human_access_state_name %>
</p>

<%= link_to 'Edit', edit_user_path(@user) %> |
Expand Down
3 changes: 3 additions & 0 deletions lib/state_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ module MacroMethods
# * <tt>state?(name)</tt> - Checks the given state name against the current
# state. If the name is not a known state, then an ArgumentError is raised.
# * <tt>state_name</tt> - Gets the name of the state for the current value
# * <tt>human_state_name</tt> - Gets the human-readable name of the state
# for the current value
# * <tt>state_events</tt> - Gets the list of events that can be fired on
# the current object's state (uses the *unqualified* event names)
# * <tt>state_transitions(requirements = {})</tt> - Gets the list of possible
Expand All @@ -156,6 +158,7 @@ module MacroMethods
# vehicle = Vehicle.new
# vehicle.state # => "parked"
# vehicle.state_name # => :parked
# vehicle.human_state_name # => "parked"
# vehicle.state?(:parked) # => true
#
# # Changing state
Expand Down
5 changes: 5 additions & 0 deletions lib/state_machine/machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,11 @@ def define_name_helpers
define_instance_method(attribute(:name)) do |machine, object|
machine.states.match!(object).name
end

# Gets the human state name for the current value
define_instance_method("human_#{attribute(:name)}") do |machine, object|
machine.states.match!(object).human_name(object.class)
end
end

# Defines the with/without scope helpers for this attribute. Both the
Expand Down
84 changes: 50 additions & 34 deletions lib/state_machine/transition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,12 @@ class Transition
# The state machine for which this transition is defined
attr_reader :machine

# The event that triggered the transition
attr_reader :event

# The fully-qualified name of the event that triggered the transition
attr_reader :qualified_event

# The original state value *before* the transition
attr_reader :from

# The original state name *before* the transition
attr_reader :from_name

# The original fully-qualified state name *before* transition
attr_reader :qualified_from_name

# The new state value *after* the transition
attr_reader :to

# The new state name *after* the transition
attr_reader :to_name

# The new fully-qualified state name *after* the transition
attr_reader :qualified_to_name

# The arguments passed in to the event that triggered the transition
# (does not include the +run_action+ boolean argument if specified)
attr_accessor :args
Expand All @@ -59,22 +41,11 @@ def initialize(object, machine, event, from_name, to_name, read_state = true) #:
@args = []
@transient = false

# Event information
event = machine.events.fetch(event)
@event = event.name
@qualified_event = event.qualified_name

# From state information
from_state = machine.states.fetch(from_name)
@from = read_state ? machine.read(object, :state) : from_state.value
@from_name = from_state.name
@qualified_from_name = from_state.qualified_name

# To state information
to_state = machine.states.fetch(to_name)
@to = to_state.value
@to_name = to_state.name
@qualified_to_name = to_state.qualified_name
@event = machine.events.fetch(event)
@from_state = machine.states.fetch(from_name)
@from = read_state ? machine.read(object, :state) : @from_state.value
@to_state = machine.states.fetch(to_name)
@to = @to_state.value

reset
end
Expand All @@ -89,6 +60,51 @@ def action
machine.action
end

# The event that triggered the transition
def event
@event.name
end

# The fully-qualified name of the event that triggered the transition
def qualified_event
@event.qualified_name
end

# The human-readable name of the event that triggered the transition
def human_event
@event.human_name(@object.class)
end

# The state name *before* the transition
def from_name
@from_state.name
end

# The fully-qualified state name *before* the transition
def qualified_from_name
@from_state.qualified_name
end

# The human-readable state name *before* the transition
def human_from_name
@from_state.human_name(@object.class)
end

# The new state name *after* the transition
def to_name
@to_state.name
end

# The new fully-qualified state name *after* the transition
def qualified_to_name
@to_state.qualified_name
end

# The new human-readable state name *after* the transition
def human_to_name
@to_state.human_name(@object.class)
end

# Does this transition represent a loopback (i.e. the from and to state
# are the same)
#
Expand Down
1 change: 1 addition & 0 deletions test/functional/state_machine_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def test_should_be_parked
assert @vehicle.parked?
assert @vehicle.state?(:parked)
assert_equal :parked, @vehicle.state_name
assert_equal 'parked', @vehicle.human_state_name
end

def test_should_not_be_idling
Expand Down
21 changes: 19 additions & 2 deletions test/unit/machine_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,10 @@ def state_name
:parked
end

def human_state_name
'parked'
end

def state_events
[:ignite]
end
Expand Down Expand Up @@ -1125,6 +1129,10 @@ def test_should_not_redefine_attribute_name_reader
assert_equal :parked, @object.state_name
end

def test_should_not_redefine_attribute_human_name_reader
assert_equal 'parked', @object.human_state_name
end

def test_should_not_redefine_attribute_events_reader
assert_equal [:ignite], @object.state_events
end
Expand Down Expand Up @@ -1178,6 +1186,10 @@ def state_name
super == :parked ? 1 : 0
end

def human_state_name
super == 'parked' ? 1 : 0
end

def state_events
super == []
end
Expand All @@ -1199,6 +1211,7 @@ def state_transitions
assert_equal 'idling', @object.status
assert_equal 0, @object.state?(:parked)
assert_equal 0, @object.state_name
assert_equal 0, @object.human_state_name
assert_equal true, @object.state_events
assert_equal true, @object.state_transitions
end
Expand Down Expand Up @@ -1976,6 +1989,10 @@ def test_should_define_a_name_reader_for_the_attribute
assert @object.respond_to?(:state_name)
end

def test_should_define_a_human_name_reader_for_the_attribute
assert @object.respond_to?(:state_name)
end

def test_should_define_an_event_reader_for_the_attribute
assert @object.respond_to?(:state_events)
end
Expand All @@ -1984,11 +2001,11 @@ def test_should_define_a_transition_reader_for_the_attribute
assert @object.respond_to?(:state_transitions)
end

def test_should_define_a_human_attribute_name_reader_for_the_attribute
def test_should_define_a_human_attribute_name_reader
assert @klass.respond_to?(:human_state_name)
end

def test_should_define_a_human_event_name_reader_for_the_attribute
def test_should_define_a_human_event_name_reader
assert @klass.respond_to?(:human_state_event_name)
end

Expand Down
20 changes: 20 additions & 0 deletions test/unit/transition_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def test_should_have_a_qualified_event
assert_equal :ignite, @transition.qualified_event
end

def test_should_have_a_human_event
assert_equal 'ignite', @transition.human_event
end

def test_should_have_a_from_value
assert_equal 'parked', @transition.from
end
Expand All @@ -41,6 +45,10 @@ def test_should_have_a_qualified_from_name
assert_equal :parked, @transition.qualified_from_name
end

def test_should_have_a_human_from_name
assert_equal 'parked', @transition.human_from_name
end

def test_should_have_a_to_value
assert_equal 'idling', @transition.to
end
Expand All @@ -53,6 +61,10 @@ def test_should_have_a_qualified_to_name
assert_equal :idling, @transition.qualified_to_name
end

def test_should_have_a_human_to_name
assert_equal 'idling', @transition.human_to_name
end

def test_should_have_an_attribute
assert_equal :state, @transition.attribute
end
Expand Down Expand Up @@ -192,13 +204,21 @@ def test_should_have_a_qualified_from_name
assert_equal :alarm_off, @transition.qualified_from_name
end

def test_should_have_a_human_from_name
assert_equal 'off', @transition.human_from_name
end

def test_should_have_a_to_name
assert_equal :active, @transition.to_name
end

def test_should_have_a_qualified_to_name
assert_equal :alarm_active, @transition.qualified_to_name
end

def test_should_have_a_human_to_name
assert_equal 'active', @transition.human_to_name
end
end

class TransitionWithCustomMachineAttributeTest < Test::Unit::TestCase
Expand Down

0 comments on commit baba531

Please sign in to comment.