james 0.0.3-universal-darwin-10 → 0.0.4-universal-darwin-10
Sign up to get free protection for your applications and to get access to all the features.
- data/aux/james/cli.rb +15 -7
- data/lib/james.rb +1 -0
- data/lib/james/builtin/core_dialogue.rb +27 -0
- data/lib/james/controller.rb +18 -12
- data/lib/james/dialogue_internals.rb +1 -1
- data/lib/james/state_api.rb +9 -0
- data/lib/james/visitor.rb +13 -4
- data/lib/james/visitors.rb +27 -2
- data/spec/aux/james/cli_spec.rb +19 -0
- data/spec/lib/james/visitor_spec.rb +25 -10
- data/spec/lib/james/visitors_spec.rb +3 -0
- metadata +4 -4
- data/lib/james/builtin/main_dialogue.rb +0 -25
- data/lib/james/main_dialogue.rb +0 -15
data/aux/james/cli.rb
CHANGED
@@ -4,18 +4,26 @@ module James
|
|
4
4
|
|
5
5
|
class CLI
|
6
6
|
|
7
|
-
def execute *
|
8
|
-
|
9
|
-
|
7
|
+
def execute *given_dialogues
|
8
|
+
dialogues = find_dialogues
|
9
|
+
dialogues.select! { |dialogue| given_dialogues.any? { |given| dialogue =~ %r{#{given}_dialog(ue)?.rb$} } } unless given_dialogues.empty?
|
10
10
|
|
11
|
-
puts "James:
|
11
|
+
puts "James: I haven't found anything to talk about (No *_dialog{ue,}.rb files found). Exiting." or exit!(1) if dialogues.empty?
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
puts "James: Using #{dialogues.join(', ')} for our conversation, Sir."
|
14
|
+
|
15
|
+
require_all dialogues
|
16
16
|
|
17
17
|
James.listen
|
18
18
|
end
|
19
|
+
def find_dialogues
|
20
|
+
Dir["**/*_dialog{,ue}.rb"]
|
21
|
+
end
|
22
|
+
def require_all dialogues
|
23
|
+
dialogues.each do |dialogue|
|
24
|
+
require File.expand_path dialogue, Dir.pwd
|
25
|
+
end
|
26
|
+
end
|
19
27
|
|
20
28
|
end
|
21
29
|
|
data/lib/james.rb
CHANGED
@@ -2,6 +2,7 @@ module James; end
|
|
2
2
|
|
3
3
|
require File.expand_path '../james/timer', __FILE__
|
4
4
|
require File.expand_path '../james/visitor', __FILE__
|
5
|
+
require File.expand_path '../james/visitors', __FILE__
|
5
6
|
require File.expand_path '../james/dialogues', __FILE__
|
6
7
|
|
7
8
|
require File.expand_path '../james/dialogue_api', __FILE__
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class CoreDialogue
|
2
|
+
|
3
|
+
include James::Dialogue
|
4
|
+
|
5
|
+
state :awake do
|
6
|
+
chainable # If James is awake, he offers more dialogues on this state, if there are any.
|
7
|
+
|
8
|
+
hear 'Leave me alone, James.' => :away,
|
9
|
+
"That's it for today, James." => :exit,
|
10
|
+
"Something else, James." => :awake
|
11
|
+
into { "Sir?" }
|
12
|
+
end
|
13
|
+
|
14
|
+
state :away do
|
15
|
+
hear 'James?' => :awake,
|
16
|
+
"That's it for today, James." => :exit
|
17
|
+
into { "Of course, Sir!" }
|
18
|
+
end
|
19
|
+
|
20
|
+
state :exit do
|
21
|
+
into do
|
22
|
+
puts "James: Exits through a side door."
|
23
|
+
Kernel.exit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/james/controller.rb
CHANGED
@@ -7,6 +7,8 @@ require File.expand_path '../inputs/terminal', __FILE__
|
|
7
7
|
require File.expand_path '../outputs/audio', __FILE__
|
8
8
|
require File.expand_path '../outputs/terminal', __FILE__
|
9
9
|
|
10
|
+
require File.expand_path '../builtin/core_dialogue', __FILE__
|
11
|
+
|
10
12
|
module James
|
11
13
|
|
12
14
|
class Controller
|
@@ -14,7 +16,9 @@ module James
|
|
14
16
|
attr_reader :visitor
|
15
17
|
|
16
18
|
def initialize
|
17
|
-
|
19
|
+
user_visitor = initialize_dialogues.visitor
|
20
|
+
system_visitor = Visitor.new CoreDialogue.new.state_for(:awake)
|
21
|
+
@visitor = Visitors.new system_visitor, user_visitor
|
18
22
|
end
|
19
23
|
|
20
24
|
def applicationDidFinishLaunching notification
|
@@ -80,29 +84,31 @@ module James
|
|
80
84
|
end
|
81
85
|
end
|
82
86
|
def expects
|
83
|
-
@visitor.expects
|
87
|
+
possibilities = @visitor.expects
|
88
|
+
puts "Possibilities:\n #{possibilities.join("\n ")}"
|
89
|
+
possibilities
|
84
90
|
end
|
85
91
|
|
86
92
|
def listen
|
87
93
|
app = NSApplication.sharedApplication
|
88
94
|
app.delegate = self
|
89
95
|
|
90
|
-
# window = NSWindow.alloc.initWithContentRect([
|
96
|
+
# window = NSWindow.alloc.initWithContentRect([100, 300, 300, 100],
|
91
97
|
# styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask,
|
92
98
|
# backing:NSBackingStoreBuffered,
|
93
99
|
# defer:false)
|
94
|
-
# window.title = '
|
100
|
+
# window.title = 'James Debug/Info'
|
95
101
|
# window.level = 3
|
96
102
|
# window.delegate = app.delegate
|
103
|
+
|
104
|
+
# @button = NSButton.alloc.initWithFrame([10, 10, 400, 10])
|
105
|
+
# @button.bezelStyle = 4
|
106
|
+
# @button.title = ''
|
107
|
+
# @button.target = app.delegate
|
108
|
+
# @button.action = 'say_hello:'
|
97
109
|
#
|
98
|
-
#
|
99
|
-
|
100
|
-
# button.title = 'Hello World!'
|
101
|
-
# button.target = app.delegate
|
102
|
-
# button.action = 'say_hello:'
|
103
|
-
#
|
104
|
-
# window.contentView.addSubview(button)
|
105
|
-
#
|
110
|
+
# window.contentView.addSubview(@button)
|
111
|
+
|
106
112
|
# window.display
|
107
113
|
# window.orderFrontRegardless
|
108
114
|
|
data/lib/james/state_api.rb
CHANGED
@@ -58,6 +58,15 @@ module James
|
|
58
58
|
@exit_block = block
|
59
59
|
end
|
60
60
|
|
61
|
+
# By default, a state is not chainable.
|
62
|
+
#
|
63
|
+
def chainable?
|
64
|
+
@chainable
|
65
|
+
end
|
66
|
+
def chainable
|
67
|
+
@chainable = true
|
68
|
+
end
|
69
|
+
|
61
70
|
# Description of self using name and transitions.
|
62
71
|
#
|
63
72
|
def to_s
|
data/lib/james/visitor.rb
CHANGED
@@ -21,13 +21,13 @@ module James
|
|
21
21
|
@current = initial
|
22
22
|
|
23
23
|
@initial = initial
|
24
|
-
@timer = timer || Timer.new
|
24
|
+
# @timer = timer || Timer.new
|
25
25
|
end
|
26
26
|
|
27
27
|
# Escapes the current state back to the initial.
|
28
28
|
#
|
29
|
-
def
|
30
|
-
timer.stop
|
29
|
+
def reset
|
30
|
+
# timer.stop
|
31
31
|
self.current = initial
|
32
32
|
end
|
33
33
|
|
@@ -53,7 +53,7 @@ module James
|
|
53
53
|
end
|
54
54
|
def hear phrase, &block
|
55
55
|
return unless hears? phrase
|
56
|
-
timer.restart
|
56
|
+
# timer.restart
|
57
57
|
exit_text = exit &block
|
58
58
|
transition phrase
|
59
59
|
check &block
|
@@ -66,6 +66,15 @@ module James
|
|
66
66
|
def expects
|
67
67
|
current.phrases
|
68
68
|
end
|
69
|
+
# Does the current state allow penetration into another dialogue?
|
70
|
+
#
|
71
|
+
def chainable?
|
72
|
+
current.chainable?
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
"#{self.class.name}(#{initial}, current: #{current})"
|
77
|
+
end
|
69
78
|
|
70
79
|
end
|
71
80
|
|
data/lib/james/visitors.rb
CHANGED
@@ -22,14 +22,39 @@ module James
|
|
22
22
|
@visitors = visitors
|
23
23
|
end
|
24
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
|
+
#
|
25
30
|
def hear phrase, &block
|
26
|
-
visitors.
|
31
|
+
enumerator = visitors.dup
|
32
|
+
|
33
|
+
while visitor = enumerator.shift
|
27
34
|
visitor.hear phrase, &block and break
|
28
35
|
end
|
36
|
+
|
37
|
+
while visitor = enumerator.shift
|
38
|
+
visitor.reset
|
39
|
+
end
|
29
40
|
end
|
30
41
|
|
42
|
+
# Enter enters the first dialogue.
|
43
|
+
#
|
44
|
+
def enter
|
45
|
+
visitors.first.enter
|
46
|
+
end
|
47
|
+
|
48
|
+
# Simply returns the sum of what phrases all dialogues expect.
|
49
|
+
#
|
50
|
+
# Stops as soon as a visitor is not in a chainable state anymore.
|
51
|
+
#
|
31
52
|
def expects
|
32
|
-
visitors.inject([])
|
53
|
+
visitors.inject([]) do |expects, visitor|
|
54
|
+
total = expects + visitor.expects
|
55
|
+
break total unless visitor.chainable?
|
56
|
+
total
|
57
|
+
end
|
33
58
|
end
|
34
59
|
|
35
60
|
end
|
@@ -0,0 +1,19 @@
|
|
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_dialogue.rb', 'test_dialog.rb', 'test/test_dialogue.rb']
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:cli) { James::CLI.new }
|
12
|
+
|
13
|
+
describe 'find_dialogues' do
|
14
|
+
it 'returns the right ones' do
|
15
|
+
cli.find_dialogues.should == ['test_dialogue.rb', 'test_dialog.rb', 'test/test_dialogue.rb']
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -8,6 +8,30 @@ describe James::Visitor do
|
|
8
8
|
let(:timer) { stub :timer }
|
9
9
|
let(:visitor) { described_class.new initial, timer }
|
10
10
|
|
11
|
+
describe 'reset' do
|
12
|
+
it 'works' do
|
13
|
+
expect { visitor.reset }.to_not raise_error
|
14
|
+
end
|
15
|
+
# it 'calls methods in order' do
|
16
|
+
# timer.should_receive(:stop).once.with
|
17
|
+
# visitor.should_receive(:current=).once.with initial
|
18
|
+
#
|
19
|
+
# visitor.reset
|
20
|
+
# end
|
21
|
+
it 'survives a functional test' do
|
22
|
+
next_state = stub :next_state
|
23
|
+
initial.stub! :next_for => next_state
|
24
|
+
|
25
|
+
visitor.current.should == initial
|
26
|
+
visitor.transition :some_phrase
|
27
|
+
visitor.current.should == next_state
|
28
|
+
|
29
|
+
visitor.reset
|
30
|
+
|
31
|
+
visitor.current.should == initial
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
11
35
|
describe 'current' do
|
12
36
|
it { visitor.current.should == initial }
|
13
37
|
end
|
@@ -62,19 +86,10 @@ describe James::Visitor do
|
|
62
86
|
end
|
63
87
|
end
|
64
88
|
|
65
|
-
describe 'escape' do
|
66
|
-
it 'calls methods in order' do
|
67
|
-
timer.should_receive(:stop).once.with
|
68
|
-
visitor.should_receive(:current=).once.with initial
|
69
|
-
|
70
|
-
visitor.escape
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
89
|
describe 'hear' do
|
75
90
|
it 'calls methods in order' do
|
76
91
|
visitor.should_receive(:hears?).once.ordered.with(:some_phrase).and_return true
|
77
|
-
timer.should_receive(:restart).once.ordered.with
|
92
|
+
# timer.should_receive(:restart).once.ordered.with
|
78
93
|
visitor.should_receive(:exit).once.ordered.with
|
79
94
|
visitor.should_receive(:transition).once.ordered.with :some_phrase
|
80
95
|
# visitor.should_receive(:check).once.ordered.with
|
@@ -15,11 +15,14 @@ describe James::Visitors do
|
|
15
15
|
second.stub! :hear => nil
|
16
16
|
end
|
17
17
|
it 'works' do
|
18
|
+
second.stub! :reset
|
19
|
+
|
18
20
|
visitors.hear 'some phrase'
|
19
21
|
end
|
20
22
|
it 'calls the second never' do
|
21
23
|
first.should_receive(:hear).once.and_return true
|
22
24
|
second.should_receive(:hear).never
|
25
|
+
second.should_receive(:reset).once
|
23
26
|
|
24
27
|
visitors.hear 'some phrase'
|
25
28
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
10
10
|
platform: universal-darwin-10
|
11
11
|
authors:
|
12
12
|
- Florian Hanke
|
@@ -42,7 +42,7 @@ executables:
|
|
42
42
|
extensions: []
|
43
43
|
extra_rdoc_files: []
|
44
44
|
files:
|
45
|
-
- lib/james/builtin/
|
45
|
+
- lib/james/builtin/core_dialogue.rb
|
46
46
|
- lib/james/controller.rb
|
47
47
|
- lib/james/dialogue_api.rb
|
48
48
|
- lib/james/dialogue_internals.rb
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- lib/james/inputs/audio.rb
|
51
51
|
- lib/james/inputs/base.rb
|
52
52
|
- lib/james/inputs/terminal.rb
|
53
|
-
- lib/james/main_dialogue.rb
|
54
53
|
- lib/james/outputs/audio.rb
|
55
54
|
- lib/james/outputs/terminal.rb
|
56
55
|
- lib/james/state_api.rb
|
@@ -90,6 +89,7 @@ signing_key:
|
|
90
89
|
specification_version: 3
|
91
90
|
summary: 'James: Modular Electronic Butler.'
|
92
91
|
test_files:
|
92
|
+
- spec/aux/james/cli_spec.rb
|
93
93
|
- spec/integration/test_dialogue_spec.rb
|
94
94
|
- spec/lib/james/controller_spec.rb
|
95
95
|
- spec/lib/james/dialogue_spec.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class Bla
|
2
|
-
|
3
|
-
include James::Dialogue
|
4
|
-
|
5
|
-
hear 'James?' => :awake
|
6
|
-
|
7
|
-
state :awake do
|
8
|
-
hear 'Leave me alone, James' => :away
|
9
|
-
into { "Sir?" }
|
10
|
-
end
|
11
|
-
|
12
|
-
state :away do
|
13
|
-
hear 'Are you there, James?' => :awake,
|
14
|
-
"That's it for today, James" => :exit
|
15
|
-
into { "Goodbye, Sir" }
|
16
|
-
end
|
17
|
-
|
18
|
-
state :exit do
|
19
|
-
into do
|
20
|
-
puts "James: Exits through a side door."
|
21
|
-
Kernel.exit
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|