cora 0.0.4
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/.gitignore +4 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/Rakefile +12 -0
- data/cora.gemspec +27 -0
- data/lib/cora.rb +62 -0
- data/lib/cora/location.rb +34 -0
- data/lib/cora/plugin.rb +97 -0
- data/lib/cora/version.rb +3 -0
- data/spec/cora_spec.rb +223 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/test_plugin.rb +96 -0
- metadata +105 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
desc 'Default: run specs.'
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc "Run specs"
|
9
|
+
RSpec::Core::RakeTask.new do |t|
|
10
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
11
|
+
# Put spec opts in a file named .rspec in root
|
12
|
+
end
|
data/cora.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cora/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cora"
|
7
|
+
s.version = Cora::VERSION
|
8
|
+
s.authors = ["Jack Chen (chendo)"]
|
9
|
+
s.email = ["@chendo"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = "Example summary"
|
12
|
+
s.description = "Example description"
|
13
|
+
|
14
|
+
s.rubyforge_project = "cora"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec"
|
17
|
+
s.add_development_dependency "guard-rspec"
|
18
|
+
s.add_development_dependency "rake"
|
19
|
+
|
20
|
+
s.add_runtime_dependency "geocoder"
|
21
|
+
|
22
|
+
s.files = `git ls-files 2> /dev/null`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/* 2> /dev/null`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/* 2> /dev/null`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
data/lib/cora.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "cora/version"
|
2
|
+
require "cora/plugin"
|
3
|
+
require "cora/location"
|
4
|
+
|
5
|
+
class Cora
|
6
|
+
|
7
|
+
attr_reader :location
|
8
|
+
|
9
|
+
def plugins
|
10
|
+
@plugins ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(text)
|
14
|
+
log "Processing '#{text}'"
|
15
|
+
|
16
|
+
if @callback
|
17
|
+
log "Active callback found, resuming"
|
18
|
+
|
19
|
+
# We must set the active callback to nil first, otherwise
|
20
|
+
# multiple callbacks within one listen block won't work
|
21
|
+
callback = @callback
|
22
|
+
@callback = nil
|
23
|
+
callback.call(text)
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
|
27
|
+
plugins.each do |plugin|
|
28
|
+
log "Processing plugin #{plugin}"
|
29
|
+
return true if plugin.process(text)
|
30
|
+
end
|
31
|
+
|
32
|
+
log "No matches for '#{text}'"
|
33
|
+
no_matches
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond(text, options = {})
|
37
|
+
end
|
38
|
+
|
39
|
+
def no_matches
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_priority_plugin(plugin)
|
43
|
+
plugins.delete(plugin)
|
44
|
+
plugins.unshift(plugin)
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_callback(&block)
|
48
|
+
@callback = block
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_active_fiber(fiber)
|
52
|
+
@fiber = fiber
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_location(latitude, longitude, extra = {})
|
56
|
+
@location = Location.new(latitude, longitude, extra)
|
57
|
+
end
|
58
|
+
|
59
|
+
def log(text)
|
60
|
+
$stderr.puts(text) if defined?(LOG)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'geocoder'
|
2
|
+
|
3
|
+
class Cora::Location
|
4
|
+
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :result, :address, :city, :state, :state_code, :country, :country_code, :postal_code
|
8
|
+
|
9
|
+
attr_reader :latitude, :longitude, :extra
|
10
|
+
|
11
|
+
def initialize(latitude, longitude, extra = {})
|
12
|
+
@latitude = latitude
|
13
|
+
@longitude = longitude
|
14
|
+
@extra = extra
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns nil if geolocation failed, or an instance of Geocoder::Result::Google
|
18
|
+
# See: http://rubydoc.info/github/alexreisner/geocoder/master/Geocoder/Result/Google
|
19
|
+
def result
|
20
|
+
results.first
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns an array of objects of class Geocoder::Result::Google (probably)
|
24
|
+
def results
|
25
|
+
@results ||= perform_reverse_geocode
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def perform_reverse_geocode
|
31
|
+
Geocoder.search([latitude, longitude].join(','))
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/cora/plugin.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'fiber'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
class Cora::Plugin
|
5
|
+
|
6
|
+
# These could use some more work
|
7
|
+
CONFIRM_REGEX = /yes|yeah|yep|ok|confirm|affirmative|indeed|engage/i
|
8
|
+
DENY_REGEX = /no|nope|nah|cancel|negative/i
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegators :manager, :log, :location
|
13
|
+
|
14
|
+
attr_accessor :manager, :match_data
|
15
|
+
attr_reader :current_state
|
16
|
+
|
17
|
+
class << self
|
18
|
+
|
19
|
+
def listen_for(regex, options = {}, &block)
|
20
|
+
listeners[regex] = {
|
21
|
+
block: block,
|
22
|
+
within_state: ([options[:within_state]].flatten)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def listeners
|
27
|
+
@listeners ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def process(text)
|
33
|
+
listeners.each do |regex, entry|
|
34
|
+
if match = text.match(regex)
|
35
|
+
captures = match.captures
|
36
|
+
log "Matches #{regex}"
|
37
|
+
|
38
|
+
if entry[:within_state]
|
39
|
+
log "Applicable states: #{entry[:within_state].join(', ')}"
|
40
|
+
log "Current state: #{current_state}"
|
41
|
+
|
42
|
+
if entry[:within_state].include?(current_state)
|
43
|
+
log "Matches, executing block"
|
44
|
+
|
45
|
+
self.match_data = match
|
46
|
+
Fiber.new {
|
47
|
+
instance_exec(*captures, &entry[:block])
|
48
|
+
}.resume
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def listeners
|
59
|
+
self.class.listeners
|
60
|
+
end
|
61
|
+
|
62
|
+
def say(text, options={})
|
63
|
+
log "Say: #{text}"
|
64
|
+
manager.respond(text, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def ask(question, options={})
|
68
|
+
log "Ask: #{question}"
|
69
|
+
|
70
|
+
f = Fiber.current
|
71
|
+
options[:prompt_for_response] = true
|
72
|
+
manager.respond(question, options)
|
73
|
+
manager.set_callback do |text|
|
74
|
+
f.resume(text)
|
75
|
+
end
|
76
|
+
|
77
|
+
Fiber.yield
|
78
|
+
end
|
79
|
+
|
80
|
+
def confirm(question, options = {unmatched_message: "I'm sorry, I didn't understand that."}, &block)
|
81
|
+
while (response = ask(question))
|
82
|
+
if response.match(CONFIRM_REGEX)
|
83
|
+
return true
|
84
|
+
elsif response.match(DENY_REGEX)
|
85
|
+
return false
|
86
|
+
else
|
87
|
+
say options[:unmatched_message]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def set_state(state)
|
93
|
+
@current_state = state
|
94
|
+
manager.set_priority_plugin(self)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/lib/cora/version.rb
ADDED
data/spec/cora_spec.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_plugin'
|
3
|
+
|
4
|
+
describe Cora do
|
5
|
+
context "integration test" do
|
6
|
+
let(:plugin) do
|
7
|
+
TestPlugin.new.tap { |plugin| plugin.manager = subject }
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
subject.plugins << plugin
|
12
|
+
end
|
13
|
+
|
14
|
+
context "single state" do
|
15
|
+
it "responds to a simple test hook" do
|
16
|
+
|
17
|
+
subject.should_receive(:respond).with("test!", {})
|
18
|
+
subject.process("this is a test")
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "say" do
|
24
|
+
it "responds to a say with options" do
|
25
|
+
subject.should_receive(:respond).with("test options", {option: "option"})
|
26
|
+
subject.process("options")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "multiple state" do
|
31
|
+
it "doesn't respond to listeners that don't have the required state" do
|
32
|
+
subject.should_receive(:no_matches)
|
33
|
+
|
34
|
+
subject.process("bar")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "responds when in the correct state" do
|
38
|
+
subject.process("foo")
|
39
|
+
|
40
|
+
subject.should_receive(:respond).with("bar get", {})
|
41
|
+
subject.process("bar")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "multiple plugins" do
|
46
|
+
class TestPlugin2 < Cora::Plugin
|
47
|
+
|
48
|
+
listen_for /test/ do
|
49
|
+
say "test2"
|
50
|
+
end
|
51
|
+
|
52
|
+
listen_for /bar/ do
|
53
|
+
say "bad bar"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
before do
|
59
|
+
subject.plugins << TestPlugin2.new.tap { |plugin| plugin.manager = subject}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "processes the plugins in order" do
|
63
|
+
subject.should_receive(:respond).with("test!", {})
|
64
|
+
subject.process("test")
|
65
|
+
|
66
|
+
subject.plugins.reverse!
|
67
|
+
subject.should_receive(:respond).with("test2", {})
|
68
|
+
subject.process("test")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "when state is set, cora should ignore other plugins" do
|
72
|
+
subject.plugins.reverse! # So TestPlugin2's bar is checked first
|
73
|
+
subject.process("foo")
|
74
|
+
subject.should_receive(:respond).with("bar get", {})
|
75
|
+
subject.process("bar")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "asking" do
|
80
|
+
# Now this is interesting. On further thought, we can't do
|
81
|
+
# answer = ask("What is your name?")
|
82
|
+
# since we need to relinquish the CPU somehow. Either we use blocks,
|
83
|
+
# but since we're on 1.9, we can use Fibers. I think?
|
84
|
+
|
85
|
+
it "gets input from the user and uses it intelligently" do
|
86
|
+
subject.should_receive(:respond).with("Who should I send it to?", prompt_for_response: true)
|
87
|
+
subject.process("send message")
|
88
|
+
subject.should_receive(:respond).with("Sending message to chendo", {})
|
89
|
+
subject.process("chendo")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "can ask multiple questions" do
|
93
|
+
subject.should_receive(:respond).with("Question 1", prompt_for_response: true)
|
94
|
+
subject.process("ask multiple")
|
95
|
+
|
96
|
+
subject.should_receive(:respond).with("You said: Answer 1", {})
|
97
|
+
subject.should_receive(:respond).with("Question 2", prompt_for_response: true)
|
98
|
+
subject.process("Answer 1")
|
99
|
+
|
100
|
+
subject.should_receive(:respond).with("You said: Answer 2", {})
|
101
|
+
subject.should_receive(:respond).with("Question 3", prompt_for_response: true)
|
102
|
+
subject.process("Answer 2")
|
103
|
+
|
104
|
+
subject.should_receive(:respond).with("You said: Answer 3", {})
|
105
|
+
subject.process("Answer 3")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "can ask questions with options" do
|
109
|
+
subject.should_receive(:respond).with("Question with option", {prompt_for_response: true, option: "option"})
|
110
|
+
subject.process("ask option")
|
111
|
+
subject.process("plamoni")
|
112
|
+
|
113
|
+
random_num = rand(1000000)
|
114
|
+
subject.should_receive(:respond).with("Question with option", {prompt_for_response: true, option: random_num})
|
115
|
+
subject.process("ask option #{random_num}")
|
116
|
+
subject.process("plamoni")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "confirming" do
|
121
|
+
it "can confirm with affirmative responses" do
|
122
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
123
|
+
subject.process("confirm something")
|
124
|
+
subject.should_receive(:respond).with("Confirmed", {})
|
125
|
+
subject.process("Yes")
|
126
|
+
|
127
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
128
|
+
subject.process("confirm something")
|
129
|
+
subject.should_receive(:respond).with("Confirmed", {})
|
130
|
+
subject.process("Yeah")
|
131
|
+
|
132
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
133
|
+
subject.process("confirm something")
|
134
|
+
subject.should_receive(:respond).with("Confirmed", {})
|
135
|
+
subject.process("Yep")
|
136
|
+
|
137
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
138
|
+
subject.process("confirm something")
|
139
|
+
subject.should_receive(:respond).with("Confirmed", {})
|
140
|
+
subject.process("Yes please")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "can deny with deny responses" do
|
144
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
145
|
+
subject.process("confirm something")
|
146
|
+
subject.should_receive(:respond).with("Cancelled", {})
|
147
|
+
subject.process("No")
|
148
|
+
|
149
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
150
|
+
subject.process("confirm something")
|
151
|
+
subject.should_receive(:respond).with("Cancelled", {})
|
152
|
+
subject.process("Nah")
|
153
|
+
|
154
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
155
|
+
subject.process("confirm something")
|
156
|
+
subject.should_receive(:respond).with("Cancelled", {})
|
157
|
+
subject.process("Nope")
|
158
|
+
|
159
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
160
|
+
subject.process("confirm something")
|
161
|
+
subject.should_receive(:respond).with("Cancelled", {})
|
162
|
+
subject.process("No thanks")
|
163
|
+
end
|
164
|
+
|
165
|
+
it "can call confirm recursively" do
|
166
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
167
|
+
subject.process("nested confirm")
|
168
|
+
subject.should_receive(:respond).with("Confirmed", {})
|
169
|
+
subject.should_receive(:respond).with("What about inside itself?", prompt_for_response: true)
|
170
|
+
subject.process("Yes")
|
171
|
+
subject.should_receive(:respond).with("Confirmed2", {})
|
172
|
+
subject.process("Yes")
|
173
|
+
end
|
174
|
+
|
175
|
+
it "can call confirm sequentially" do
|
176
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true).ordered
|
177
|
+
subject.process("sequential confirm")
|
178
|
+
subject.should_receive(:respond).with("Confirmed", {}).ordered
|
179
|
+
subject.should_receive(:respond).with("And a second time?", prompt_for_response: true).ordered
|
180
|
+
subject.process("Yes")
|
181
|
+
subject.should_receive(:respond).with("Cancelled2", {}).ordered
|
182
|
+
subject.should_receive(:respond).with("And a third time?", prompt_for_response: true).ordered
|
183
|
+
subject.process("No")
|
184
|
+
subject.should_receive(:respond).with("Confirmed3", {}).ordered
|
185
|
+
subject.process("Yes")
|
186
|
+
end
|
187
|
+
|
188
|
+
it "can reprompt if given invalid answer to confirmation" do
|
189
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
190
|
+
subject.process("confirm something")
|
191
|
+
subject.should_receive(:respond).with("I'm sorry, I didn't understand that.", {}).ordered
|
192
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true).ordered
|
193
|
+
subject.should_receive(:respond).with("Confirmed", {}).ordered
|
194
|
+
# subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
195
|
+
subject.process("Lamp")
|
196
|
+
subject.process("Yes")
|
197
|
+
end
|
198
|
+
|
199
|
+
it "can reprompt with custom message if given invalid answer to confirmation" do
|
200
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
201
|
+
subject.process("confirm custom reprompt")
|
202
|
+
subject.should_receive(:respond).with("What you say!?", {}).ordered
|
203
|
+
subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true).ordered
|
204
|
+
subject.should_receive(:respond).with("Confirmed", {}).ordered
|
205
|
+
# subject.should_receive(:respond).with("Does confirm work?", prompt_for_response: true)
|
206
|
+
subject.process("Lamp")
|
207
|
+
subject.process("Yes")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "captures" do
|
212
|
+
it "passes the captures to the block" do
|
213
|
+
subject.should_receive(:respond).with("Nice to meet you, Jackie Chan", {})
|
214
|
+
subject.process("my name is Jackie Chan")
|
215
|
+
end
|
216
|
+
|
217
|
+
it "lets you access the match_data for dynamic capture count" do
|
218
|
+
subject.should_receive(:respond).with("only repeat this", {})
|
219
|
+
subject.process("only repeat this, not this")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
class TestPlugin < Cora::Plugin
|
3
|
+
|
4
|
+
listen_for /test/ do
|
5
|
+
say "test!"
|
6
|
+
end
|
7
|
+
|
8
|
+
listen_for /^options$/ do
|
9
|
+
say "test options", {option: "option"}
|
10
|
+
end
|
11
|
+
|
12
|
+
listen_for /^foo$/ do
|
13
|
+
say "foo"
|
14
|
+
set_state :waiting_for_bar
|
15
|
+
end
|
16
|
+
|
17
|
+
listen_for /send message/ do
|
18
|
+
receipent = ask "Who should I send it to?"
|
19
|
+
say "Sending message to #{receipent}"
|
20
|
+
end
|
21
|
+
|
22
|
+
listen_for /ask multiple/ do
|
23
|
+
answer = ask "Question 1"
|
24
|
+
say "You said: #{answer}"
|
25
|
+
answer = ask "Question 2"
|
26
|
+
say "You said: #{answer}"
|
27
|
+
answer = ask "Question 3"
|
28
|
+
say "You said: #{answer}"
|
29
|
+
end
|
30
|
+
|
31
|
+
listen_for /ask option[ ]?([0-9]*)/ do |numeric_option|
|
32
|
+
opt = "option"
|
33
|
+
opt = numeric_option.to_i if not numeric_option.empty?
|
34
|
+
answer = ask "Question with option", {option: opt}
|
35
|
+
end
|
36
|
+
|
37
|
+
listen_for /confirm something/ do
|
38
|
+
if confirm "Does confirm work?"
|
39
|
+
say "Confirmed"
|
40
|
+
else
|
41
|
+
say "Cancelled"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
listen_for /confirm custom reprompt/ do
|
46
|
+
if confirm "Does confirm work?", unmatched_message: "What you say!?"
|
47
|
+
say "Confirmed"
|
48
|
+
else
|
49
|
+
say "Cancelled"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
listen_for /nested confirm/ do
|
55
|
+
if confirm "Does confirm work?"
|
56
|
+
say "Confirmed"
|
57
|
+
if confirm "What about inside itself?"
|
58
|
+
say "Confirmed2"
|
59
|
+
else
|
60
|
+
say "Cancelled2"
|
61
|
+
end
|
62
|
+
else
|
63
|
+
say "Cancelled"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
listen_for /sequential confirm/ do
|
68
|
+
if confirm "Does confirm work?"
|
69
|
+
say "Confirmed"
|
70
|
+
else
|
71
|
+
say "Cancelled"
|
72
|
+
end
|
73
|
+
if confirm "And a second time?"
|
74
|
+
say "Confirmed2"
|
75
|
+
else
|
76
|
+
say "Cancelled2"
|
77
|
+
end
|
78
|
+
if confirm "And a third time?"
|
79
|
+
say "Confirmed3"
|
80
|
+
else
|
81
|
+
say "Cancelled3"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
listen_for /bar/, within_state: :waiting_for_bar do
|
86
|
+
say "bar get"
|
87
|
+
end
|
88
|
+
|
89
|
+
listen_for /my name is (\w+) (\w+)/i do |first_name, last_name|
|
90
|
+
say "Nice to meet you, #{first_name} #{last_name}"
|
91
|
+
end
|
92
|
+
|
93
|
+
listen_for /only repeat this/i do
|
94
|
+
say "#{match_data}"
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cora
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jack Chen (chendo)
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70356401591140 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70356401591140
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard-rspec
|
27
|
+
requirement: &70356401590140 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70356401590140
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &70356401588880 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70356401588880
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: geocoder
|
49
|
+
requirement: &70356401588060 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70356401588060
|
58
|
+
description: Example description
|
59
|
+
email:
|
60
|
+
- ! '@chendo'
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- .travis.yml
|
67
|
+
- Gemfile
|
68
|
+
- Guardfile
|
69
|
+
- Rakefile
|
70
|
+
- cora.gemspec
|
71
|
+
- lib/cora.rb
|
72
|
+
- lib/cora/location.rb
|
73
|
+
- lib/cora/plugin.rb
|
74
|
+
- lib/cora/version.rb
|
75
|
+
- spec/cora_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/support/test_plugin.rb
|
78
|
+
homepage: ''
|
79
|
+
licenses: []
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project: cora
|
98
|
+
rubygems_version: 1.8.10
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Example summary
|
102
|
+
test_files:
|
103
|
+
- spec/cora_spec.rb
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
- spec/support/test_plugin.rb
|