stateology 0.1.3 → 0.1.6

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 (6) hide show
  1. data/CHANGELOG +9 -0
  2. data/README.markdown +161 -0
  3. data/lib/stateology.rb +145 -86
  4. data/test/test.rb +239 -0
  5. metadata +5 -3
  6. data/README +0 -153
@@ -0,0 +1,9 @@
1
+
2
+
3
+ 3-12-08
4
+ * nested states now supported
5
+ 26-11-08
6
+ * can now provide state() (instance method) a block; the block will be invoked after the successful change of state
7
+
8
+ 23-11-08
9
+ * supported subclassing of classes that include Stateology (see README)
@@ -0,0 +1,161 @@
1
+ Stateology
2
+ ==========
3
+
4
+ *Clean and fast Object state transitions in Ruby using the Mixology C extension.*
5
+
6
+ Supports:
7
+ * Dynamic switching between states (mixing and unmixing modules)
8
+ * Clean DSL-style syntax
9
+ * Optional state\_entry() and state\_exit() hooks for each state (automatically called upon state entry and exit)
10
+ * support for subclassing of classes that include Stateology (see below)
11
+ * support for nested states, i.e states defined within other states
12
+
13
+ Use as in the following:
14
+
15
+ class Sample
16
+ include Stateology
17
+
18
+ state(:Happy) {
19
+ def state_entry
20
+ puts "entering Happy state"
21
+ end
22
+
23
+ def do_something
24
+ puts "Pets a puppy"
25
+ end
26
+
27
+ def state_exit
28
+ puts "exiting Happy state"
29
+ end
30
+ }
31
+
32
+ state(:Angry) {
33
+ def state_entry
34
+ puts "entering Angry state"
35
+ end
36
+
37
+ def do_something
38
+ puts "Kicks a puppy"
39
+ end
40
+
41
+ def state_exit
42
+ puts "exiting Angry state"
43
+ end
44
+ }
45
+
46
+ # methods declared outside a 'state' are not part of any state
47
+
48
+ def state_entry
49
+ puts "entering Default state"
50
+ end
51
+
52
+ def do_something
53
+ puts "stares at the ceiling"
54
+ end
55
+
56
+ def state_exit
57
+ puts "exiting Default state"
58
+ end
59
+
60
+ # if we want the state_entry to run on instantiation
61
+ # we must call it from the initialize method
62
+ def initialize
63
+ state_entry
64
+ end
65
+
66
+ end
67
+
68
+ s = Sample.new
69
+
70
+ # in no state
71
+ s.do_something #=> "stares at the ceiling"
72
+
73
+ # now switch to Happy state
74
+ s.state :Happy
75
+ s.do_something #=> "Pets a puppy"
76
+
77
+ # now switch to Angry state
78
+ s.state :Angry
79
+ s.do_something #=> "Kicks a puppy"
80
+
81
+ # now switch back to no state
82
+ s.state nil
83
+ s.do_something #=> "stares at the ceiling"
84
+
85
+ UPDATE:
86
+
87
+ * made it so subclasses can inherit states from their superclasses e.g
88
+
89
+
90
+ class A
91
+ include Stateology
92
+
93
+ state(:Happy) {
94
+ def state_entry
95
+ puts "entering Happy state"
96
+ end
97
+
98
+ def hello
99
+ puts "hello from A"
100
+ end
101
+ }
102
+ end
103
+
104
+ class B < A
105
+ state(:Happy) {
106
+ def hello
107
+ puts "hello from B"
108
+ end
109
+ }
110
+ end
111
+
112
+ b = B.new
113
+
114
+ b.state :Happy
115
+ #=> "entering Happy state"
116
+
117
+ b.hello
118
+ #=> "hello from B"
119
+
120
+ * prior behaviour was for state\_entry not to exist in class B as Happy module from class A was overwritten by the new Happy module in B
121
+ * how does this fix work? the Happy module in B just includes any extant Happy module accessible in B
122
+
123
+
124
+
125
+
126
+ A FEW THINGS TO NOTE
127
+ --------------------
128
+
129
+ * When an object is instantiated it begins life in no state and only ordinary instance methods are accessible (The ordinary instance methods are those defined outside of any state() {} block)
130
+
131
+ * The ordinary instance methods are available to any state so long as they are not overridden by the state.
132
+
133
+ * To change from any given state to 'no state' pass nil as a parameter to the state method
134
+ e.g s.state nil
135
+
136
+ * 'no state', while not a state, may nonetheless have state\_entry() and state\_exit() methods; and these methods will be invoked on 'entry' and exit from 'no state'
137
+
138
+ * The state\_entry method for 'no state' is not automatically called on object instantiation. If you wish state\_entry to run when the object is instantiated invoke it in the initialize() method.
139
+
140
+ * The state\_entry method can also accept parameters:
141
+ e.g s.state :Happy, "hello"
142
+ In the above the string "hello" is passed as a parameter to the state\_entry() method of the Happy state.
143
+
144
+ * The #state method can accept either a Symbol (e.g :Happy) or a Module (e.g Happy or Sample::Happy). The following are equivalent:
145
+ s.state :Happy #=> change state to Happy
146
+
147
+ * The #state method can take a block; the block will be executed after the successful change of state:
148
+ e.g s.state(:Happy) { s.hello } #=> hello method invoked immediately after change of state as it's in the block
149
+
150
+ s.state Sample::Happy #=> equivalent to above (note the fully qualified name; as Happy is a module defined under the Sample class)
151
+
152
+ * alternatively; if the #state method is invoked internally by another instance method of the Sample class then a fully qualified module name is not required:
153
+ state Happy #=> Fully qualified module name not required when #state invoked in an instance method
154
+
155
+ * The #state method can also act as a 'getter' method when invoked with no parameters. It will return the current state name in Symbol form (e.g :Happy)
156
+
157
+ * The #state\_mod method works similarly to the #state 'getter' except it returns the Module representing the current state (e.g Sample::Happy)
158
+
159
+ * The #state?(state\_name) returns boolean true if the current state is equal to state\_name, and false if not. state\_name can be either a Module or a Symbol
160
+
161
+
@@ -7,7 +7,8 @@ end
7
7
  require 'mixology'
8
8
 
9
9
  module Stateology
10
-
10
+ VERSION = "0.1.6"
11
+
11
12
  # alternative to 'nil'
12
13
  Default = nil
13
14
 
@@ -18,113 +19,171 @@ module Stateology
18
19
 
19
20
  # class methods
20
21
  module SM_Class_Methods
21
- def state(name, &block)
22
- m = Module.new(&block)
23
-
24
- if constants.include?(name.to_s) then
25
- inherited_state = const_get(name)
26
-
27
- # ignore if the constant is not a module
28
- m.send(:include, inherited_state) if Module === inherited_state
22
+ def state(name, &block)
23
+
24
+ # if const is defined here then module_eval
25
+ if constants.include?(name.to_s) && const_defined?(name) then
26
+ self.module_eval(&block)
27
+ else
28
+
29
+ m = Module.new
30
+ # if the state is defined further up the chain then "inherit it"
31
+ if constants.include?(name.to_s) && !const_defined?(name) then
32
+ # if constant not defined here then must be inherited
33
+ inherited_state = const_get(name)
34
+
35
+ # ignore if the constant is not a module
36
+ m.send(:include, inherited_state) if inherited_state.instance_of?(Module)
37
+ end
38
+
39
+ m.send(:include, Stateology)
40
+ m.module_eval(&block)
41
+
42
+ const_set(name, m)
29
43
  end
30
-
31
- const_set(name, m)
32
-
33
44
  end
34
45
  end
35
-
46
+
47
+ # strip the class path and return just the constant name, i.e Hello::Fren -> Fren
48
+ def __elided_class_path(sym)
49
+ "#{sym}".split(/::/).last.intern
50
+ end
51
+
52
+ def __sym_to_mod(sym)
53
+ class << self; self; end.const_get(sym)
54
+ end
55
+
56
+ def __mod_to_sym(mod)
57
+ # weird case where module does not have name (i.e when a state created on the eigenclass)
58
+ if mod.name == "" then
59
+ class << self; self; end.constants.each do |v|
60
+ return v.to_sym if __sym_to_mod(v.to_sym) == mod
61
+ end
62
+ return :ConstantNotDefined
63
+ end
64
+
65
+ mod.name.to_sym
66
+ end
67
+
68
+ # is state_name a nested state?
69
+ def __nested_state?(new_state)
70
+
71
+ # test is:
72
+ # (1) are we currently in a state? (non nil)
73
+ # (2) is the new state a state? (non nil)
74
+ # (3) is the new state defined under the current state? (i.e it's nested)
75
+ __current_state &&
76
+ new_state &&
77
+ __current_state.const_defined?(__elided_class_path(__mod_to_sym(new_state)))
78
+ end
79
+
36
80
  # instance methods
37
-
38
- def __state_epilogue(old_state)
39
-
81
+ def __state_epilogue
82
+
83
+ @__SM_nesting.each do |old_state|
84
+ raise NameError if !old_state.instance_of?(Module) && old_state != nil
85
+
86
+ begin
87
+ state_exit()
88
+ rescue NoMethodError
89
+ # do nothing
90
+ end
91
+
92
+ if old_state then unmix(old_state) end
93
+ end
94
+ @__SM_nesting = []
95
+ end
96
+
97
+ def __state_prologue(new_state, state_args, &block)
98
+
40
99
  # ensure that the constant is a module
41
- raise NameError if(!(Module === old_state) && old_state != nil)
42
-
100
+ raise NameError if !new_state.instance_of?(Module) && new_state != nil
101
+
102
+ # only mixin if non-nil (duh)
103
+ if new_state then extend(new_state) end
104
+
43
105
  begin
44
- state_exit()
106
+ state_entry(*state_args, &block)
45
107
  rescue NoMethodError
46
108
  # do nothing
47
109
  end
48
-
49
- if old_state then unmix(old_state) end
110
+
50
111
  end
51
-
52
- def __state_prologue(new_state, state_args)
53
-
54
- # ensure that the constant is a module
55
- raise NameError if(!(Module === new_state) && new_state != nil)
56
-
57
- # only mixin if
58
- if new_state then mixin(new_state) end
59
-
60
- begin
61
- state_entry(*state_args)
62
- rescue NoMethodError
63
- # do nothing
112
+
113
+ def __validate_state_name(state_name)
114
+ # if we receive a Symbol convert it to a constant
115
+ if Symbol === state_name then
116
+ state_name = __sym_to_mod(state_name)
64
117
  end
65
-
118
+
119
+ raise NameError if state_name && !state_name.instance_of?(Module)
120
+
121
+ state_name
122
+ end
123
+
124
+ def __state_transition(new_state, state_args, &block)
125
+ # preven unnecessary state transition
126
+ return if __current_state == new_state
127
+
128
+ # get rid of state_name from arg list
129
+ state_args.shift
130
+
131
+ # exit old state only if the new state is not nested within it
132
+ __state_epilogue unless __nested_state?(new_state)
133
+ __state_prologue(new_state, state_args, &block)
134
+
135
+ @__SM_nesting.unshift(new_state)
136
+ end
137
+
138
+ def __state_getter
139
+ __current_state ? __elided_class_path(__mod_to_sym(__current_state)) : nil
140
+ end
141
+
142
+ def __current_state
143
+ @__SM_nesting ||= [nil]
144
+ @__SM_nesting.first
66
145
  end
67
-
146
+
68
147
  def state(*state_args, &block)
69
-
148
+
70
149
  # behave as getter
71
- if(state_args.empty?) then
72
- return @__SM_cur_state ? "#{@__SM_cur_state}".split(/::/).last.intern : nil
73
- end
74
-
75
- # behave as setter (only care about first argument)
76
- state_name = state_args.shift
77
-
78
- # if we receive a Symbol convert it to a constant
79
- if(Symbol === state_name) then
80
- state_name = self.class.const_get(state_name)
150
+ if state_args.empty? then
151
+ return __state_getter
81
152
  end
82
-
83
- # prevent unnecessary state transitions
84
- return if(@__SM_cur_state == state_name)
85
-
86
- # exit old state
87
- __state_epilogue(@__SM_cur_state)
88
-
89
-
90
- # enter new state
91
- __state_prologue(state_name, state_args)
92
-
93
- # update the current state variable
94
- @__SM_cur_state = state_name
95
-
96
- # if we were given a block, run it now
97
- if(block) then yield end
98
-
99
- rescue NameError
100
- raise NameError, "#{state_name} not a valid state"
101
-
153
+
154
+ new_state = __validate_state_name(state_args.first)
155
+
156
+ __state_transition(new_state, state_args, &block)
157
+
158
+ # return value is the current state
159
+ __current_state
160
+
161
+ rescue NameError
162
+ raise NameError, "#{new_state} not a valid state"
163
+
102
164
  end
103
-
165
+
104
166
  # is the current state equal to state_name?
105
167
  def state?(state_name)
106
-
107
- # if we receive a Symbol convert it to a constant
108
- if(Symbol === state_name) then
109
- state_name = self.class.const_get(state_name)
110
- end
111
-
112
- raise NameError if(!(Module === state_name) && state_name != nil)
113
-
114
- state_name == @__SM_cur_state
115
-
116
- rescue NameError
117
- raise NameError, "#{state_name} not a valid state"
118
-
168
+
169
+ state_name = __validate_state_name(state_name)
170
+
171
+ # compare
172
+ state_name == __current_state
173
+
174
+ rescue NameError
175
+ raise NameError, "#{state_name} not a valid state"
176
+
119
177
  end
120
-
178
+
121
179
  # return the current state as a module
122
180
  def state_mod
123
- @__SM_cur_state
181
+ __current_state
124
182
  end
125
-
126
- private :__state_prologue, :__state_epilogue
127
-
183
+
184
+ private :__state_prologue, :__state_epilogue, :__elided_class_path, :__mod_to_sym, :__sym_to_mod,
185
+ :__nested_state?, :__current_state, :__validate_state_name, :__state_transition, :__state_getter
186
+
128
187
  end
129
188
 
130
189
 
@@ -0,0 +1,239 @@
1
+ require 'test/unit'
2
+ require '../lib/stateology'
3
+
4
+ class Object
5
+ def meta
6
+ class << self; self; end
7
+ end
8
+ end
9
+
10
+ class ParentState
11
+ include Stateology
12
+ attr_reader :state_entry_check
13
+ attr_reader :state_exit_check
14
+
15
+ def state_entry
16
+ @state_entry_check = "entry_nil"
17
+ end
18
+
19
+ def state_exit
20
+ @state_exit_check = "exit_nil"
21
+ end
22
+
23
+ state(:State1) {
24
+
25
+ def state_entry
26
+ @state_entry_check = "entry_state1"
27
+ end
28
+
29
+ def act
30
+ 1
31
+ end
32
+
33
+ def state1_act
34
+ 1
35
+ end
36
+
37
+ def state_exit
38
+ @state_exit_check = "exit_state1"
39
+ end
40
+
41
+ state(:State1_nested) {
42
+ def state_entry(&block)
43
+ puts "balls-deep in State1_nested!"
44
+ if block then yield end
45
+ end
46
+ def act
47
+ 1.5
48
+ end
49
+ }
50
+ }
51
+
52
+ state(:State2) {
53
+ def act
54
+ 2
55
+ end
56
+
57
+ def state2_act
58
+ 2
59
+ end
60
+ }
61
+
62
+
63
+ def act
64
+ 0
65
+ end
66
+ end
67
+
68
+ class ChildState < ParentState
69
+ state(:State1) {
70
+ def act_child
71
+ 1
72
+ end
73
+ }
74
+
75
+ state(:State2) {
76
+ def act_child
77
+ 2
78
+ end
79
+ }
80
+
81
+ def act
82
+ 0
83
+ end
84
+ end
85
+
86
+ class StateologyTest < Test::Unit::TestCase
87
+ puts "testing Stateology #{Stateology::VERSION}"
88
+
89
+ def test_nil_state
90
+ s = ParentState.new
91
+ assert_equal(0, s.act)
92
+ assert_equal(nil, s.state_exit_check)
93
+ assert_equal(nil, s.state_entry_check)
94
+ assert_raises(NoMethodError) { s.state1_act }
95
+ end
96
+
97
+ def test_transition_from_nil_state
98
+ s = ParentState.new
99
+ assert_equal(0, s.act)
100
+ assert_equal(nil, s.state_exit_check)
101
+ assert_equal(nil, s.state_entry_check)
102
+ s.state :State1
103
+ assert_equal("exit_nil", s.state_exit_check)
104
+ assert_equal("entry_state1", s.state_entry_check)
105
+ assert_equal(1, s.act)
106
+ end
107
+
108
+ def test_transition_to_nil_state
109
+ s = ParentState.new
110
+ s.state :State1
111
+ assert_equal(1, s.act)
112
+ s.state nil
113
+ assert_equal("exit_state1", s.state_exit_check)
114
+ assert_equal("entry_nil", s.state_entry_check)
115
+ assert_equal(0, s.act)
116
+ assert_raises(NoMethodError) { s.state1_act }
117
+ end
118
+
119
+ def test_transition_from_state1_to_state2
120
+ s = ParentState.new
121
+ s.state :State1
122
+ assert_equal(1, s.act)
123
+ assert_raises(NoMethodError) { s.state2_act }
124
+ s.state :State2
125
+ assert_equal(2, s.act)
126
+ assert_raises(NoMethodError) { s.state1_act }
127
+ end
128
+
129
+ def test_inheritance_of_state
130
+ s = ChildState.new
131
+ s.state :State1
132
+
133
+ # testing inherited state methods
134
+ assert_equal(1, s.act)
135
+ assert_equal(1, s.state1_act)
136
+
137
+ # testing own method
138
+ assert_equal(1, s.act_child)
139
+ end
140
+
141
+ def test_cant_transition_to_nested_from_nil
142
+ s = ParentState.new
143
+ assert_raises(NameError){ s.state(:State1_nested1) }
144
+ end
145
+
146
+
147
+ def test_nested_state
148
+ s = ParentState.new
149
+ s.state :State1
150
+ s.state :State1_nested
151
+ assert_equal(1.5, s.act)
152
+ assert_equal(1, s.state1_act)
153
+ s.state nil
154
+ assert_raises(NoMethodError) { s.state1_act }
155
+ assert_equal(0, s.act)
156
+ end
157
+
158
+ def test_state_getter
159
+ s = ParentState.new
160
+ assert_equal(nil, s.state)
161
+
162
+ s.state :State1
163
+ assert_equal(:State1, s.state)
164
+
165
+ s.state :State1_nested
166
+ assert_equal(:State1_nested, s.state)
167
+ end
168
+
169
+ def test_state_compare
170
+ s = ParentState.new
171
+ assert_equal(true, s.state?(nil))
172
+
173
+ s.state :State1
174
+ assert_equal(false, s.state?(nil))
175
+ assert_equal(true, s.state?(:State1))
176
+
177
+ s.state :State1_nested
178
+ assert_equal(false, s.state?(:State1))
179
+ assert_equal(true, s.state?(:State1_nested))
180
+
181
+ s.state nil
182
+ assert_equal(true, s.state?(nil))
183
+ end
184
+
185
+ def test_state_defined_on_singleton
186
+ s = ParentState.new
187
+
188
+ class << s
189
+ state(:Sing_state) {
190
+ def state_entry
191
+ @state_entry_check = "sing_entry"
192
+ end
193
+
194
+ def act
195
+ 99
196
+ end
197
+
198
+ def state_exit
199
+ @state_exit_check = "sing_exit"
200
+ end
201
+ }
202
+ end
203
+
204
+ assert_equal(0, s.act)
205
+
206
+ s.state :Sing_state
207
+
208
+ # test the getter
209
+ assert_equal(:Sing_state, s.state)
210
+
211
+ # test state_entry
212
+ assert_equal("sing_entry", s.state_entry_check)
213
+
214
+ # test the act function
215
+ assert_equal(99, s.act)
216
+
217
+ # test state compare
218
+ assert_equal(true, s.state?(:Sing_state))
219
+
220
+ s.state nil
221
+
222
+ # test state_exit
223
+ assert_equal("sing_exit", s.state_exit_check)
224
+
225
+ end
226
+
227
+ end
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stateology
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mair
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-14 00:00:00 +13:00
12
+ date: 2008-12-03 00:00:00 +13:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -31,10 +31,12 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
 
33
33
  files:
34
- - README
34
+ - README.markdown
35
35
  - LICENSE
36
36
  - lib/stateology.rb
37
37
  - sample.rb
38
+ - CHANGELOG
39
+ - test/test.rb
38
40
  has_rdoc: false
39
41
  homepage: http://banisterfiend.wordpress.com
40
42
  post_install_message:
data/README DELETED
@@ -1,153 +0,0 @@
1
- Clean and fast Object state transitions in Ruby using the Mixology C extension.
2
-
3
- Supports:
4
- * Dynamic switching between states (mixing and unmixing modules)
5
- * Clean DSL-style syntax
6
- * Optional state_entry() and state_exit() hooks for each state (automatically called upon state entry and exit)
7
- * support for subclassing of classes that include Stateology (see below)
8
-
9
- Use as in the following:
10
-
11
- class Sample
12
- include Stateology
13
-
14
- state(:Happy) {
15
- def state_entry
16
- puts "entering Happy state"
17
- end
18
-
19
- def do_something
20
- puts "Pets a puppy"
21
- end
22
-
23
- def state_exit
24
- puts "exiting Happy state"
25
- end
26
- }
27
-
28
- state(:Angry) {
29
- def state_entry
30
- puts "entering Angry state"
31
- end
32
-
33
- def do_something
34
- puts "Kicks a puppy"
35
- end
36
-
37
- def state_exit
38
- puts "exiting Angry state"
39
- end
40
- }
41
-
42
- # methods declared outside a 'state' are not part of any state
43
-
44
- def state_entry
45
- puts "entering Default state"
46
- end
47
-
48
- def do_something
49
- puts "stares at the ceiling"
50
- end
51
-
52
- def state_exit
53
- puts "exiting Default state"
54
- end
55
-
56
- # if we want the state_entry to run on instantiation
57
- # we must call it from the initialize method
58
- def initialize
59
- state_entry
60
- end
61
-
62
- end
63
-
64
- s = Sample.new
65
-
66
- # in no state
67
- s.do_something #=> "stares at the ceiling"
68
-
69
- # now switch to Happy state
70
- s.state :Happy
71
- s.do_something #=> "Pets a puppy"
72
-
73
- # now switch to Angry state
74
- s.state :Angry
75
- s.do_something #=> "Kicks a puppy"
76
-
77
- # now switch back to no state
78
- s.state nil
79
- s.do_something #=> "stares at the ceiling"
80
-
81
- UPDATE:
82
- * made it so subclasses can inherit states from their superclasses e.g
83
- class A
84
- include Stateology
85
-
86
- state(:Happy) {
87
- def state_entry
88
- puts "entering Happy state"
89
- end
90
-
91
- def hello
92
- puts "hello from A"
93
- end
94
- }
95
- end
96
-
97
- class B < A
98
- state(:Happy) {
99
- def hello
100
- puts "hello from B"
101
- end
102
- }
103
- end
104
-
105
- b = B.new
106
-
107
- b.state :Happy
108
- #=> "entering Happy state"
109
-
110
- b.hello
111
- #=> "hello from B"
112
-
113
- * prior behaviour was for state_entry not to exist in class B as Happy module from class A was overwritten by the new Happy module in B
114
- * how does this fix work? the Happy module in B just includes any extant Happy module accessible in B
115
-
116
-
117
-
118
-
119
- ---=A FEW THINGS TO NOTE=---
120
-
121
- * When an object is instantiated it begins life in no state and only ordinary instance methods are accessible (The ordinary instance methods are those defined outside of any state() {} block)
122
-
123
- * The ordinary instance methods are available to any state so long as they are not overridden by the state.
124
-
125
- * To change from any given state to 'no state' pass nil as a parameter to the state method
126
- e.g s.state nil
127
-
128
- * 'no state', while not a state, may nonetheless have state_entry() and state_exit() methods; and these methods will be invoked on 'entry' and exit from 'no state'
129
-
130
- * The state_entry method for 'no state' is not automatically called on object instantiation. If you wish state_entry to run when the object is instantiated invoke it in the initialize() method.
131
-
132
- * The state_entry method can also accept parameters:
133
- e.g s.state :Happy, "hello"
134
- In the above the string "hello" is passed as a parameter to the state_entry() method of the Happy state.
135
-
136
- * The #state method can accept either a Symbol (e.g :Happy) or a Module (e.g Happy or Sample::Happy). The following are equivalent:
137
- s.state :Happy #=> change state to Happy
138
-
139
- * The #state method can take a block; the block will be executed after the successful change of state:
140
- e.g s.state(:Happy) { s.hello } #=> hello method invoked immediately after change of state as it's in the block
141
-
142
- s.state Sample::Happy #=> equivalent to above (note the fully qualified name; as Happy is a module defined under the Sample class)
143
-
144
- * alternatively; if the #state method is invoked internally by another instance method of the Sample class then a fully qualified module name is not required:
145
- state Happy #=> Fully qualified module name not required when #state invoked in an instance method
146
-
147
- * The #state method can also act as a 'getter' method when invoked with no parameters. It will return the current state name in Symbol form (e.g :Happy)
148
-
149
- * The #state_mod method works similarly to the #state 'getter' except it returns the Module representing the current state (e.g Sample::Happy)
150
-
151
- * The #state?(state_name) returns boolean true if the current state is equal to state_name, and false if not. state_name can be either a Module or a Symbol
152
-
153
- * One last note: state(:Name) {} is just DSL-style syntactic sugar for module Name...end