james 0.0.6-universal-darwin-10 → 0.0.7-universal-darwin-10
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.
- 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
|