james 0.1.1-universal-darwin-10 → 0.2.0-universal-darwin-10

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,18 +2,28 @@ module James
2
2
 
3
3
  class State
4
4
 
5
- attr_reader :transitions
5
+ # Transitions are internal transitions & external transitions.
6
+ #
7
+ def transitions
8
+ @transitions
9
+ end
6
10
 
7
- # Returns all possible phrases that lead
8
- # away from this state.
9
11
  #
10
- def phrases
12
+ #
13
+ def expects
11
14
  transitions.keys
12
15
  end
13
16
 
17
+ #
18
+ #
19
+ def internal_expects
20
+ transitions.select { |phrase, target| target.respond_to?(:to_sym) || target == self.context }.keys
21
+ end
22
+
23
+
14
24
  # Returns the next state for the given phrase.
15
25
  #
16
- # It accesses the context (aka Dialog(ue)) to get a full object state.
26
+ # It accesses the context (aka Dialog) to get a full object state.
17
27
  #
18
28
  # If it is a Symbol, James will try to get the real state.
19
29
  # If not, it will just return it (a State already, or lambda).
@@ -23,15 +33,26 @@ module James
23
33
  state.respond_to?(:id2name) ? context.state_for(state) : state
24
34
  end
25
35
 
26
- def __into__
27
- @into_block && context.instance_eval(&@into_block)
28
- end
29
- def __exit__
30
- @exit_block && context.instance_eval(&@exit_block)
31
- end
32
- def __transition__ &block
33
- context.instance_eval &block
34
- end
36
+ # The naughty privates.
37
+ #
38
+
39
+ # Called by the visitor visiting this state.
40
+ #
41
+ def __into__
42
+ @into_block && context.instance_eval(&@into_block)
43
+ end
44
+
45
+ # Called by the visitor visiting this state.
46
+ #
47
+ def __exit__
48
+ @exit_block && context.instance_eval(&@exit_block)
49
+ end
50
+
51
+ # Called by the visitor visiting this state.
52
+ #
53
+ def __transition__ &block
54
+ context.instance_eval &block
55
+ end
35
56
 
36
57
  end
37
58
 
data/lib/james.rb CHANGED
@@ -3,8 +3,10 @@ module James; end
3
3
  require File.expand_path '../james/state_api', __FILE__
4
4
  require File.expand_path '../james/state_internals', __FILE__
5
5
 
6
- require File.expand_path '../james/visitor', __FILE__
7
- require File.expand_path '../james/visitors', __FILE__
6
+ require File.expand_path '../james/markers/marker', __FILE__
7
+ require File.expand_path '../james/markers/current', __FILE__
8
+ require File.expand_path '../james/markers/memory', __FILE__
9
+ require File.expand_path '../james/conversation', __FILE__
8
10
 
9
11
  require File.expand_path '../james/dialog_api', __FILE__
10
12
  require File.expand_path '../james/dialog_internals', __FILE__
@@ -30,13 +32,11 @@ module James
30
32
  # If called twice or more, will just add more dialogs.
31
33
  #
32
34
  def self.use *dialogs
33
- dialogs.each { |dialog| controller.add_dialog dialog }
35
+ dialogs.each { |dialog| controller << dialog}
34
36
  end
35
37
 
36
38
  # Start listening.
37
39
  #
38
- # Will not listen again if already listening.
39
- #
40
40
  def self.listen options
41
41
  controller.listen options
42
42
  end
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: james
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.1
5
+ version: 0.2.0
6
6
  platform: universal-darwin-10
7
7
  authors:
8
8
  - Florian Hanke
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-05-29 00:00:00 +10:00
12
+ date: 2011-06-08 00:00:00 +10:00
13
13
  default_executable: james
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -38,6 +38,7 @@ extra_rdoc_files: []
38
38
  files:
39
39
  - lib/james/builtin/core_dialog.rb
40
40
  - lib/james/controller.rb
41
+ - lib/james/conversation.rb
41
42
  - lib/james/dialog_api.rb
42
43
  - lib/james/dialog_internals.rb
43
44
  - lib/james/dialogs.rb
@@ -45,23 +46,15 @@ files:
45
46
  - lib/james/inputs/audio.rb
46
47
  - lib/james/inputs/base.rb
47
48
  - lib/james/inputs/terminal.rb
49
+ - lib/james/markers/current.rb
50
+ - lib/james/markers/marker.rb
51
+ - lib/james/markers/memory.rb
48
52
  - lib/james/outputs/audio.rb
49
53
  - lib/james/outputs/terminal.rb
50
54
  - lib/james/state_api.rb
51
55
  - lib/james/state_internals.rb
52
- - lib/james/visitor.rb
53
- - lib/james/visitors.rb
54
56
  - lib/james.rb
55
57
  - aux/james/cli.rb
56
- - spec/aux/james/cli_spec.rb
57
- - spec/integration/test_dialogue_spec.rb
58
- - spec/lib/james/controller_spec.rb
59
- - spec/lib/james/dialog_spec.rb
60
- - spec/lib/james/inputs/audio_spec.rb
61
- - spec/lib/james/inputs/terminal_spec.rb
62
- - spec/lib/james/state_spec.rb
63
- - spec/lib/james/visitor_spec.rb
64
- - spec/lib/james/visitors_spec.rb
65
58
  - bin/james
66
59
  has_rdoc: true
67
60
  homepage: http://floere.github.com/james
@@ -88,13 +81,4 @@ rubygems_version: 1.4.2
88
81
  signing_key:
89
82
  specification_version: 3
90
83
  summary: 'James: Modular Electronic Butler with modular Dialogs.'
91
- test_files:
92
- - spec/aux/james/cli_spec.rb
93
- - spec/integration/test_dialogue_spec.rb
94
- - spec/lib/james/controller_spec.rb
95
- - spec/lib/james/dialog_spec.rb
96
- - spec/lib/james/inputs/audio_spec.rb
97
- - spec/lib/james/inputs/terminal_spec.rb
98
- - spec/lib/james/state_spec.rb
99
- - spec/lib/james/visitor_spec.rb
100
- - spec/lib/james/visitors_spec.rb
84
+ test_files: []
data/lib/james/visitor.rb DELETED
@@ -1,80 +0,0 @@
1
- module James
2
-
3
- # The visitor knows where in the conversation we are.
4
- #
5
- # It also remembers where it has to go back to if
6
- # too much time passes without input.
7
- #
8
- # Note: A visitor should generally be very stupid.
9
- #
10
- class Visitor
11
-
12
- attr_reader :initial, :timer
13
- attr_accessor :current
14
-
15
- # Pass in an initial state to start from.
16
- #
17
- def initialize initial
18
- @current = initial
19
-
20
- @initial = initial
21
- end
22
-
23
- # Resets the current state back to the initial.
24
- #
25
- def reset
26
- self.current = initial
27
- end
28
-
29
- # We hear a phrase.
30
- #
31
- # Also used to start the whole process.
32
- #
33
- def enter
34
- result = current.__into__
35
- yield result if result && block_given?
36
- result
37
- end
38
- def exit
39
- result = current.__exit__
40
- yield result if result && block_given?
41
- result
42
- end
43
- def transition phrase
44
- state_or_lambda = current.next_for phrase
45
- if state_or_lambda.respond_to?(:call)
46
- current.__transition__ &state_or_lambda # Don't transition.
47
- else
48
- self.current = state_or_lambda
49
- end
50
- end
51
- def check
52
- reset && yield("Whoops. That led nowhere. Perhaps you didn't define the target state?") unless self.current
53
- end
54
- def hear phrase, &block
55
- return unless hears? phrase
56
- exit_text = exit &block
57
- transition phrase
58
- check &block
59
- into_text = enter &block
60
- exit_text || into_text
61
- end
62
- def hears? phrase
63
- expects.include? phrase
64
- end
65
- def expects
66
- current.phrases
67
- end
68
- # Does the current state allow penetration into another dialog?
69
- #
70
- def chainable?
71
- current.chainable?
72
- end
73
-
74
- def to_s
75
- "#{self.class.name}(#{initial}, current: #{current})"
76
- end
77
-
78
- end
79
-
80
- end
@@ -1,62 +0,0 @@
1
- module James
2
-
3
- # The visitors class has a number of visitors, whose
4
- # dialogs are visited in order of preference.
5
- #
6
- # Why?
7
- # Discussions have multiple points where they can be.
8
- # (Politics, then this joke, then back again, finally "Oh, bye I have to go!")
9
- #
10
- # In James, though, it is much simpler.
11
- # We just have a visitor in an entry scenario
12
- # (James!, Sleep, Wake up, Something completely different)
13
- # and one in any specific user-given scenario.
14
- #
15
- # Visitors is a proxy object for visitors.
16
- #
17
- class Visitors
18
-
19
- attr_reader :visitors
20
-
21
- def initialize *visitors
22
- @visitors = visitors
23
- end
24
-
25
- # Hear tries all visitors in order
26
- # until one hears a phrase he knows.
27
- #
28
- # After that, all remaining visitors are reset.
29
- #
30
- def hear phrase, &block
31
- enumerator = visitors.dup
32
-
33
- while visitor = enumerator.shift
34
- visitor.hear phrase, &block and break
35
- end
36
-
37
- enumerator.each do |visitor|
38
- visitor.reset
39
- end
40
- end
41
-
42
- # Enter enters the first visitor.
43
- #
44
- def enter
45
- visitors.first.enter
46
- end
47
-
48
- # Simply returns the sum of what phrases all dialogs do expect, front-to-back.
49
- #
50
- # Stops as soon as a visitor is not in a chainable state anymore.
51
- #
52
- def expects
53
- visitors.inject([]) do |expects, visitor|
54
- total = visitor.expects + expects
55
- break total unless visitor.chainable?
56
- total
57
- end
58
- end
59
-
60
- end
61
-
62
- end
@@ -1,19 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../../aux/james/cli', __FILE__
4
-
5
- describe James::CLI do
6
-
7
- before(:each) do
8
- Dir.stub! :[] => ['test_dialog.rb', 'test_dialog.rb', 'test/test_dialog.rb']
9
- end
10
-
11
- let(:cli) { James::CLI.new }
12
-
13
- describe 'find_dialogs' do
14
- it 'returns the right ones' do
15
- cli.find_dialogs.should == ['test_dialog.rb', 'test_dialog.rb', 'test/test_dialog.rb']
16
- end
17
- end
18
-
19
- end
@@ -1,67 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../lib/james', __FILE__
4
-
5
- describe 'TestDialog' do
6
-
7
- context 'unit' do
8
- let(:dialog) do
9
-
10
- Class.new do
11
- include James::Dialog
12
-
13
- hear ['test1', 'test2'] => :first
14
-
15
- state :first do
16
- hear 'go' => :second, 'stay' => :first
17
- end
18
-
19
- state :second do
20
- hear 'go' => :third, 'back' => :first
21
- end
22
- end.new
23
-
24
- end
25
- let(:visitor) do
26
- James::Visitor.new dialog.state_for(:first)
27
- end
28
-
29
- describe "integration" do
30
- it 'works correctly' do
31
- visitor.current.name.should == :first
32
- visitor.hear('go') {}
33
- visitor.current.name.should == :second
34
- visitor.hear('back') {}
35
- visitor.current.name.should == :first
36
- visitor.hear('stay') {}
37
- visitor.current.name.should == :first
38
- end
39
- end
40
- end
41
-
42
- # context 'integration' do
43
- # let(:dialog) do
44
- # dialog = Class.new do
45
- # include James::Dialog
46
- #
47
- # hear ['test1', 'test2'] => :first
48
- # state :first do
49
- # hear 'go' => :second, 'stay' => :first
50
- # end
51
- # state :second do
52
- # hear 'go' => :third, 'back' => :first
53
- # end
54
- # end.new
55
- # end
56
- # it 'works correctly' do
57
- # dialog.state.name.should == :awake
58
- # dialog.hear 'sleep'
59
- # dialog.state.name.should == :sleeping
60
- # end
61
- # it 'delegates correctly' do
62
- # dialog.state.name.should == :awake
63
- # dialog.hear 'test1'
64
- # end
65
- # end
66
-
67
- end
@@ -1,35 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../../lib/james/dialog_api', __FILE__
4
- require File.expand_path '../../../../lib/james/dialog_internals', __FILE__
5
- require File.expand_path '../../../../lib/james/builtin/core_dialog', __FILE__
6
- require File.expand_path '../../../../lib/james/visitors', __FILE__
7
- require File.expand_path '../../../../lib/james/visitor', __FILE__
8
- require File.expand_path '../../../../lib/james/state_api', __FILE__
9
- require File.expand_path '../../../../lib/james/dialogs', __FILE__
10
- require File.expand_path '../../../../lib/james/inputs/base', __FILE__
11
- require File.expand_path '../../../../lib/james/inputs/terminal', __FILE__
12
- require File.expand_path '../../../../lib/james/inputs/audio', __FILE__
13
- require File.expand_path '../../../../lib/james/controller', __FILE__
14
-
15
- describe James::Controller do
16
-
17
- let(:controller) { described_class.new }
18
-
19
- describe 'listening?' do
20
- it 'is correct' do
21
- controller.listening?.should == false
22
- end
23
- end
24
- describe 'expects' do
25
- it 'delegates' do
26
- visitor = stub! :visitor
27
- controller.stub! :visitor => visitor
28
-
29
- visitor.should_receive(:expects).once.with()
30
-
31
- controller.expects
32
- end
33
- end
34
-
35
- end
@@ -1,90 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../../lib/james', __FILE__
4
- require File.expand_path '../../../../lib/james/state_api', __FILE__
5
- require File.expand_path '../../../../lib/james/dialog_api', __FILE__
6
- require File.expand_path '../../../../lib/james/dialog_internals', __FILE__
7
- require File.expand_path '../../../../lib/james/builtin/core_dialog', __FILE__
8
- require File.expand_path '../../../../lib/james/dialogs', __FILE__
9
-
10
- describe James::Dialog do
11
-
12
- context 'units' do
13
- let(:dialog) do
14
- James.use_dialog do
15
-
16
- hear 'something' => :first
17
-
18
- state :first do
19
- hear 'something else' => :second
20
- into {}
21
- exit {}
22
- end
23
-
24
- state :second do
25
- hear 'yet something else' => :first
26
- into {}
27
- exit {}
28
- end
29
-
30
- end
31
- end
32
- describe 'state_for' do
33
- it 'delegates to the class, adding itself' do
34
- new_dialog = dialog.new
35
- dialog.should_receive(:state_for).once.with :some_name, new_dialog
36
-
37
- new_dialog.state_for :some_name
38
- end
39
- it 'returns nil on not found' do
40
- dialog.new.state_for(:nonexistent).should == nil
41
- end
42
- end
43
- end
44
-
45
- describe 'hear with lambda' do
46
- let(:dialog) do
47
- class Test
48
- include James::Dialog
49
-
50
- def initialize
51
- @bla = 'some bla'
52
- end
53
-
54
- state :test do
55
- hear 'bla' => ->(){ @bla }
56
- end
57
- end
58
- Test.new
59
- end
60
- it "is instance eval'd" do
61
- test_state = dialog.state_for :test
62
- test_state.hear 'bla' do |result|
63
- result.should == 'some bla'
64
- end
65
- end
66
- end
67
-
68
- describe 'initialization' do
69
- it 'can be included' do
70
- expect do
71
- class Test
72
- include James::Dialog
73
-
74
- hear 'something' => :some_state
75
- end
76
- end.to_not raise_error
77
- end
78
-
79
- it 'can be defined' do
80
- expect do
81
- James.dialog do
82
-
83
- hear 'something' => :some_state
84
-
85
- end
86
- end.to_not raise_error
87
- end
88
- end
89
-
90
- end
@@ -1,18 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../../../lib/james/inputs/base', __FILE__
4
- require File.expand_path '../../../../../lib/james/inputs/audio', __FILE__
5
-
6
- describe James::Inputs::Audio do
7
-
8
- let(:input) { described_class.new }
9
-
10
- describe 'speechRecognizer' do
11
- it 'does something' do
12
- sender = stub :sender
13
-
14
- input.speechRecognizer sender
15
- end
16
- end
17
-
18
- end
@@ -1,12 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require File.expand_path '../../../../../lib/james/inputs/base', __FILE__
4
- require File.expand_path '../../../../../lib/james/inputs/terminal', __FILE__
5
-
6
- describe James::Inputs::Terminal do
7
-
8
- let(:input) { described_class.new }
9
-
10
-
11
-
12
- end