james 0.0.6-universal-darwin-10 → 0.0.7-universal-darwin-10
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/james +2 -2
- data/lib/james.rb +16 -2
- data/lib/james/builtin/core_dialogue.rb +25 -4
- data/lib/james/controller.rb +2 -22
- data/lib/james/dialogue_api.rb +4 -0
- data/lib/james/dialogue_internals.rb +0 -8
- data/lib/james/dialogues.rb +2 -2
- data/lib/james/inputs/audio.rb +2 -0
- data/lib/james/inputs/base.rb +2 -0
- data/lib/james/inputs/terminal.rb +1 -0
- data/lib/james/state_api.rb +1 -1
- data/lib/james/state_internals.rb +5 -2
- data/lib/james/visitor.rb +7 -4
- data/spec/lib/james/dialogue_spec.rb +2 -0
- data/spec/lib/james/state_spec.rb +32 -3
- data/spec/lib/james/visitors_spec.rb +13 -4
- metadata +16 -18
- data/lib/old/main.rb +0 -30
- data/lib/old/main_dialogue.rb +0 -47
data/bin/james
CHANGED
data/lib/james.rb
CHANGED
@@ -1,13 +1,27 @@
|
|
1
1
|
module James; end
|
2
2
|
|
3
|
-
require File.expand_path '../james/timer', __FILE__
|
3
|
+
# require File.expand_path '../james/timer', __FILE__
|
4
|
+
|
5
|
+
require File.expand_path '../james/state_api', __FILE__
|
6
|
+
require File.expand_path '../james/state_internals', __FILE__
|
7
|
+
|
4
8
|
require File.expand_path '../james/visitor', __FILE__
|
5
9
|
require File.expand_path '../james/visitors', __FILE__
|
6
|
-
require File.expand_path '../james/dialogues', __FILE__
|
7
10
|
|
8
11
|
require File.expand_path '../james/dialogue_api', __FILE__
|
9
12
|
require File.expand_path '../james/dialogue_internals', __FILE__
|
10
13
|
|
14
|
+
require File.expand_path '../james/dialogues', __FILE__
|
15
|
+
|
16
|
+
require File.expand_path '../james/inputs/base', __FILE__
|
17
|
+
require File.expand_path '../james/inputs/audio', __FILE__
|
18
|
+
require File.expand_path '../james/inputs/terminal', __FILE__
|
19
|
+
|
20
|
+
require File.expand_path '../james/outputs/audio', __FILE__
|
21
|
+
require File.expand_path '../james/outputs/terminal', __FILE__
|
22
|
+
|
23
|
+
require File.expand_path '../james/builtin/core_dialogue', __FILE__
|
24
|
+
|
11
25
|
require File.expand_path '../james/controller', __FILE__
|
12
26
|
|
13
27
|
module James
|
@@ -1,22 +1,43 @@
|
|
1
|
+
# This is the core dialogue every dialogue will be hooking into.
|
2
|
+
#
|
3
|
+
# Eventually, the design should be such that everyone can use
|
4
|
+
# the design and core dialogue they like best.
|
5
|
+
#
|
6
|
+
# But to get going, this suffices for now.
|
7
|
+
#
|
1
8
|
class CoreDialogue
|
2
9
|
|
3
10
|
include James::Dialogue
|
4
11
|
|
12
|
+
# The alert state.
|
13
|
+
# When James is in this state, he should be
|
14
|
+
# open for user dialogues.
|
15
|
+
#
|
5
16
|
state :awake do
|
6
|
-
|
17
|
+
# If James is awake, he offers more dialogues
|
18
|
+
# on this state, if there are any hooked into this state.
|
19
|
+
#
|
20
|
+
chainable
|
7
21
|
|
8
|
-
hear 'I need some time alone, James.'
|
9
|
-
"Good night, James."
|
10
|
-
|
22
|
+
hear 'I need some time alone, James.' => :away,
|
23
|
+
"Good night, James." => :exit,
|
24
|
+
"Thank you, James." => :awake
|
11
25
|
into { "Sir?" }
|
12
26
|
end
|
13
27
|
|
28
|
+
# The away state. James does not listen to any
|
29
|
+
# user dialogue hooks, but only for his name
|
30
|
+
# or the good night, i.e. exit phrase.
|
31
|
+
#
|
14
32
|
state :away do
|
15
33
|
hear 'James?' => :awake,
|
16
34
|
"Good night, James." => :exit
|
17
35
|
into { "Of course, Sir!" }
|
18
36
|
end
|
19
37
|
|
38
|
+
# This is not a real state. It just exists to Kernel.exit
|
39
|
+
# James when he enters this state.
|
40
|
+
#
|
20
41
|
state :exit do
|
21
42
|
into do
|
22
43
|
puts "James: Exits through a side door."
|
data/lib/james/controller.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
framework 'AppKit'
|
2
2
|
|
3
|
-
require File.expand_path '../inputs/base', __FILE__
|
4
|
-
require File.expand_path '../inputs/audio', __FILE__
|
5
|
-
require File.expand_path '../inputs/terminal', __FILE__
|
6
|
-
|
7
|
-
require File.expand_path '../outputs/audio', __FILE__
|
8
|
-
require File.expand_path '../outputs/terminal', __FILE__
|
9
|
-
|
10
|
-
require File.expand_path '../builtin/core_dialogue', __FILE__
|
11
|
-
|
12
3
|
module James
|
13
4
|
|
14
5
|
class Controller
|
@@ -36,18 +27,7 @@ module James
|
|
36
27
|
# Load voices from yaml.
|
37
28
|
#
|
38
29
|
def load_voices
|
39
|
-
#
|
40
|
-
# File.open('voices.yml') do |f| yaml_voices << f.read end
|
41
|
-
# voices = YAML.load(yaml_voices)
|
42
|
-
# @male_voice = voices['male']
|
43
|
-
# @female_voice = voices['female']
|
44
|
-
# Commented voices are Apple built-in voices. Can be changed by replacing the last part e.g.'Vicki' with e.g.'Laura'
|
45
|
-
# much better female voice from iVox:
|
46
|
-
# female: com.acapela.iVox.voice.iVoxHeather22k
|
47
|
-
# much better male voice from iVox:
|
48
|
-
# male: com.acapela.iVox.voice.iVoxRyan22k
|
49
|
-
# female: com.apple.speech.synthesis.voice.Vicki
|
50
|
-
# male: com.apple.speech.synthesis.voice.Bruce
|
30
|
+
# TODO
|
51
31
|
end
|
52
32
|
|
53
33
|
# Initialize and "parse" the
|
@@ -61,7 +41,7 @@ module James
|
|
61
41
|
# Start recognizing words.
|
62
42
|
#
|
63
43
|
def start_input
|
64
|
-
@input = Inputs::
|
44
|
+
@input = Inputs::Terminal.new self
|
65
45
|
@input.listen
|
66
46
|
end
|
67
47
|
# Start speaking.
|
data/lib/james/dialogue_api.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
require File.expand_path '../state_api', __FILE__
|
2
|
-
require File.expand_path '../state_internals', __FILE__
|
3
|
-
require File.expand_path '../dialogues', __FILE__
|
4
|
-
|
5
1
|
module James
|
6
2
|
|
7
3
|
# A dialogue is just a container object
|
@@ -54,8 +50,4 @@ module James
|
|
54
50
|
|
55
51
|
end
|
56
52
|
|
57
|
-
# We don't care about the spelling.
|
58
|
-
#
|
59
|
-
Dialog = Dialogue
|
60
|
-
|
61
53
|
end
|
data/lib/james/dialogues.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require File.expand_path '../visitor', __FILE__
|
2
|
-
|
3
1
|
module James
|
4
2
|
|
5
3
|
# Registers all dialogues and connects their states.
|
@@ -42,6 +40,8 @@ module James
|
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
43
|
+
# Hook all user dialogues into the initial state.
|
44
|
+
#
|
45
45
|
initial.hear resolved_entries
|
46
46
|
end
|
47
47
|
|
data/lib/james/inputs/audio.rb
CHANGED
data/lib/james/inputs/base.rb
CHANGED
data/lib/james/state_api.rb
CHANGED
@@ -43,7 +43,7 @@ module James
|
|
43
43
|
#
|
44
44
|
def hear transitions
|
45
45
|
transitions = { transitions => name } unless transitions.respond_to?(:to_hash)
|
46
|
-
@transitions
|
46
|
+
@transitions.merge! expand(transitions)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Execute this block when entering this state.
|
@@ -13,11 +13,14 @@ module James
|
|
13
13
|
|
14
14
|
# Returns the next state for the given phrase.
|
15
15
|
#
|
16
|
-
# It accesses the context (Dialog(ue)) to get a full object state.
|
16
|
+
# It accesses the context (aka Dialog(ue)) to get a full object state.
|
17
|
+
#
|
18
|
+
# If it is a Symbol, James will try to get the real state.
|
19
|
+
# If not, it will just return it (a State already, or lambda).
|
17
20
|
#
|
18
21
|
def next_for phrase
|
19
22
|
state = self.transitions[phrase]
|
20
|
-
state.respond_to?(:
|
23
|
+
state.respond_to?(:id2name) ? context.state_for(state) : state
|
21
24
|
end
|
22
25
|
|
23
26
|
def __into__
|
data/lib/james/visitor.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require File.expand_path '../timer', __FILE__
|
2
|
-
|
3
1
|
module James
|
4
2
|
|
5
3
|
# The visitor knows where in the conversation we are.
|
@@ -46,10 +44,15 @@ module James
|
|
46
44
|
result
|
47
45
|
end
|
48
46
|
def transition phrase
|
49
|
-
|
47
|
+
state_or_lambda = current.next_for phrase
|
48
|
+
if state_or_lambda.respond_to?(:call)
|
49
|
+
state_or_lambda.call # Don't transition.
|
50
|
+
else
|
51
|
+
self.current = state_or_lambda
|
52
|
+
end
|
50
53
|
end
|
51
54
|
def check
|
52
|
-
escape && yield("That led nowhere.") unless current
|
55
|
+
escape && yield("That led nowhere.") unless self.current
|
53
56
|
end
|
54
57
|
def hear phrase, &block
|
55
58
|
return unless hears? phrase
|
@@ -2,6 +2,8 @@
|
|
2
2
|
#
|
3
3
|
require File.expand_path '../../../../lib/james/dialogue_api', __FILE__
|
4
4
|
require File.expand_path '../../../../lib/james/dialogue_internals', __FILE__
|
5
|
+
require File.expand_path '../../../../lib/james/builtin/core_dialogue', __FILE__
|
6
|
+
require File.expand_path '../../../../lib/james/dialogues', __FILE__
|
5
7
|
|
6
8
|
describe James::Dialogue do
|
7
9
|
|
@@ -76,6 +76,17 @@ describe James::State do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
context 'with a returning transition' do
|
80
|
+
let(:state) do
|
81
|
+
described_class.new :some_name, @context do
|
82
|
+
hear 'transition one' => lambda { "I do this and return to :some_name" }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
describe 'phrases' do
|
86
|
+
it { state.phrases.should == ['transition one'] }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
79
90
|
context 'with 1 transition and into and exit' do
|
80
91
|
let(:state) do
|
81
92
|
described_class.new :some_name, @context do
|
@@ -106,12 +117,12 @@ describe James::State do
|
|
106
117
|
end
|
107
118
|
end
|
108
119
|
|
109
|
-
context 'with multiple transition' do
|
120
|
+
context 'with multiple transition and separate hears' do
|
110
121
|
let(:state) do
|
111
122
|
described_class.new :some_name, @context do
|
112
123
|
hear 'transition one' => :next_state1,
|
113
|
-
'transition two' => :next_state2
|
114
|
-
|
124
|
+
'transition two' => :next_state2
|
125
|
+
hear 'transition three' => :next_state3
|
115
126
|
end
|
116
127
|
end
|
117
128
|
describe 'phrases' do
|
@@ -121,6 +132,24 @@ describe James::State do
|
|
121
132
|
it { state.to_s.should == 'James::State(some_name, some_context, {"transition one"=>:next_state1, "transition two"=>:next_state2, "transition three"=>:next_state3})' }
|
122
133
|
end
|
123
134
|
it { state.next_for('transition two').should == :some_state_object2 }
|
135
|
+
it { state.next_for('transition three').should == :some_state_object3 }
|
136
|
+
it { state.next_for('non-existent').should == nil }
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with self-transitions' do
|
140
|
+
some_proc = ->(){ "Going back to where I came from" }
|
141
|
+
let(:state) do
|
142
|
+
described_class.new :some_name, @context do
|
143
|
+
hear 'transition one' => some_proc
|
144
|
+
end
|
145
|
+
end
|
146
|
+
describe 'phrases' do
|
147
|
+
it { state.phrases.should == ['transition one'] }
|
148
|
+
end
|
149
|
+
describe 'to_s' do
|
150
|
+
it { state.to_s.should == "James::State(some_name, some_context, {\"transition one\"=>#{some_proc}})" }
|
151
|
+
end
|
152
|
+
it { state.next_for('transition one').should == some_proc }
|
124
153
|
it { state.next_for('non-existent').should == nil }
|
125
154
|
end
|
126
155
|
|
@@ -45,11 +45,20 @@ describe James::Visitors do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
describe 'expects' do
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
context 'chainable' do
|
49
|
+
before(:each) do
|
50
|
+
first.stub! :expects => [:a, :b], :chainable? => true
|
51
|
+
second.stub! :expects => [:c, :d, :e], :chainable? => true
|
52
|
+
end
|
53
|
+
it { visitors.expects.should == [:a, :b, :c, :d, :e] }
|
54
|
+
end
|
55
|
+
context 'not chainable' do
|
56
|
+
before(:each) do
|
57
|
+
first.stub! :expects => [:a, :b], :chainable? => false
|
58
|
+
second.stub! :expects => [:c, :d, :e], :chainable? => false
|
59
|
+
end
|
60
|
+
it { visitors.expects.should == [:a, :b] }
|
51
61
|
end
|
52
|
-
it { visitors.expects.should == [:a, :b, :c, :d, :e] }
|
53
62
|
end
|
54
63
|
|
55
64
|
end
|
metadata
CHANGED
@@ -1,38 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: james
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 6
|
9
|
-
version: 0.0.6
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.7
|
10
6
|
platform: universal-darwin-10
|
11
7
|
authors:
|
12
8
|
- Florian Hanke
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
date: 2011-05-
|
12
|
+
date: 2011-05-13 00:00:00 +10:00
|
17
13
|
default_executable: james
|
18
14
|
dependencies:
|
19
15
|
- !ruby/object:Gem::Dependency
|
20
16
|
name: rspec
|
21
17
|
prerelease: false
|
22
18
|
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
23
20
|
requirements:
|
24
21
|
- - '>='
|
25
22
|
- !ruby/object:Gem::Version
|
26
|
-
segments:
|
27
|
-
- 0
|
28
23
|
version: "0"
|
29
24
|
type: :development
|
30
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
31
27
|
requirements:
|
32
28
|
- - '>='
|
33
29
|
- !ruby/object:Gem::Version
|
34
|
-
segments:
|
35
|
-
- 0
|
36
30
|
version: "0"
|
37
31
|
description: Modular Electronic Butler. Using a simple dialogue system where you can
|
38
32
|
easily add more dialogues.
|
@@ -58,9 +52,15 @@ files:
|
|
58
52
|
- lib/james/visitor.rb
|
59
53
|
- lib/james/visitors.rb
|
60
54
|
- lib/james.rb
|
61
|
-
- lib/old/main.rb
|
62
|
-
- lib/old/main_dialogue.rb
|
63
55
|
- 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/dialogue_spec.rb
|
60
|
+
- spec/lib/james/state_spec.rb
|
61
|
+
- spec/lib/james/visitor_spec.rb
|
62
|
+
- spec/lib/james/visitors_spec.rb
|
63
|
+
- bin/james
|
64
64
|
has_rdoc: true
|
65
65
|
homepage: http://floere.github.com/james
|
66
66
|
licenses: []
|
@@ -69,22 +69,20 @@ rdoc_options: []
|
|
69
69
|
require_paths:
|
70
70
|
- lib
|
71
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
72
73
|
requirements:
|
73
74
|
- - '>='
|
74
75
|
- !ruby/object:Gem::Version
|
75
|
-
segments:
|
76
|
-
- 0
|
77
76
|
version: "0"
|
78
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
79
|
requirements:
|
80
80
|
- - '>='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
segments:
|
83
|
-
- 0
|
84
82
|
version: "0"
|
85
83
|
requirements: []
|
86
84
|
rubyforge_project:
|
87
|
-
rubygems_version: 1.
|
85
|
+
rubygems_version: 1.4.2
|
88
86
|
signing_key:
|
89
87
|
specification_version: 3
|
90
88
|
summary: 'James: Modular Electronic Butler with modular Dialogues.'
|
data/lib/old/main.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# Instead of this, check for __main__.
|
2
|
-
#
|
3
|
-
|
4
|
-
require File.expand_path '../../james', __FILE__
|
5
|
-
|
6
|
-
app = NSApplication.sharedApplication
|
7
|
-
app.delegate = James::Controller.new
|
8
|
-
|
9
|
-
# window = NSWindow.alloc.initWithContentRect([200, 300, 300, 100],
|
10
|
-
# styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask,
|
11
|
-
# backing:NSBackingStoreBuffered,
|
12
|
-
# defer:false)
|
13
|
-
# window.title = 'MacRuby: The Definitive Guide'
|
14
|
-
# window.level = 3
|
15
|
-
# window.delegate = app.delegate
|
16
|
-
#
|
17
|
-
# button = NSButton.alloc.initWithFrame([80, 10, 120, 80])
|
18
|
-
# button.bezelStyle = 4
|
19
|
-
# button.title = 'Hello World!'
|
20
|
-
# button.target = app.delegate
|
21
|
-
# button.action = 'say_hello:'
|
22
|
-
#
|
23
|
-
# window.contentView.addSubview(button)
|
24
|
-
#
|
25
|
-
# window.display
|
26
|
-
# window.orderFrontRegardless
|
27
|
-
|
28
|
-
app.delegate.applicationDidFinishLaunching nil
|
29
|
-
|
30
|
-
app.run
|
data/lib/old/main_dialogue.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module James
|
2
|
-
|
3
|
-
# This is the default main dialogue.
|
4
|
-
#
|
5
|
-
# It is a proxy to the internal dialogues.
|
6
|
-
#
|
7
|
-
class MainDialogue
|
8
|
-
include Dialogue
|
9
|
-
|
10
|
-
hear 'wake up james' => :awake
|
11
|
-
|
12
|
-
# Create Protostate with block. Then, create instance instance_evaling block.
|
13
|
-
#
|
14
|
-
state :awake do
|
15
|
-
hear 'sleep james' => :sleeping
|
16
|
-
hear 'my options?' { |the_next| the_next.phrases.join ' ' }
|
17
|
-
into { "At your service" }
|
18
|
-
exit { "Right away" }
|
19
|
-
end
|
20
|
-
|
21
|
-
state :sleeping do
|
22
|
-
hear 'wake up james' => :awake
|
23
|
-
into { "Good night, Sir" }
|
24
|
-
end
|
25
|
-
|
26
|
-
# state :awake, {
|
27
|
-
# 'sleep james' => :sleeping
|
28
|
-
# # 'james, my options?' => lambda { || } # stays in this state but executes.
|
29
|
-
# }
|
30
|
-
# state :sleeping, {
|
31
|
-
# 'wake up james' => :awake
|
32
|
-
# }
|
33
|
-
# entry 'wake up james' => :awake
|
34
|
-
#
|
35
|
-
# def enter_sleeping
|
36
|
-
# "Good night, Sir"
|
37
|
-
# end
|
38
|
-
# def enter_awake
|
39
|
-
# "At your service"
|
40
|
-
# end
|
41
|
-
# def exit_awake
|
42
|
-
# "Right away"
|
43
|
-
# end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|