Class: James::State
- Inherits:
-
Object
- Object
- James::State
- Defined in:
- lib/james/state_api.rb,
lib/james/state_internals.rb
Overview
A state is defined in a dialog.
It has a name with which it can be targeted.
A state has three methods:
* hear: If this phrase (or one of these phrases) is heard, move to that state. Takes a hash.
* into: A block that is called on entering.
* exit: A block that is called on exit.
Example:
state :time do
hear ['What time is it?', 'And now?'] => :time
into { time = Time.now; "It is currently #{time.hour} #{time.min}." }
exit { "And that was the time." }
end
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
-
#<<(dialog) ⇒ Object
Chain the given dialog to this state.
-
#__exit__ ⇒ Object
Called by the visitor visiting this state.
-
#__into__ ⇒ Object
Called by the visitor visiting this state.
-
#__transition__(&block) ⇒ Object
Called by the visitor visiting this state.
-
#chainable ⇒ Object
A chainable state is a state from which other Dialogs can be reached.
-
#chainable? ⇒ Boolean
By default, a state is not chainable.
-
#exit(text = nil, &block) ⇒ Object
Execute this block or say the text when exiting this state.
-
#expand(transitions) ⇒ Object
Expands a hash in the form * [a, b] => c to a => c, b => c but leaves a non-array key alone.
- #expects ⇒ Object
-
#hear(transitions) ⇒ Object
How do I get from this state to another?.
-
#initialize(name, context) ⇒ State
constructor
A new instance of State.
- #internal_expects ⇒ Object
-
#into(text = nil, &block) ⇒ Object
Execute this block or say the text when entering this state.
-
#next_for(phrase) ⇒ Object
Returns the next state for the given phrase.
-
#raise_no_text_or_block(on_method) ⇒ Object
Raise an ArgumentError for the given method if it needs either a text or a block.
-
#to_s ⇒ Object
Description of self using name and transitions.
-
#transitions ⇒ Object
Transitions are internal transitions & external transitions.
Constructor Details
#initialize(name, context) ⇒ State
Returns a new instance of State.
23 24 25 26 27 28 29 30 |
# File 'lib/james/state_api.rb', line 23 def initialize name, context @name = name @context = context @transitions = {} instance_eval(&Proc.new) if block_given? end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
21 22 23 |
# File 'lib/james/state_api.rb', line 21 def context @context end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
21 22 23 |
# File 'lib/james/state_api.rb', line 21 def name @name end |
Instance Method Details
#<<(dialog) ⇒ Object
Chain the given dialog to this state.
75 76 77 |
# File 'lib/james/state_api.rb', line 75 def << dialog dialog.chain_to self end |
#__exit__ ⇒ Object
Called by the visitor visiting this state.
47 48 49 |
# File 'lib/james/state_internals.rb', line 47 def __exit__ @exit_block && context.instance_eval(&@exit_block) end |
#__into__ ⇒ Object
Called by the visitor visiting this state.
41 42 43 |
# File 'lib/james/state_internals.rb', line 41 def __into__ @into_block && context.instance_eval(&@into_block) end |
#__transition__(&block) ⇒ Object
Called by the visitor visiting this state.
53 54 55 |
# File 'lib/james/state_internals.rb', line 53 def __transition__ &block context.instance_eval &block end |
#chainable ⇒ Object
A chainable state is a state from which other Dialogs can be reached.
82 83 84 |
# File 'lib/james/state_api.rb', line 82 def chainable @chainable = true end |
#chainable? ⇒ Boolean
By default, a state is not chainable.
117 118 119 |
# File 'lib/james/state_api.rb', line 117 def chainable? !!@chainable end |
#exit(text = nil, &block) ⇒ Object
Execute this block or say the text when exiting this state.
Examples:
exit "Yes, Sir?"
exit { "A random number is #{rand(10)}" }
67 68 69 70 71 |
# File 'lib/james/state_api.rb', line 67 def exit text = nil, &block @exit_block = block || text && lambda { text } || raise_no_text_or_block(__method__) end |
#expand(transitions) ⇒ Object
Expands a hash in the form
* [a, b] => c to a => c, b => c
but leaves a non-array key alone.
99 100 101 102 103 104 105 106 107 |
# File 'lib/james/state_api.rb', line 99 def transitions results = {} transitions.each_pair do |phrases, state_name| [*phrases].each do |phrase| results[phrase] = state_name end end results end |
#expects ⇒ Object
13 14 15 |
# File 'lib/james/state_internals.rb', line 13 def expects transitions.keys end |
#hear(transitions) ⇒ Object
How do I get from this state to another?
Example:
hear 'What time is it?' => :time,
'What? This late?' => :yes
Example for staying in the same state:
hear 'What time is it?' # Implicitly staying.
Example for staying in the same state and doing something:
hear 'What time is it?' => ->() { "I'm staying in the same state" }
44 45 46 47 |
# File 'lib/james/state_api.rb', line 44 def hear transitions transitions = { transitions => name } unless transitions.respond_to?(:to_hash) @transitions = (transitions).merge @transitions end |
#internal_expects ⇒ Object
19 20 21 |
# File 'lib/james/state_internals.rb', line 19 def internal_expects transitions.select { |phrase, target| target.respond_to?(:to_sym) || target == self.context }.keys end |
#into(text = nil, &block) ⇒ Object
Execute this block or say the text when entering this state.
Examples:
into "Yes, Sir?"
into { "A random number is #{rand(10)}" }
55 56 57 58 59 |
# File 'lib/james/state_api.rb', line 55 def into text = nil, &block @into_block = block || text && lambda { text } || raise_no_text_or_block(__method__) end |
#next_for(phrase) ⇒ Object
Returns the next state for the given phrase.
It accesses the context (aka Dialog) to get a full object state.
If it is a Symbol, James will try to get the real state. If not, it will just return it (a State already, or lambda).
31 32 33 34 |
# File 'lib/james/state_internals.rb', line 31 def next_for phrase state = self.transitions[phrase] state.respond_to?(:id2name) ? context.state_for(state) : state end |
#raise_no_text_or_block(on_method) ⇒ Object
Raise an ArgumentError for the given method if it needs either a text or a block.
111 112 113 |
# File 'lib/james/state_api.rb', line 111 def raise_no_text_or_block on_method raise ArgumentError.new("Neither block nor text given to ##{on_method} call in #{caller[1]}.") end |
#to_s ⇒ Object
Description of self using name and transitions.
88 89 90 |
# File 'lib/james/state_api.rb', line 88 def to_s "#{self.class.name}(#{name}, #{context}, #{@transitions})" end |
#transitions ⇒ Object
Transitions are internal transitions & external transitions.
7 8 9 |
# File 'lib/james/state_internals.rb', line 7 def transitions @transitions end |