stateology 0.1.3 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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