state_machines 0.0.1

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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.idea/.name +1 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/cssxfire.xml +9 -0
  6. data/.idea/encodings.xml +5 -0
  7. data/.idea/misc.xml +5 -0
  8. data/.idea/modules.xml +12 -0
  9. data/.idea/scopes/scope_settings.xml +5 -0
  10. data/.idea/state_machine2.iml +34 -0
  11. data/.idea/vcs.xml +9 -0
  12. data/.idea/workspace.xml +1156 -0
  13. data/.rspec +3 -0
  14. data/.travis.yml +8 -0
  15. data/Gemfile +4 -0
  16. data/LICENSE.txt +23 -0
  17. data/README.md +29 -0
  18. data/Rakefile +1 -0
  19. data/lib/state_machines/assertions.rb +40 -0
  20. data/lib/state_machines/branch.rb +187 -0
  21. data/lib/state_machines/callback.rb +220 -0
  22. data/lib/state_machines/core.rb +25 -0
  23. data/lib/state_machines/core_ext/class/state_machine.rb +5 -0
  24. data/lib/state_machines/core_ext.rb +2 -0
  25. data/lib/state_machines/error.rb +13 -0
  26. data/lib/state_machines/eval_helpers.rb +87 -0
  27. data/lib/state_machines/event.rb +246 -0
  28. data/lib/state_machines/event_collection.rb +141 -0
  29. data/lib/state_machines/extensions.rb +148 -0
  30. data/lib/state_machines/helper_module.rb +17 -0
  31. data/lib/state_machines/integrations/base.rb +100 -0
  32. data/lib/state_machines/integrations.rb +113 -0
  33. data/lib/state_machines/machine.rb +2234 -0
  34. data/lib/state_machines/machine_collection.rb +84 -0
  35. data/lib/state_machines/macro_methods.rb +520 -0
  36. data/lib/state_machines/matcher.rb +123 -0
  37. data/lib/state_machines/matcher_helpers.rb +54 -0
  38. data/lib/state_machines/node_collection.rb +221 -0
  39. data/lib/state_machines/path.rb +120 -0
  40. data/lib/state_machines/path_collection.rb +90 -0
  41. data/lib/state_machines/state.rb +276 -0
  42. data/lib/state_machines/state_collection.rb +112 -0
  43. data/lib/state_machines/state_context.rb +138 -0
  44. data/lib/state_machines/transition.rb +470 -0
  45. data/lib/state_machines/transition_collection.rb +245 -0
  46. data/lib/state_machines/version.rb +3 -0
  47. data/lib/state_machines/yard.rb +8 -0
  48. data/lib/state_machines.rb +3 -0
  49. data/spec/errors/default_spec.rb +14 -0
  50. data/spec/errors/with_message_spec.rb +39 -0
  51. data/spec/helpers/helper_spec.rb +14 -0
  52. data/spec/internal/app/models/auto_shop.rb +31 -0
  53. data/spec/internal/app/models/car.rb +19 -0
  54. data/spec/internal/app/models/model_base.rb +6 -0
  55. data/spec/internal/app/models/motorcycle.rb +9 -0
  56. data/spec/internal/app/models/traffic_light.rb +47 -0
  57. data/spec/internal/app/models/vehicle.rb +123 -0
  58. data/spec/machine_spec.rb +3167 -0
  59. data/spec/matcher_helpers_spec.rb +39 -0
  60. data/spec/matcher_spec.rb +157 -0
  61. data/spec/models/auto_shop_spec.rb +41 -0
  62. data/spec/models/car_spec.rb +90 -0
  63. data/spec/models/motorcycle_spec.rb +44 -0
  64. data/spec/models/traffic_light_spec.rb +56 -0
  65. data/spec/models/vehicle_spec.rb +580 -0
  66. data/spec/node_collection_spec.rb +371 -0
  67. data/spec/path_collection_spec.rb +271 -0
  68. data/spec/path_spec.rb +488 -0
  69. data/spec/spec_helper.rb +6 -0
  70. data/spec/state_collection_spec.rb +352 -0
  71. data/spec/state_context_spec.rb +442 -0
  72. data/spec/state_machine_spec.rb +29 -0
  73. data/spec/state_spec.rb +970 -0
  74. data/spec/support/migration_helpers.rb +50 -0
  75. data/spec/support/models.rb +6 -0
  76. data/spec/transition_collection_spec.rb +2199 -0
  77. data/spec/transition_spec.rb +1558 -0
  78. data/state_machines.gemspec +23 -0
  79. metadata +194 -0
@@ -0,0 +1,3 @@
1
+ module StateMachines
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,8 @@
1
+ module StateMachines
2
+ # YARD plugin for automated documentation
3
+ module YARD
4
+ end
5
+ end
6
+
7
+ require 'state_machines/yard/handlers'
8
+ require 'state_machines/yard/templates'
@@ -0,0 +1,3 @@
1
+ require 'state_machines/version'
2
+ require 'state_machines/core'
3
+ require 'state_machines/core_ext'
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ErrorByDefault' do
4
+ let(:klass) { Class.new }
5
+ let(:machine) { StateMachines::Machine.new(klass) }
6
+ let(:collection) { StateMachines::NodeCollection.new(machine) }
7
+ it '#length' do
8
+ expect(collection.length).to eq(0)
9
+ end
10
+
11
+ it do
12
+ expect(collection.machine).to eq(machine)
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ErrorWithMessage' do
4
+ let(:klass) { Class.new }
5
+ let(:machine) { StateMachines::Machine.new(klass) }
6
+ let(:collection) { StateMachines::NodeCollection.new(machine) }
7
+ it 'should_raise_exception_if_invalid_option_specified' do
8
+ expect { StateMachines::NodeCollection.new(machine, invalid: true) }.to raise_error(ArgumentError)
9
+ # assert_equal 'Invalid key(s): invalid', exception.message
10
+ end
11
+
12
+ it 'should_raise_exception_on_lookup_if_invalid_index_specified' do
13
+ expect { collection[:something, :invalid] }.to raise_error(ArgumentError)
14
+ # assert_equal 'Invalid index: :invalid', exception.message
15
+ end
16
+
17
+ it 'should raise exception on fetch if invalid index specified' do
18
+ expect { collection[:something, :invalid] }.to raise_error(ArgumentError)
19
+ # assert_equal 'Invalid index: :invalid', exception.message
20
+ end
21
+ end
22
+
23
+ # class ErrorWithMessageTest < Test::Unit::TestCase
24
+ #
25
+ # it 'should_raise_exception_if_invalid_option_specified
26
+ # exception = assert_raise(ArgumentError) { StateMachines::NodeCollection.new(@machine, :invalid => true) }
27
+ # assert_equal 'Invalid key(s): invalid', exception.message
28
+ # end
29
+ #
30
+ # it 'should_raise_exception_on_lookup_if_invalid_index_specified
31
+ # exception = assert_raise(ArgumentError) { @collection[:something, :invalid] }
32
+ # assert_equal 'Invalid index: :invalid', exception.message
33
+ # end
34
+ #
35
+ # it 'should_raise_exception_on_fetch_if_invalid_index_specified
36
+ # exception = assert_raise(ArgumentError) { @collection.fetch(:something, :invalid) }
37
+ # assert_equal 'Invalid index: :invalid', exception.message
38
+ # end
39
+ # end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachines::HelperModule do
4
+ let(:klass) { Class.new }
5
+ let(:machine) { StateMachines::Machine.new(klass) }
6
+ let(:helper_module) { StateMachines::HelperModule.new(machine, :instance) }
7
+ it 'should not have a name' do
8
+ expect(helper_module.name.to_s).to eq('')
9
+ end
10
+
11
+ it 'should_provide_human_readable_to_s' do
12
+ expect(helper_module.to_s).to eq("#{klass} :state instance helpers")
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ class AutoShop
2
+ attr_accessor :num_customers
3
+
4
+ def initialize
5
+ @num_customers = 0
6
+ super
7
+ end
8
+
9
+ state_machine initial: :available do
10
+ after_transition available: any, do: :increment_customers
11
+ after_transition busy: any, do: :decrement_customers
12
+
13
+ event :tow_vehicle do
14
+ transition available: :busy
15
+ end
16
+
17
+ event :fix_vehicle do
18
+ transition busy: :available
19
+ end
20
+ end
21
+
22
+ # Increments the number of customers in service
23
+ def increment_customers
24
+ self.num_customers += 1
25
+ end
26
+
27
+ # Decrements the number of customers in service
28
+ def decrement_customers
29
+ self.num_customers -= 1
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ class Car < Vehicle
2
+ state_machine do
3
+ event :reverse do
4
+ transition [:parked, :idling, :first_gear] => :backing_up
5
+ end
6
+
7
+ event :park do
8
+ transition backing_up: :parked
9
+ end
10
+
11
+ event :idle do
12
+ transition backing_up: :idling
13
+ end
14
+
15
+ event :shift_up do
16
+ transition backing_up: :first_gear
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ class ModelBase
2
+ def save
3
+ @saved = true
4
+ self
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ class Motorcycle < Vehicle
2
+ state_machine initial: :idling do
3
+ state :first_gear do
4
+ def decibels
5
+ 1.0
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,47 @@
1
+ class TrafficLight
2
+ state_machine initial: :stop do
3
+ event :cycle do
4
+ transition stop: :proceed, proceed: :caution, caution: :stop
5
+ end
6
+
7
+ state :stop do
8
+ def color(transform)
9
+ value = 'red'
10
+
11
+ if block_given?
12
+ yield value
13
+ else
14
+ value.send(transform)
15
+ end
16
+
17
+ value
18
+ end
19
+ end
20
+
21
+ state all - :proceed do
22
+ def capture_violations?
23
+ true
24
+ end
25
+ end
26
+
27
+ state :proceed do
28
+ def color(transform)
29
+ 'green'
30
+ end
31
+
32
+ def capture_violations?
33
+ false
34
+ end
35
+ end
36
+
37
+ state :caution do
38
+ def color(transform)
39
+ 'yellow'
40
+ end
41
+ end
42
+ end
43
+
44
+ def color(transform = :to_s)
45
+ super
46
+ end
47
+ end
@@ -0,0 +1,123 @@
1
+ class Vehicle < ModelBase
2
+ attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved, :time_elapsed, :last_transition_args
3
+
4
+ def initialize(attributes = {})
5
+ attributes = {
6
+ auto_shop: AutoShop.new,
7
+ seatbelt_on: false,
8
+ insurance_premium: 50,
9
+ force_idle: false,
10
+ callbacks: [],
11
+ saved: false
12
+ }.merge(attributes)
13
+
14
+ attributes.each { |attr, value| send("#{attr}=", value) }
15
+ super()
16
+ end
17
+
18
+ # Defines the state machine for the state of the vehicled
19
+ state_machine initial: lambda { |vehicle| vehicle.force_idle ? :idling : :parked }, action: :save do
20
+ before_transition { |vehicle, transition| vehicle.last_transition_args = transition.args }
21
+ before_transition parked: any, do: :put_on_seatbelt
22
+ before_transition any => :stalled, :do => :increase_insurance_premium
23
+ after_transition any => :parked, :do => lambda { |vehicle| vehicle.seatbelt_on = false }
24
+ after_transition on: :crash, do: :tow
25
+ after_transition on: :repair, do: :fix
26
+
27
+ # Callback tracking for initial state callbacks
28
+ after_transition any => :parked, :do => lambda { |vehicle| vehicle.callbacks << 'before_enter_parked' }
29
+ before_transition any => :idling, :do => lambda { |vehicle| vehicle.callbacks << 'before_enter_idling' }
30
+
31
+ around_transition do |vehicle, transition, block|
32
+ time = Time.now
33
+ block.call
34
+ vehicle.time_elapsed = Time.now - time
35
+ end
36
+
37
+ event all do
38
+ transition locked: :parked
39
+ end
40
+
41
+ event :park do
42
+ transition [:idling, :first_gear] => :parked
43
+ end
44
+
45
+ event :ignite do
46
+ transition stalled: :stalled
47
+ transition parked: :idling
48
+ end
49
+
50
+ event :idle do
51
+ transition first_gear: :idling
52
+ end
53
+
54
+ event :shift_up do
55
+ transition idling: :first_gear, first_gear: :second_gear, second_gear: :third_gear
56
+ end
57
+
58
+ event :shift_down do
59
+ transition third_gear: :second_gear
60
+ transition second_gear: :first_gear
61
+ end
62
+
63
+ event :crash do
64
+ transition [:first_gear, :second_gear, :third_gear] => :stalled, :if => lambda { |vehicle| vehicle.auto_shop.available? }
65
+ end
66
+
67
+ event :repair do
68
+ transition stalled: :parked, if: :auto_shop_busy?
69
+ end
70
+ end
71
+
72
+ state_machine :insurance_state, initial: :inactive, namespace: 'insurance' do
73
+ event :buy do
74
+ transition inactive: :active
75
+ end
76
+
77
+ event :cancel do
78
+ transition active: :inactive
79
+ end
80
+ end
81
+
82
+ def save
83
+ super
84
+ end
85
+
86
+ def new_record?
87
+ @saved == false
88
+ end
89
+
90
+ def park
91
+ super
92
+ end
93
+
94
+ # Tows the vehicle to the auto shop
95
+ def tow
96
+ auto_shop.tow_vehicle
97
+ end
98
+
99
+ # Fixes the vehicle; it will no longer be in the auto shop
100
+ def fix
101
+ auto_shop.fix_vehicle
102
+ end
103
+
104
+ def decibels
105
+ 0.0
106
+ end
107
+
108
+ private
109
+ # Safety first! Puts on our seatbelt
110
+ def put_on_seatbelt
111
+ self.seatbelt_on = true
112
+ end
113
+
114
+ # We crashed! Increase the insurance premium on the vehicle
115
+ def increase_insurance_premium
116
+ self.insurance_premium += 100
117
+ end
118
+
119
+ # Is the auto shop currently servicing another customer?
120
+ def auto_shop_busy?
121
+ auto_shop.busy?
122
+ end
123
+ end