ego 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/.yardopts +1 -0
- data/README.md +40 -35
- data/ego.gemspec +1 -0
- data/lib/ego.rb +40 -3
- data/lib/ego/capability.rb +30 -0
- data/lib/ego/filesystem.rb +58 -29
- data/lib/ego/handler.rb +62 -59
- data/lib/ego/options.rb +14 -2
- data/lib/ego/plugin.rb +58 -0
- data/lib/ego/plugins/capabilities.rb +17 -0
- data/lib/ego/plugins/fallback.rb +36 -0
- data/lib/ego/plugins/robot_io.rb +16 -0
- data/lib/ego/plugins/social.rb +19 -0
- data/lib/ego/plugins/system.rb +21 -0
- data/lib/ego/printer.rb +95 -0
- data/lib/ego/robot.rb +157 -10
- data/lib/ego/robot_error.rb +8 -0
- data/lib/ego/runner.rb +51 -20
- data/lib/ego/version.rb +2 -1
- data/spec/ego/capability_spec.rb +23 -0
- data/spec/ego/handler_spec.rb +63 -0
- data/spec/ego/options_spec.rb +23 -13
- data/spec/ego/plugin_spec.rb +68 -0
- data/spec/ego/printer_spec.rb +120 -0
- data/spec/ego/robot_error_spec.rb +12 -0
- data/spec/ego/robot_spec.rb +283 -26
- metadata +36 -10
- data/lib/ego/formatter.rb +0 -36
- data/lib/ego/handler/default.rb +0 -31
- data/lib/ego/handler/echo.rb +0 -9
- data/lib/ego/handler/greet.rb +0 -17
- data/lib/ego/handler/handlers.rb +0 -15
- data/lib/ego/handler/self.rb +0 -9
- data/lib/ego/listener.rb +0 -25
- data/spec/ego/formatter_spec.rb +0 -53
data/spec/ego/robot_spec.rb
CHANGED
@@ -1,43 +1,300 @@
|
|
1
1
|
require 'ego/robot'
|
2
2
|
|
3
3
|
RSpec.describe Ego::Robot do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
let(:name) { 'TestBot' }
|
5
|
+
let(:options) { double('Ego::Options') }
|
6
|
+
let(:plugin) { double('Ego::Plugin') }
|
7
|
+
subject do
|
8
|
+
allow(options).to receive_messages({
|
9
|
+
robot_name: name,
|
10
|
+
verbose: false,
|
11
|
+
})
|
9
12
|
|
10
|
-
|
11
|
-
expect(robot.name).to eq('foo')
|
13
|
+
described_class.new(options)
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
context 'on initization' do
|
17
|
+
it 'sets its name' do
|
18
|
+
expect(subject.name).to eq(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'exposes the passed options object' do
|
22
|
+
expect(subject.options).to be options
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has no capabilities' do
|
26
|
+
expect(subject.capabilities).to be_empty
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#on_ready' do
|
31
|
+
it 'is defined' do
|
32
|
+
expect(subject.respond_to?(:on_ready)).to be true
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can be hooked into' do
|
36
|
+
subject.on_ready { print 'Ready!' }
|
37
|
+
expect { subject.run_hook :on_ready }.to output('Ready!').to_stdout
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#on_shutdown' do
|
42
|
+
it 'is defined' do
|
43
|
+
expect(subject.respond_to?(:on_shutdown)).to be true
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'can be hooked into' do
|
47
|
+
subject.on_shutdown { print 'Bye!' }
|
48
|
+
expect { subject.run_hook :on_shutdown }.to output('Bye!').to_stdout
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#ready' do
|
53
|
+
it 'runs the on_ready hook' do
|
54
|
+
subject.on_ready { print 'Ready!' }
|
55
|
+
expect { subject.ready }.to output('Ready!').to_stdout
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'is chainable' do
|
59
|
+
expect(subject.ready).to be subject
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#shutdown' do
|
64
|
+
it 'runs the on_shutdown hook' do
|
65
|
+
subject.on_shutdown { print 'Bye!' }
|
66
|
+
expect { subject.shutdown }.to output('Bye!').to_stdout
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#provide' do
|
71
|
+
it 'is an alias for #define_singleton_method' do
|
72
|
+
expect(subject.respond_to?(:foo)).to be false
|
73
|
+
subject.provide(:foo) { :bar }
|
74
|
+
expect(subject.respond_to?(:foo)).to be true
|
75
|
+
expect(subject.foo).to eq(:bar)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#can' do
|
80
|
+
context 'without a plug-in context set' do
|
81
|
+
it 'fails' do
|
82
|
+
expect { subject.can('fail') }.to raise_error(Ego::RobotError)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with a plug-in context set' do
|
87
|
+
let(:plugin_name) { 'my_plug' }
|
88
|
+
before do
|
89
|
+
allow(plugin).to receive(:name) { plugin_name }
|
90
|
+
subject.context = plugin
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'adds a capability' do
|
94
|
+
expect(subject.capabilities).to be_empty
|
95
|
+
subject.can('succeed')
|
96
|
+
expect(subject.capabilities).not_to be_empty
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sets the capability description' do
|
100
|
+
subject.can('succeed')
|
101
|
+
expect(subject.capabilities.last.desc).to eq('succeed')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'records the plug-in with the capability' do
|
105
|
+
subject.can('succeed')
|
106
|
+
expect(subject.capabilities.last.plugin.name).to eq(plugin_name)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#on' do
|
112
|
+
context 'given a single condition' do
|
113
|
+
let(:condition) { /^some condition/i }
|
114
|
+
let(:priority) { 9 }
|
115
|
+
|
116
|
+
before do
|
117
|
+
subject.on(condition, priority) { }
|
20
118
|
end
|
21
119
|
|
22
|
-
it '
|
23
|
-
expect(
|
24
|
-
|
25
|
-
|
120
|
+
it 'passes the condition and action to a new handler' do
|
121
|
+
expect(subject.instance_variable_get(:@handlers).count).to eq(1)
|
122
|
+
expect(subject.instance_variable_get(:@handlers).last).to be_instance_of(Ego::Handler)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'passes the condition and action to a new handler with a priority' do
|
126
|
+
expect(subject.instance_variable_get(:@handlers).count).to eq(1)
|
127
|
+
expect(subject.instance_variable_get(:@handlers).last.priority).to eq(priority)
|
26
128
|
end
|
27
129
|
end
|
28
130
|
|
29
|
-
context '
|
30
|
-
before
|
31
|
-
|
32
|
-
|
33
|
-
|
131
|
+
context 'given a hash' do
|
132
|
+
before do
|
133
|
+
subject.on(
|
134
|
+
->(q) { 'foo' } => 1,
|
135
|
+
->(q) { 'bar' } => 2,
|
136
|
+
) { }
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'creates a new handler for each item' do
|
140
|
+
expect(subject.instance_variable_get(:@handlers).count).to eq(2)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'uses the keys as conditions' do
|
144
|
+
expect(subject.instance_variable_get(:@handlers).first.condition.call('')).to eq('foo')
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'uses the values as priorities' do
|
148
|
+
expect(subject.instance_variable_get(:@handlers).first.priority).to eq(1)
|
34
149
|
end
|
150
|
+
end
|
35
151
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
robot.debug 'foo'
|
152
|
+
context 'given no action block' do
|
153
|
+
it 'raises an error' do
|
154
|
+
expect { subject.on(:foo) }.to raise_error(Ego::RobotError)
|
40
155
|
end
|
41
156
|
end
|
42
157
|
end
|
158
|
+
|
159
|
+
describe '#run_action' do
|
160
|
+
it 'calls the action with supplied parameters' do
|
161
|
+
expect(subject.run_action(->(params) { params }, 'foo')).to eq('foo')
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'executes the action in the context of the robot instance' do
|
165
|
+
expect(subject.run_action(->(params) { name }, 'foo')).to eq(subject.name)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '#before_action' do
|
170
|
+
it 'is defined' do
|
171
|
+
expect(subject.respond_to?(:before_action)).to be true
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'can be hooked into' do
|
175
|
+
subject.before_action { print 'Before!' }
|
176
|
+
expect { subject.run_hook :before_action }.to output('Before!').to_stdout
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'is run by #run_action' do
|
180
|
+
subject.before_action { print 'Before!' }
|
181
|
+
expect { subject.run_action(->(p) { true }, 'p') }.to output('Before!').to_stdout
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'receives the action and action parameters' do
|
185
|
+
subject.before_action { |action, params| print params }
|
186
|
+
expect { subject.run_action(->(p) { true }, 'p') }.to output('p').to_stdout
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe '#after_action' do
|
191
|
+
it 'is defined' do
|
192
|
+
expect(subject.respond_to?(:after_action)).to be true
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'can be hooked into' do
|
196
|
+
subject.after_action { print 'After!' }
|
197
|
+
expect { subject.run_hook :after_action }.to output('After!').to_stdout
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'is run by #run_action' do
|
201
|
+
subject.after_action { print 'After!' }
|
202
|
+
expect { subject.run_action(->(p) { 'out' }, 'p') }.to output('After!').to_stdout
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'receives the action, parameters, and return value' do
|
206
|
+
subject.after_action { |action, params, result| print result + params }
|
207
|
+
expect { subject.run_action(->(p) { 'out' }, 'p') }.to output('outp').to_stdout
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#handle' do
|
212
|
+
before do
|
213
|
+
subject.on(
|
214
|
+
->(q) { :three if 'bar'.match(q) } => 3,
|
215
|
+
->(q) { :two if 'foo'.match(q) } => 2,
|
216
|
+
->(q) { :one if 'foo'.match(q) } => 1,
|
217
|
+
) { |params| params }
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'chooses the highest-priority handler that matches the query' do
|
221
|
+
expect(subject.handle('foo')).to eq(:two)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'returns false when no handlers match' do
|
225
|
+
expect(subject.handle('xxx')).to be false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe '#before_handle_query' do
|
230
|
+
it 'is defined' do
|
231
|
+
expect(subject.respond_to?(:before_handle_query)).to be true
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'can be hooked into' do
|
235
|
+
subject.before_handle_query { print 'Before!' }
|
236
|
+
expect { subject.run_hook :before_handle_query }.to output('Before!').to_stdout
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'is run by #handle' do
|
240
|
+
subject.before_handle_query { print 'Before!' }
|
241
|
+
expect { subject.handle('xxx') }.to output('Before!').to_stdout
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'receives the query' do
|
245
|
+
subject.before_handle_query { |query| print query }
|
246
|
+
expect { subject.handle('xxx') }.to output('xxx').to_stdout
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe '#after_handle_query' do
|
251
|
+
it 'is defined' do
|
252
|
+
expect(subject.respond_to?(:after_handle_query)).to be true
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'can be hooked into' do
|
256
|
+
subject.after_handle_query { print 'After!' }
|
257
|
+
expect { subject.run_hook :after_handle_query }.to output('After!').to_stdout
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'is run by #handle' do
|
261
|
+
subject.on('xxx') { true }
|
262
|
+
subject.after_handle_query { print 'After!' }
|
263
|
+
expect { subject.handle('xxx') }.to output('After!').to_stdout
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'receives the query and handler' do
|
267
|
+
subject.on('xxx') { true }
|
268
|
+
subject.after_handle_query { |query, handler| print query unless handler.nil? }
|
269
|
+
expect { subject.handle('xxx') }.to output('xxx').to_stdout
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#on_unhandled_query' do
|
274
|
+
before do
|
275
|
+
subject.on_unhandled_query { print 'Oops!' }
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'is defined' do
|
279
|
+
expect(subject.respond_to?(:on_unhandled_query)).to be true
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'can be hooked into' do
|
283
|
+
expect { subject.run_hook :on_unhandled_query }.to output('Oops!').to_stdout
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'is run by #handle when no handlers match' do
|
287
|
+
expect { subject.handle('xxx') }.to output('Oops!').to_stdout
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'is not run by #handle when the query is handled' do
|
291
|
+
subject.on('xxx') { }
|
292
|
+
expect { subject.handle('xxx') }.not_to output('Oops!').to_stdout
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'receives the query' do
|
296
|
+
subject.on_unhandled_query { |query| print query }
|
297
|
+
expect { subject.handle('xxx') }.to output('Oops!xxx').to_stdout
|
298
|
+
end
|
299
|
+
end
|
43
300
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ego
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Frederick
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.7'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: hooks
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.4'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.4'
|
83
97
|
description: |2
|
84
98
|
Ego is a personal command-line assistant that provides a flexible, natural
|
85
99
|
language interface (sort of) for interacting with other programs. Think of
|
@@ -94,6 +108,8 @@ extra_rdoc_files: []
|
|
94
108
|
files:
|
95
109
|
- ".gitignore"
|
96
110
|
- ".rspec"
|
111
|
+
- ".travis.yml"
|
112
|
+
- ".yardopts"
|
97
113
|
- Gemfile
|
98
114
|
- Guardfile
|
99
115
|
- LICENSE.txt
|
@@ -102,21 +118,27 @@ files:
|
|
102
118
|
- bin/ego
|
103
119
|
- ego.gemspec
|
104
120
|
- lib/ego.rb
|
121
|
+
- lib/ego/capability.rb
|
105
122
|
- lib/ego/filesystem.rb
|
106
|
-
- lib/ego/formatter.rb
|
107
123
|
- lib/ego/handler.rb
|
108
|
-
- lib/ego/handler/default.rb
|
109
|
-
- lib/ego/handler/echo.rb
|
110
|
-
- lib/ego/handler/greet.rb
|
111
|
-
- lib/ego/handler/handlers.rb
|
112
|
-
- lib/ego/handler/self.rb
|
113
|
-
- lib/ego/listener.rb
|
114
124
|
- lib/ego/options.rb
|
125
|
+
- lib/ego/plugin.rb
|
126
|
+
- lib/ego/plugins/capabilities.rb
|
127
|
+
- lib/ego/plugins/fallback.rb
|
128
|
+
- lib/ego/plugins/robot_io.rb
|
129
|
+
- lib/ego/plugins/social.rb
|
130
|
+
- lib/ego/plugins/system.rb
|
131
|
+
- lib/ego/printer.rb
|
115
132
|
- lib/ego/robot.rb
|
133
|
+
- lib/ego/robot_error.rb
|
116
134
|
- lib/ego/runner.rb
|
117
135
|
- lib/ego/version.rb
|
118
|
-
- spec/ego/
|
136
|
+
- spec/ego/capability_spec.rb
|
137
|
+
- spec/ego/handler_spec.rb
|
119
138
|
- spec/ego/options_spec.rb
|
139
|
+
- spec/ego/plugin_spec.rb
|
140
|
+
- spec/ego/printer_spec.rb
|
141
|
+
- spec/ego/robot_error_spec.rb
|
120
142
|
- spec/ego/robot_spec.rb
|
121
143
|
- spec/spec_helper.rb
|
122
144
|
homepage: https://github.com/noahfrederick/ego
|
@@ -144,7 +166,11 @@ signing_key:
|
|
144
166
|
specification_version: 4
|
145
167
|
summary: An extensible personal command-line assistant
|
146
168
|
test_files:
|
147
|
-
- spec/ego/
|
169
|
+
- spec/ego/capability_spec.rb
|
170
|
+
- spec/ego/handler_spec.rb
|
148
171
|
- spec/ego/options_spec.rb
|
172
|
+
- spec/ego/plugin_spec.rb
|
173
|
+
- spec/ego/printer_spec.rb
|
174
|
+
- spec/ego/robot_error_spec.rb
|
149
175
|
- spec/ego/robot_spec.rb
|
150
176
|
- spec/spec_helper.rb
|
data/lib/ego/formatter.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'colorize'
|
2
|
-
|
3
|
-
module Ego
|
4
|
-
class Formatter
|
5
|
-
def initialize
|
6
|
-
String.disable_colorization = !$stdout.isatty
|
7
|
-
end
|
8
|
-
|
9
|
-
def puts(message)
|
10
|
-
$stdout.puts message
|
11
|
-
end
|
12
|
-
|
13
|
-
def robot_respond(message, *replacements)
|
14
|
-
message = sprintf(message, *replacements)
|
15
|
-
message = message[0].upcase + message[1..-1]
|
16
|
-
|
17
|
-
$stdout.puts message.yellow
|
18
|
-
end
|
19
|
-
|
20
|
-
def robot_action(message)
|
21
|
-
$stdout.puts "*#{message}*".magenta
|
22
|
-
end
|
23
|
-
|
24
|
-
def debug(message, *replacements)
|
25
|
-
message = sprintf(message, *replacements)
|
26
|
-
|
27
|
-
$stderr.puts message
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.print_handlers(handlers)
|
31
|
-
handlers.keys.sort.each do |key|
|
32
|
-
$stdout.puts "- #{handlers[key]}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|