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 CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
3
 
4
- # james joke phonebook quote
4
+ # james joke phonebook quote # Uses just the described ones.
5
5
  # OR
6
- # james # Uses Dir.pwd
6
+ # james # Uses all it can find.
7
7
  #
8
8
 
9
9
  begin
@@ -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
- chainable # If James is awake, he offers more dialogues on this state, if there are any.
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.' => :away,
9
- "Good night, James." => :exit,
10
- ["Thank you, James.", "Thanks, James."] => :awake
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."
@@ -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
- # yaml_voices = ''
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::Audio.new self
44
+ @input = Inputs::Terminal.new self
65
45
  @input.listen
66
46
  end
67
47
  # Start speaking.
@@ -16,6 +16,10 @@ module James
16
16
  #
17
17
  module Dialogue; end
18
18
 
19
+ # We don't care about the spelling.
20
+ #
21
+ Dialog = Dialogue
22
+
19
23
  class << self
20
24
 
21
25
  def dialogue &block
@@ -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
@@ -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
 
@@ -26,6 +26,8 @@ module James
26
26
 
27
27
  # Callback method from the speech interface.
28
28
  #
29
+ # Note: Uses a MacRuby only form.
30
+ #
29
31
  def speechRecognizer sender, didRecognizeCommand: command
30
32
  heard command
31
33
  end
@@ -10,6 +10,8 @@ module James
10
10
  @controller = controller
11
11
  end
12
12
 
13
+ # Call this method if you heard something in the subclass.
14
+ #
13
15
  def heard command
14
16
  # Call dialogue.
15
17
  #
@@ -7,6 +7,7 @@ module James
7
7
  class Terminal < Base
8
8
 
9
9
  def listen
10
+ sleep 2
10
11
  loop do
11
12
  possibilities = controller.expects
12
13
  puts "Possibilities:\n #{possibilities.join("\n ")}"
@@ -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 = expand 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?(:phrases) ? state : context.state_for(state)
23
+ state.respond_to?(:id2name) ? context.state_for(state) : state
21
24
  end
22
25
 
23
26
  def __into__
@@ -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
- self.current = current.next_for phrase
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
- 'transition three' => :next_state3
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
- before(:each) do
49
- first.stub! :expects => [:a, :b]
50
- second.stub! :expects => [:c, :d, :e]
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: false
5
- segments:
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-10 00:00:00 +10:00
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.3.6
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.'
@@ -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
@@ -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