branston 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/lib/branston/Gemfile +25 -0
- data/lib/branston/Gemfile.lock +76 -0
- data/lib/branston/app/controllers/application_controller.rb +1 -1
- data/lib/branston/app/controllers/outcomes_controller.rb +2 -0
- data/lib/branston/app/controllers/stories_controller.rb +82 -86
- data/lib/branston/app/controllers/users_controller.rb +69 -11
- data/lib/branston/app/helpers/iterations_helper.rb +13 -13
- data/lib/branston/app/models/iteration.rb +3 -1
- data/lib/branston/app/models/release.rb +0 -1
- data/lib/branston/app/models/story.rb +30 -28
- data/lib/branston/app/models/user.rb +46 -1
- data/lib/branston/app/views/layouts/_header.html.erb +8 -3
- data/lib/branston/app/views/layouts/user_roles.html.erb +5 -5
- data/lib/branston/app/views/sessions/new.html.erb +8 -14
- data/lib/branston/app/views/users/_admin_controls.html.erb +14 -0
- data/lib/branston/app/views/users/_form.html.erb +27 -0
- data/lib/branston/app/views/users/edit.html.erb +9 -0
- data/lib/branston/app/views/users/index.html.erb +14 -0
- data/lib/branston/app/views/users/new.html.erb +3 -22
- data/lib/branston/config/boot.rb +20 -0
- data/lib/branston/config/environment.rb +2 -7
- data/lib/branston/config/environments/test.rb +0 -8
- data/lib/branston/config/preinitializer.rb +21 -0
- data/lib/branston/config/routes.rb +15 -10
- data/lib/branston/db/development.sqlite3 +0 -0
- data/lib/branston/db/development_structure.sql +21 -8
- data/lib/branston/db/migrate/20100723161424_add_state_to_user.rb +12 -0
- data/lib/branston/db/migrate/20100726150322_add_activation_fields_to_user.rb +12 -0
- data/lib/branston/db/migrate/20100729125551_set_default_user_state_to_pending.rb +10 -0
- data/lib/branston/db/migrate/20100812133837_add_is_admin_property_to_user.rb +10 -0
- data/lib/branston/db/migrate/20100812140532_set_default_user_state_to_active.rb +10 -0
- data/lib/branston/db/migrate/20100812143455_add_default_admin_user.rb +17 -0
- data/lib/branston/db/migrate/20110408162438_remove_is_admin_property_and_add_role_instead.rb +12 -0
- data/lib/branston/db/pristine.sqlite3 +0 -0
- data/lib/branston/db/schema.rb +6 -8
- data/lib/branston/db/test.sqlite3 +0 -0
- data/lib/branston/log/development.log +1181 -433
- data/lib/branston/log/test.log +145306 -52026
- data/lib/branston/test/blueprints.rb +22 -28
- data/lib/branston/test/functional/iterations_controller_test.rb +149 -113
- data/lib/branston/test/functional/outcomes_controller_test.rb +94 -60
- data/lib/branston/test/functional/preconditions_controller_test.rb +101 -67
- data/lib/branston/test/functional/releases_controller_test.rb +85 -49
- data/lib/branston/test/functional/scenarios_controller_test.rb +104 -70
- data/lib/branston/test/functional/stories_controller_test.rb +41 -12
- data/lib/branston/test/functional/users_controller_test.rb +364 -43
- data/lib/branston/test/unit/iteration_test.rb +37 -6
- data/lib/branston/test/unit/outcome_test.rb +2 -2
- data/lib/branston/test/unit/participation_test.rb +2 -2
- data/lib/branston/test/unit/precondition_test.rb +3 -3
- data/lib/branston/test/unit/release_test.rb +4 -0
- data/lib/branston/test/unit/scenario_test.rb +4 -4
- data/lib/branston/test/unit/story_test.rb +62 -40
- data/lib/branston/test/unit/user_test.rb +195 -5
- metadata +136 -156
- data/lib/branston/app/controllers/user_roles_controller.rb +0 -105
- data/lib/branston/app/helpers/user_roles_helper.rb +0 -2
- data/lib/branston/app/models/user_role.rb +0 -21
- data/lib/branston/app/views/layouts/outcomes.html.erb +0 -17
- data/lib/branston/app/views/layouts/preconditions.html.erb +0 -17
- data/lib/branston/app/views/layouts/releases.html.erb +0 -17
- data/lib/branston/app/views/user_roles/edit.html.erb +0 -16
- data/lib/branston/app/views/user_roles/index.html.erb +0 -20
- data/lib/branston/app/views/user_roles/new.html.erb +0 -15
- data/lib/branston/app/views/user_roles/show.html.erb +0 -8
- data/lib/branston/coverage/app-controllers-application_controller_rb.html +0 -231
- data/lib/branston/coverage/app-controllers-iterations_controller_rb.html +0 -801
- data/lib/branston/coverage/app-controllers-outcomes_controller_rb.html +0 -759
- data/lib/branston/coverage/app-controllers-preconditions_controller_rb.html +0 -783
- data/lib/branston/coverage/app-controllers-releases_controller_rb.html +0 -705
- data/lib/branston/coverage/app-controllers-scenarios_controller_rb.html +0 -777
- data/lib/branston/coverage/app-controllers-sessions_controller_rb.html +0 -411
- data/lib/branston/coverage/app-controllers-stories_controller_rb.html +0 -1071
- data/lib/branston/coverage/app-controllers-user_roles_controller_rb.html +0 -693
- data/lib/branston/coverage/app-controllers-users_controller_rb.html +0 -315
- data/lib/branston/coverage/app-helpers-application_helper_rb.html +0 -327
- data/lib/branston/coverage/app-helpers-iterations_helper_rb.html +0 -363
- data/lib/branston/coverage/app-helpers-outcomes_helper_rb.html +0 -75
- data/lib/branston/coverage/app-helpers-preconditions_helper_rb.html +0 -75
- data/lib/branston/coverage/app-helpers-releases_helper_rb.html +0 -75
- data/lib/branston/coverage/app-helpers-sessions_helper_rb.html +0 -75
- data/lib/branston/coverage/app-helpers-stories_helper_rb.html +0 -75
- data/lib/branston/coverage/app-helpers-user_roles_helper_rb.html +0 -75
- data/lib/branston/coverage/app-models-iteration_rb.html +0 -321
- data/lib/branston/coverage/app-models-outcome_rb.html +0 -243
- data/lib/branston/coverage/app-models-participation_rb.html +0 -189
- data/lib/branston/coverage/app-models-precondition_rb.html +0 -243
- data/lib/branston/coverage/app-models-release_rb.html +0 -195
- data/lib/branston/coverage/app-models-scenario_rb.html +0 -231
- data/lib/branston/coverage/app-models-story_rb.html +0 -621
- data/lib/branston/coverage/app-models-user_rb.html +0 -513
- data/lib/branston/coverage/app-models-user_role_rb.html +0 -189
- data/lib/branston/coverage/index.html +0 -570
- data/lib/branston/coverage/jquery-1.3.2.min.js +0 -19
- data/lib/branston/coverage/jquery.tablesorter.min.js +0 -15
- data/lib/branston/coverage/lib-client_rb.html +0 -537
- data/lib/branston/coverage/lib-faker_extras_rb.html +0 -207
- data/lib/branston/coverage/lib-story_generator_rb.html +0 -873
- data/lib/branston/coverage/print.css +0 -12
- data/lib/branston/coverage/rcov.js +0 -42
- data/lib/branston/coverage/screen.css +0 -270
- data/lib/branston/db/migrate/20091127131037_create_user_roles.rb +0 -13
- data/lib/branston/db/migrate/20091127172950_add_story_id_to_user_role.rb +0 -10
- data/lib/branston/test/functional/user_roles_controller_test.rb +0 -71
- data/lib/branston/test/unit/helpers/user_roles_helper_test.rb +0 -4
- data/lib/branston/test/unit/user_role_test.rb +0 -9
- data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_flat.txt +0 -8
- data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_graph.html +0 -6718
- data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_tree.txt +0 -9942
- data/lib/branston/vendor/plugins/state_machine/CHANGELOG.rdoc +0 -298
- data/lib/branston/vendor/plugins/state_machine/LICENSE +0 -20
- data/lib/branston/vendor/plugins/state_machine/README.rdoc +0 -466
- data/lib/branston/vendor/plugins/state_machine/Rakefile +0 -98
- data/lib/branston/vendor/plugins/state_machine/examples/AutoShop_state.png +0 -0
- data/lib/branston/vendor/plugins/state_machine/examples/Car_state.png +0 -0
- data/lib/branston/vendor/plugins/state_machine/examples/TrafficLight_state.png +0 -0
- data/lib/branston/vendor/plugins/state_machine/examples/Vehicle_state.png +0 -0
- data/lib/branston/vendor/plugins/state_machine/examples/auto_shop.rb +0 -11
- data/lib/branston/vendor/plugins/state_machine/examples/car.rb +0 -19
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/controller.rb +0 -51
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/model.rb +0 -28
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_edit.html.erb +0 -24
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_index.html.erb +0 -23
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_new.html.erb +0 -13
- data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_show.html.erb +0 -17
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/controller.rb +0 -43
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/migration.rb +0 -11
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/model.rb +0 -23
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_edit.html.erb +0 -25
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_index.html.erb +0 -23
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_new.html.erb +0 -14
- data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_show.html.erb +0 -17
- data/lib/branston/vendor/plugins/state_machine/examples/traffic_light.rb +0 -7
- data/lib/branston/vendor/plugins/state_machine/examples/vehicle.rb +0 -31
- data/lib/branston/vendor/plugins/state_machine/init.rb +0 -1
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine.rb +0 -388
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/assertions.rb +0 -36
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/callback.rb +0 -189
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/condition_proxy.rb +0 -94
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/eval_helpers.rb +0 -67
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event.rb +0 -252
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event_collection.rb +0 -122
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/extensions.rb +0 -149
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/guard.rb +0 -230
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations.rb +0 -68
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record.rb +0 -492
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/locale.rb +0 -11
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/observer.rb +0 -41
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper.rb +0 -351
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper/observer.rb +0 -139
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/sequel.rb +0 -322
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine.rb +0 -1467
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine_collection.rb +0 -155
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher.rb +0 -123
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher_helpers.rb +0 -54
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/node_collection.rb +0 -152
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state.rb +0 -249
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state_collection.rb +0 -112
- data/lib/branston/vendor/plugins/state_machine/lib/state_machine/transition.rb +0 -394
- data/lib/branston/vendor/plugins/state_machine/state_machine.gemspec +0 -30
- data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rake +0 -1
- data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rb +0 -30
- data/lib/branston/vendor/plugins/state_machine/test/classes/switch.rb +0 -11
- data/lib/branston/vendor/plugins/state_machine/test/functional/state_machine_test.rb +0 -941
- data/lib/branston/vendor/plugins/state_machine/test/test_helper.rb +0 -4
- data/lib/branston/vendor/plugins/state_machine/test/unit/assertions_test.rb +0 -40
- data/lib/branston/vendor/plugins/state_machine/test/unit/callback_test.rb +0 -455
- data/lib/branston/vendor/plugins/state_machine/test/unit/condition_proxy_test.rb +0 -328
- data/lib/branston/vendor/plugins/state_machine/test/unit/eval_helpers_test.rb +0 -120
- data/lib/branston/vendor/plugins/state_machine/test/unit/event_collection_test.rb +0 -326
- data/lib/branston/vendor/plugins/state_machine/test/unit/event_test.rb +0 -743
- data/lib/branston/vendor/plugins/state_machine/test/unit/guard_test.rb +0 -908
- data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/active_record_test.rb +0 -1367
- data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/data_mapper_test.rb +0 -962
- data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/sequel_test.rb +0 -859
- data/lib/branston/vendor/plugins/state_machine/test/unit/integrations_test.rb +0 -42
- data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_event_test.rb +0 -7
- data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_transition_test.rb +0 -7
- data/lib/branston/vendor/plugins/state_machine/test/unit/machine_collection_test.rb +0 -938
- data/lib/branston/vendor/plugins/state_machine/test/unit/machine_test.rb +0 -2004
- data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_helpers_test.rb +0 -37
- data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_test.rb +0 -155
- data/lib/branston/vendor/plugins/state_machine/test/unit/node_collection_test.rb +0 -207
- data/lib/branston/vendor/plugins/state_machine/test/unit/state_collection_test.rb +0 -280
- data/lib/branston/vendor/plugins/state_machine/test/unit/state_machine_test.rb +0 -31
- data/lib/branston/vendor/plugins/state_machine/test/unit/state_test.rb +0 -795
- data/lib/branston/vendor/plugins/state_machine/test/unit/transition_test.rb +0 -1212
@@ -1,155 +0,0 @@
|
|
1
|
-
module StateMachine
|
2
|
-
# Represents a collection of state machines for a class
|
3
|
-
class MachineCollection < Hash
|
4
|
-
# Initializes the state of each machine in the given object. Initial
|
5
|
-
# values are only set if the machine's attribute doesn't already exist
|
6
|
-
# (which must mean the defaults are being skipped)
|
7
|
-
def initialize_states(object, options = {})
|
8
|
-
if ignore = options[:ignore]
|
9
|
-
ignore.map! {|attribute| attribute.to_sym}
|
10
|
-
end
|
11
|
-
|
12
|
-
each_value do |machine|
|
13
|
-
if (!ignore || !ignore.include?(machine.attribute)) && (!options.include?(:dynamic) || machine.dynamic_initial_state? == options[:dynamic])
|
14
|
-
value = machine.read(object, :state)
|
15
|
-
machine.write(object, :state, machine.initial_state(object).value) if ignore || value.nil? || value.respond_to?(:empty?) && value.empty?
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Runs one or more events in parallel on the given object. See
|
21
|
-
# StateMachine::InstanceMethods#fire_events for more information.
|
22
|
-
def fire_events(object, *events)
|
23
|
-
run_action = [true, false].include?(events.last) ? events.pop : true
|
24
|
-
|
25
|
-
# Generate the transitions to run for each event
|
26
|
-
transitions = events.collect do |event_name|
|
27
|
-
# Find the actual event being run
|
28
|
-
event = nil
|
29
|
-
detect do |name, machine|
|
30
|
-
event = machine.events[event_name, :qualified_name]
|
31
|
-
end
|
32
|
-
|
33
|
-
raise InvalidEvent, "#{event_name.inspect} is an unknown state machine event" unless event
|
34
|
-
|
35
|
-
# Get the transition that will be performed for the event
|
36
|
-
unless transition = event.transition_for(object)
|
37
|
-
machine = event.machine
|
38
|
-
machine.invalidate(object, :state, :invalid_transition, [[:event, event_name]])
|
39
|
-
end
|
40
|
-
|
41
|
-
transition
|
42
|
-
end.compact
|
43
|
-
|
44
|
-
# Run the events in parallel only if valid transitions were found for
|
45
|
-
# all of them
|
46
|
-
if events.length == transitions.length
|
47
|
-
Transition.perform_within_transaction(transitions, :action => run_action)
|
48
|
-
else
|
49
|
-
false
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Runs one or more event attributes in parallel during the invocation of
|
54
|
-
# an action on the given object. after_transition callbacks can be
|
55
|
-
# optionally disabled if the events are being only partially fired (for
|
56
|
-
# example, when validating records in ORM integrations).
|
57
|
-
#
|
58
|
-
# The event attributes that will be fired are based on which machines
|
59
|
-
# match the action that is being invoked.
|
60
|
-
#
|
61
|
-
# == Examples
|
62
|
-
#
|
63
|
-
# class Vehicle
|
64
|
-
# include DataMapper::Resource
|
65
|
-
# property :id, Serial
|
66
|
-
#
|
67
|
-
# state_machine :initial => :parked do
|
68
|
-
# event :ignite do
|
69
|
-
# transition :parked => :idling
|
70
|
-
# end
|
71
|
-
# end
|
72
|
-
#
|
73
|
-
# state_machine :alarm_state, :namespace => 'alarm', :initial => :active do
|
74
|
-
# event :disable do
|
75
|
-
# transition all => :off
|
76
|
-
# end
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
#
|
80
|
-
# With valid events:
|
81
|
-
#
|
82
|
-
# vehicle = Vehicle.create # => #<Vehicle id=1 state="parked" alarm_state="active">
|
83
|
-
# vehicle.state_event = 'ignite'
|
84
|
-
# vehicle.alarm_state_event = 'disable'
|
85
|
-
#
|
86
|
-
# Vehicle.state_machines.fire_event_attributes(vehicle, :save) { true }
|
87
|
-
# vehicle.state # => "idling"
|
88
|
-
# vehicle.state_event # => nil
|
89
|
-
# vehicle.alarm_state # => "off"
|
90
|
-
# vehicle.alarm_state_event # => nil
|
91
|
-
#
|
92
|
-
# With invalid events:
|
93
|
-
#
|
94
|
-
# vehicle = Vehicle.create # => #<Vehicle id=1 state="parked" alarm_state="active">
|
95
|
-
# vehicle.state_event = 'park'
|
96
|
-
# vehicle.alarm_state_event = 'disable'
|
97
|
-
#
|
98
|
-
# Vehicle.state_machines.fire_event_attributes(vehicle, :save) { true }
|
99
|
-
# vehicle.state # => "parked"
|
100
|
-
# vehicle.state_event # => nil
|
101
|
-
# vehicle.alarm_state # => "active"
|
102
|
-
# vehicle.alarm_state_event # => nil
|
103
|
-
# vehicle.errors # => #<DataMapper::Validate::ValidationErrors:0xb7af9abc @errors={"state_event"=>["is invalid"]}>
|
104
|
-
#
|
105
|
-
# With partial firing:
|
106
|
-
#
|
107
|
-
# vehicle = Vehicle.create # => #<Vehicle id=1 state="parked" alarm_state="active">
|
108
|
-
# vehicle.state_event = 'ignite'
|
109
|
-
#
|
110
|
-
# Vehicle.state_machines.fire_event_attributes(vehicle, :save, false) { true }
|
111
|
-
# vehicle.state # => "idling"
|
112
|
-
# vehicle.state_event # => "ignite"
|
113
|
-
# vehicle.state_event_transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
|
114
|
-
def fire_event_attributes(object, action, complete = true)
|
115
|
-
# Get the transitions to fire for each applicable machine
|
116
|
-
transitions = map {|name, machine| machine.action == action ? machine.events.attribute_transition_for(object, true) : nil}.compact
|
117
|
-
return yield if transitions.empty?
|
118
|
-
|
119
|
-
# The value generated by the yielded block (the actual action)
|
120
|
-
action_value = nil
|
121
|
-
|
122
|
-
# Make sure all events were valid
|
123
|
-
if result = transitions.all? {|transition| transition != false}
|
124
|
-
# Clear any traces of the event since transitions are available and to
|
125
|
-
# prevent from being evaluated multiple times if actions are nested
|
126
|
-
transitions.each do |transition|
|
127
|
-
transition.machine.write(object, :event, nil)
|
128
|
-
transition.machine.write(object, :event_transition, nil)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Perform the transitions
|
132
|
-
begin
|
133
|
-
result = Transition.perform(transitions, :after => complete) { action_value = yield }
|
134
|
-
rescue Exception
|
135
|
-
# Reset the event attribute so it can be re-evaluated if attempted again
|
136
|
-
transitions.each do |transition|
|
137
|
-
transition.machine.write(object, :event, transition.event)
|
138
|
-
end
|
139
|
-
|
140
|
-
raise
|
141
|
-
end
|
142
|
-
|
143
|
-
transitions.each do |transition|
|
144
|
-
# Revert event if failed (to allow for more attempts)
|
145
|
-
transition.machine.write(object, :event, transition.event) unless result
|
146
|
-
|
147
|
-
# Track transition if partial transition was successful
|
148
|
-
transition.machine.write(object, :event_transition, transition) if !complete && result
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
action_value.nil? ? result : action_value
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
|
3
|
-
module StateMachine
|
4
|
-
# Provides a general strategy pattern for determining whether a match is found
|
5
|
-
# for a value. The algorithm that actually determines the match depends on
|
6
|
-
# the matcher in use.
|
7
|
-
class Matcher
|
8
|
-
# The list of values against which queries are matched
|
9
|
-
attr_reader :values
|
10
|
-
|
11
|
-
# Creates a new matcher for querying against the given set of values
|
12
|
-
def initialize(values = [])
|
13
|
-
@values = values.is_a?(Array) ? values : [values]
|
14
|
-
end
|
15
|
-
|
16
|
-
# Generates a subset of values that exists in both the set of values being
|
17
|
-
# filtered and the values configured for the matcher
|
18
|
-
def filter(values)
|
19
|
-
self.values & values
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# Matches any given value. Since there is no configuration for this type of
|
24
|
-
# matcher, it must be used as a singleton.
|
25
|
-
class AllMatcher < Matcher
|
26
|
-
include Singleton
|
27
|
-
|
28
|
-
# Generates a blacklist matcher based on the given set of values
|
29
|
-
#
|
30
|
-
# == Examples
|
31
|
-
#
|
32
|
-
# matcher = StateMachine::AllMatcher.instance - [:parked, :idling]
|
33
|
-
# matcher.matches?(:parked) # => false
|
34
|
-
# matcher.matches?(:first_gear) # => true
|
35
|
-
def -(blacklist)
|
36
|
-
BlacklistMatcher.new(blacklist)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Always returns true
|
40
|
-
def matches?(value, context = {})
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
# Always returns the given set of values
|
45
|
-
def filter(values)
|
46
|
-
values
|
47
|
-
end
|
48
|
-
|
49
|
-
# A human-readable description of this matcher. Always "all".
|
50
|
-
def description
|
51
|
-
'all'
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Matches a specific set of values
|
56
|
-
class WhitelistMatcher < Matcher
|
57
|
-
# Checks whether the given value exists within the whitelist configured
|
58
|
-
# for this matcher.
|
59
|
-
#
|
60
|
-
# == Examples
|
61
|
-
#
|
62
|
-
# matcher = StateMachine::WhitelistMatcher.new([:parked, :idling])
|
63
|
-
# matcher.matches?(:parked) # => true
|
64
|
-
# matcher.matches?(:first_gear) # => false
|
65
|
-
def matches?(value, context = {})
|
66
|
-
values.include?(value)
|
67
|
-
end
|
68
|
-
|
69
|
-
# A human-readable description of this matcher
|
70
|
-
def description
|
71
|
-
values.length == 1 ? values.first.inspect : values.inspect
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Matches everything but a specific set of values
|
76
|
-
class BlacklistMatcher < Matcher
|
77
|
-
# Checks whether the given value exists outside the blacklist configured
|
78
|
-
# for this matcher.
|
79
|
-
#
|
80
|
-
# == Examples
|
81
|
-
#
|
82
|
-
# matcher = StateMachine::BlacklistMatcher.new([:parked, :idling])
|
83
|
-
# matcher.matches?(:parked) # => false
|
84
|
-
# matcher.matches?(:first_gear) # => true
|
85
|
-
def matches?(value, context = {})
|
86
|
-
!values.include?(value)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Finds all values that are *not* within the blacklist configured for this
|
90
|
-
# matcher
|
91
|
-
def filter(values)
|
92
|
-
values - self.values
|
93
|
-
end
|
94
|
-
|
95
|
-
# A human-readable description of this matcher
|
96
|
-
def description
|
97
|
-
"all - #{values.length == 1 ? values.first.inspect : values.inspect}"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Matches a loopback of two values within a context. Since there is no
|
102
|
-
# configuration for this type of matcher, it must be used as a singleton.
|
103
|
-
class LoopbackMatcher < Matcher
|
104
|
-
include Singleton
|
105
|
-
|
106
|
-
# Checks whether the given value matches what the value originally was.
|
107
|
-
# This value should be defined in the context.
|
108
|
-
#
|
109
|
-
# == Examples
|
110
|
-
#
|
111
|
-
# matcher = StateMachine::LoopbackMatcher.instance
|
112
|
-
# matcher.matches?(:parked, :from => :parked) # => true
|
113
|
-
# matcher.matches?(:parked, :from => :idling) # => false
|
114
|
-
def matches?(value, context)
|
115
|
-
context[:from] == value
|
116
|
-
end
|
117
|
-
|
118
|
-
# A human-readable description of this matcher. Always "same".
|
119
|
-
def description
|
120
|
-
'same'
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module StateMachine
|
2
|
-
# Provides a set of helper methods for generating matchers
|
3
|
-
module MatcherHelpers
|
4
|
-
# Represents a state that matches all known states in a machine.
|
5
|
-
#
|
6
|
-
# == Examples
|
7
|
-
#
|
8
|
-
# class Vehicle
|
9
|
-
# state_machine do
|
10
|
-
# before_transition any => :parked, :do => lambda {...}
|
11
|
-
# before_transition all - :parked => all - :idling, :do => lambda {}
|
12
|
-
#
|
13
|
-
# event :park
|
14
|
-
# transition all => :parked
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# event :crash
|
18
|
-
# transition all - :parked => :stalled
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# In the above example, +all+ will match the following states since they
|
24
|
-
# are known:
|
25
|
-
# * +parked+
|
26
|
-
# * +stalled+
|
27
|
-
# * +idling+
|
28
|
-
def all
|
29
|
-
AllMatcher.instance
|
30
|
-
end
|
31
|
-
alias_method :any, :all
|
32
|
-
|
33
|
-
# Represents a state that matches the original +from+ state. This is useful
|
34
|
-
# for defining transitions which are loopbacks.
|
35
|
-
#
|
36
|
-
# == Examples
|
37
|
-
#
|
38
|
-
# class Vehicle
|
39
|
-
# state_machine do
|
40
|
-
# event :ignite
|
41
|
-
# transition [:idling, :first_gear] => same
|
42
|
-
# end
|
43
|
-
# end
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# In the above example, +same+ will match whichever the from state is. In
|
47
|
-
# the case of the +ignite+ event, it is essential the same as the following:
|
48
|
-
#
|
49
|
-
# transition :parked => :parked, :first_gear => :first_gear
|
50
|
-
def same
|
51
|
-
LoopbackMatcher.instance
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'state_machine/assertions'
|
2
|
-
|
3
|
-
module StateMachine
|
4
|
-
# Represents a collection of nodes in a state machine, be it events or states.
|
5
|
-
class NodeCollection
|
6
|
-
include Enumerable
|
7
|
-
include Assertions
|
8
|
-
|
9
|
-
# The machine associated with the nodes
|
10
|
-
attr_reader :machine
|
11
|
-
|
12
|
-
# Creates a new collection of nodes for the given state machine. By default,
|
13
|
-
# the collection is empty.
|
14
|
-
#
|
15
|
-
# Configuration options:
|
16
|
-
# * <tt>:index</tt> - One or more attributes to automatically generate
|
17
|
-
# hashed indices for in order to perform quick lookups. Default is to
|
18
|
-
# index by the :name attribute
|
19
|
-
def initialize(machine, options = {})
|
20
|
-
assert_valid_keys(options, :index)
|
21
|
-
options = {:index => :name}.merge(options)
|
22
|
-
|
23
|
-
@machine = machine
|
24
|
-
@nodes = []
|
25
|
-
@indices = Array(options[:index]).inject({}) {|indices, attribute| indices[attribute] = {}; indices}
|
26
|
-
@default_index = Array(options[:index]).first
|
27
|
-
end
|
28
|
-
|
29
|
-
# Creates a copy of this collection such that modifications don't affect
|
30
|
-
# the original collection
|
31
|
-
def initialize_copy(orig) #:nodoc:
|
32
|
-
super
|
33
|
-
|
34
|
-
nodes = @nodes
|
35
|
-
@nodes = []
|
36
|
-
@indices = @indices.inject({}) {|indices, (name, index)| indices[name] = {}; indices}
|
37
|
-
nodes.each {|node| self << node.dup}
|
38
|
-
end
|
39
|
-
|
40
|
-
# Changes the current machine associated with the collection. In turn, this
|
41
|
-
# will change the state machine associated with each node in the collection.
|
42
|
-
def machine=(new_machine)
|
43
|
-
@machine = new_machine
|
44
|
-
each {|node| node.machine = new_machine}
|
45
|
-
end
|
46
|
-
|
47
|
-
# Gets the number of nodes in this collection
|
48
|
-
def length
|
49
|
-
@nodes.length
|
50
|
-
end
|
51
|
-
|
52
|
-
# Gets the set of unique keys for the given index
|
53
|
-
def keys(index_name = @default_index)
|
54
|
-
index(index_name).keys
|
55
|
-
end
|
56
|
-
|
57
|
-
# Adds a new node to the collection. By doing so, this will also add it to
|
58
|
-
# the configured indices.
|
59
|
-
def <<(node)
|
60
|
-
@nodes << node
|
61
|
-
@indices.each {|attribute, index| index[value(node, attribute)] = node}
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
# Updates the indexed keys for the given node. If the node's attribute
|
66
|
-
# has changed since it was added to the collection, the old indexed keys
|
67
|
-
# will be replaced with the updated ones.
|
68
|
-
def update(node)
|
69
|
-
@indices.each do |attribute, index|
|
70
|
-
old_key = RUBY_VERSION < '1.9' ? index.index(node) : index.key(node)
|
71
|
-
new_key = value(node, attribute)
|
72
|
-
|
73
|
-
# Only replace the key if it's changed
|
74
|
-
if old_key != new_key
|
75
|
-
index.delete(old_key)
|
76
|
-
index[new_key] = node
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Calls the block once for each element in self, passing that element as a
|
82
|
-
# parameter.
|
83
|
-
#
|
84
|
-
# states = StateMachine::NodeCollection.new
|
85
|
-
# states << StateMachine::State.new(machine, :parked)
|
86
|
-
# states << StateMachine::State.new(machine, :idling)
|
87
|
-
# states.each {|state| puts state.name, ' -- '}
|
88
|
-
#
|
89
|
-
# ...produces:
|
90
|
-
#
|
91
|
-
# parked -- idling --
|
92
|
-
def each
|
93
|
-
@nodes.each {|node| yield node}
|
94
|
-
self
|
95
|
-
end
|
96
|
-
|
97
|
-
# Gets the node at the given index.
|
98
|
-
#
|
99
|
-
# states = StateMachine::NodeCollection.new
|
100
|
-
# states << StateMachine::State.new(machine, :parked)
|
101
|
-
# states << StateMachine::State.new(machine, :idling)
|
102
|
-
#
|
103
|
-
# states.at(0).name # => :parked
|
104
|
-
# states.at(1).name # => :idling
|
105
|
-
def at(index)
|
106
|
-
@nodes[index]
|
107
|
-
end
|
108
|
-
|
109
|
-
# Gets the node indexed by the given key. By default, this will look up the
|
110
|
-
# key in the first index configured for the collection. A custom index can
|
111
|
-
# be specified like so:
|
112
|
-
#
|
113
|
-
# collection['parked', :value]
|
114
|
-
#
|
115
|
-
# The above will look up the "parked" key in a hash indexed by each node's
|
116
|
-
# +value+ attribute.
|
117
|
-
#
|
118
|
-
# If the key cannot be found, then nil will be returned.
|
119
|
-
def [](key, index_name = @default_index)
|
120
|
-
index(index_name)[key]
|
121
|
-
end
|
122
|
-
|
123
|
-
# Gets the node indexed by the given key. By default, this will look up the
|
124
|
-
# key in the first index configured for the collection. A custom index can
|
125
|
-
# be specified like so:
|
126
|
-
#
|
127
|
-
# collection['parked', :value]
|
128
|
-
#
|
129
|
-
# The above will look up the "parked" key in a hash indexed by each node's
|
130
|
-
# +value+ attribute.
|
131
|
-
#
|
132
|
-
# If the key cannot be found, then an IndexError exception will be raised:
|
133
|
-
#
|
134
|
-
# collection['invalid', :value] # => IndexError: "invalid" is an invalid value
|
135
|
-
def fetch(key, index_name = @default_index)
|
136
|
-
self[key, index_name] || raise(IndexError, "#{key.inspect} is an invalid #{index_name}")
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
# Gets the given index. If the index does not exist, then an ArgumentError
|
141
|
-
# is raised.
|
142
|
-
def index(name)
|
143
|
-
raise ArgumentError, 'No indices configured' unless @indices.any?
|
144
|
-
@indices[name] || raise(ArgumentError, "Invalid index: #{name.inspect}")
|
145
|
-
end
|
146
|
-
|
147
|
-
# Gets the value for the given attribute on the node
|
148
|
-
def value(node, attribute)
|
149
|
-
node.send(attribute)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|