ego 0.5.0 → 0.6.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +20 -0
  3. data/.rubocop_todo.yml +36 -0
  4. data/Gemfile +2 -0
  5. data/Guardfile +9 -2
  6. data/Rakefile +5 -1
  7. data/bin/ego +2 -0
  8. data/ego.gemspec +22 -17
  9. data/lib/ego.rb +3 -1
  10. data/lib/ego/capability.rb +2 -0
  11. data/lib/ego/filesystem.rb +2 -0
  12. data/lib/ego/handler.rb +8 -2
  13. data/lib/ego/options.rb +13 -8
  14. data/lib/ego/plugin.rb +3 -1
  15. data/lib/ego/plugin_helper.rb +18 -16
  16. data/lib/ego/plugins/capabilities.rb +9 -3
  17. data/lib/ego/plugins/fallback.rb +9 -7
  18. data/lib/ego/plugins/robot_io.rb +2 -0
  19. data/lib/ego/plugins/social.rb +3 -1
  20. data/lib/ego/plugins/status.rb +2 -0
  21. data/lib/ego/plugins/system.rb +4 -2
  22. data/lib/ego/printer.rb +9 -5
  23. data/lib/ego/robot.rb +9 -6
  24. data/lib/ego/robot_error.rb +2 -0
  25. data/lib/ego/runner.rb +12 -7
  26. data/lib/ego/version.rb +3 -1
  27. data/spec/ego/acceptance/help_spec.rb +9 -0
  28. data/spec/ego/acceptance/no_args_spec.rb +9 -0
  29. data/spec/ego/acceptance/shell_spec.rb +11 -0
  30. data/spec/ego/acceptance/simple_query_spec.rb +9 -0
  31. data/spec/ego/acceptance/template_spec.rb +43 -0
  32. data/spec/ego/acceptance/usage_error_spec.rb +17 -0
  33. data/spec/ego/acceptance/version_spec.rb +9 -0
  34. data/spec/ego/capability_spec.rb +2 -0
  35. data/spec/ego/handler_spec.rb +18 -6
  36. data/spec/ego/options_spec.rb +8 -1
  37. data/spec/ego/plugin_helper_spec.rb +4 -2
  38. data/spec/ego/plugin_spec.rb +5 -4
  39. data/spec/ego/plugins/capabilities_spec.rb +4 -4
  40. data/spec/ego/plugins/fallback_spec.rb +16 -6
  41. data/spec/ego/plugins/robot_io_spec.rb +3 -3
  42. data/spec/ego/plugins/social_spec.rb +3 -3
  43. data/spec/ego/plugins/status_spec.rb +3 -3
  44. data/spec/ego/plugins/system_spec.rb +8 -8
  45. data/spec/ego/printer_spec.rb +86 -86
  46. data/spec/ego/robot_error_spec.rb +2 -0
  47. data/spec/ego/robot_spec.rb +24 -22
  48. data/spec/ego/runner_spec.rb +12 -0
  49. data/spec/spec_helper.rb +5 -48
  50. data/spec/support/aruba.rb +3 -0
  51. data/spec/support/plugin_helper.rb +64 -0
  52. metadata +71 -9
@@ -1,8 +1,8 @@
1
- require 'ego/robot'
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Ego::Robot, 'with capabilities plug-in' do
4
- subject { robot_with_plugin('capabilities') }
3
+ require 'ego/robot'
5
4
 
5
+ RSpec.describe Ego::Robot, 'with capabilities plug-in', plugin: 'capabilities' do
6
6
  describe '#understand?' do
7
7
  it 'is defined on the robot instance' do
8
8
  expect(subject.respond_to?(:understand?)).to be true
@@ -13,7 +13,7 @@ RSpec.describe Ego::Robot, 'with capabilities plug-in' do
13
13
  end
14
14
 
15
15
  it 'returns true for queries the robot can handle' do
16
- subject.on(/^zzz$/) { }
16
+ subject.on(/^zzz$/) {}
17
17
  expect(subject.understand?('zzz')).to be true
18
18
  end
19
19
  end
@@ -1,22 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ego/robot'
2
4
 
3
- RSpec.describe Ego::Robot, 'with fallback plug-in' do
4
- subject { robot_with_plugin('fallback') }
5
+ RSpec.describe Ego::Robot, 'with fallback plug-in', plugin: 'fallback' do
5
6
  let(:unhandlable_query) { 'xxx' }
7
+ let(:empty_query) { '' }
6
8
 
7
9
  it { should be_able_to 'help you write plug-ins' }
8
10
 
9
- it { should_not handle_query :unhandlable_query }
11
+ it { should_not handle_query unhandlable_query }
10
12
 
11
13
  it 'prints a hint when a query is unhandled' do
12
- expect { subject.handle('xxx') }.to output(
14
+ expect { subject.handle(unhandlable_query) }.to output(
13
15
  /^Ego\.plugin/
14
16
  ).to_stdout
15
17
  end
16
18
 
17
19
  it 'prints a hint containing the original query' do
18
- expect { subject.handle('xxx') }.to output(
19
- /xxx/
20
+ expect { subject.handle(unhandlable_query) }.to output(
21
+ Regexp.new(unhandlable_query)
22
+ ).to_stdout
23
+ end
24
+
25
+ it { should handle_query empty_query }
26
+
27
+ it 'prints a message when the query is empty' do
28
+ expect { subject.handle(empty_query) }.to output(
29
+ /^(Yes|Hello|\.\.\.)\?$/
20
30
  ).to_stdout
21
31
  end
22
32
  end
@@ -1,8 +1,8 @@
1
- require 'ego/robot'
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Ego::Robot, 'with robot_io plug-in' do
4
- subject { robot_with_plugin('robot_io') }
3
+ require 'ego/robot'
5
4
 
5
+ RSpec.describe Ego::Robot, 'with robot_io plug-in', plugin: 'robot_io' do
6
6
  it { should be_able_to 'output text to the terminal' }
7
7
 
8
8
  describe '#verbose?' do
@@ -1,8 +1,8 @@
1
- require 'ego/robot'
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Ego::Robot, 'with social plug-in' do
4
- subject { robot_with_plugin('social') }
3
+ require 'ego/robot'
5
4
 
5
+ RSpec.describe Ego::Robot, 'with social plug-in', plugin: 'social' do
6
6
  it { should be_able_to 'socialize' }
7
7
 
8
8
  it { should handle_query 'who are you' }
@@ -1,8 +1,8 @@
1
- require 'ego/robot'
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Ego::Robot, 'with status plug-in' do
4
- subject { robot_with_plugin('status') }
3
+ require 'ego/robot'
5
4
 
5
+ RSpec.describe Ego::Robot, 'with status plug-in', plugin: 'status' do
6
6
  it { should be_able_to 'report robot status' }
7
7
 
8
8
  it { should handle_query 'status' }
@@ -1,12 +1,12 @@
1
- require 'ego/robot'
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Ego::Robot, 'with system plug-in' do
4
- subject { robot_with_plugin('system') }
3
+ require 'ego/robot'
5
4
 
5
+ RSpec.describe Ego::Robot, 'with system plug-in', plugin: 'system' do
6
6
  it { should be_able_to 'execute system commands' }
7
7
 
8
8
  describe '#system' do
9
- let(:args) { ['foo', 'bar'] }
9
+ let(:args) { %w[foo bar] }
10
10
 
11
11
  before do
12
12
  allow(Kernel).to receive(:system).and_return(true)
@@ -20,7 +20,7 @@ RSpec.describe Ego::Robot, 'with system plug-in' do
20
20
 
21
21
  it 'calls Kernel.system' do
22
22
  expect(Kernel).to receive(:system).with(*args)
23
- subject.system *args
23
+ subject.system(*args)
24
24
  end
25
25
 
26
26
  it 'prints a debug message' do
@@ -28,12 +28,12 @@ RSpec.describe Ego::Robot, 'with system plug-in' do
28
28
  'Running system with arguments %s.',
29
29
  args
30
30
  )
31
- subject.system *args
31
+ subject.system(*args)
32
32
  end
33
33
 
34
34
  it 'prints nothing on success' do
35
35
  expect(subject).not_to receive(:alert)
36
- subject.system *args
36
+ subject.system(*args)
37
37
  end
38
38
 
39
39
  it 'prints an alert on error' do
@@ -42,7 +42,7 @@ RSpec.describe Ego::Robot, 'with system plug-in' do
42
42
  'Sorry, there was a problem running %s.',
43
43
  args.first
44
44
  )
45
- subject.system *args
45
+ subject.system(*args)
46
46
  end
47
47
  end
48
48
 
@@ -1,122 +1,122 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ego/printer'
2
4
 
3
- module Ego
4
- RSpec.describe Printer do
5
- let(:verbose_printer) { (Class.new { include Printer; def verbose?; true; end }).new }
6
- let(:printer) { (Class.new { include Printer }).new }
5
+ RSpec.describe Ego::Printer do
6
+ let(:verbose_printer) { (Class.new { include Ego::Printer; def verbose?; true; end }).new }
7
+ let(:printer) { (Class.new { include Ego::Printer }).new }
7
8
 
8
- before(:all) { String.disable_colorization = false }
9
- after(:all) { String.disable_colorization = true }
9
+ before(:all) { String.disable_colorization = false }
10
+ after(:all) { String.disable_colorization = true }
10
11
 
11
- describe '#puts' do
12
- it 'is callable on the module' do
13
- expect(described_class.respond_to?(:puts)).to be true
14
- end
12
+ describe '#puts' do
13
+ it 'is callable on the module' do
14
+ expect(described_class.respond_to?(:puts)).to be true
15
+ end
15
16
 
16
- it 'is private on the instance' do
17
- expect(printer.respond_to?(:puts)).to be false
18
- end
17
+ it 'is private on the instance' do
18
+ expect(printer.respond_to?(:puts)).to be false
19
+ end
19
20
 
20
- it 'prints to STDOUT' do
21
- expect { described_class.puts 'bar' }.to output("bar\n").to_stdout
22
- end
21
+ it 'prints to STDOUT' do
22
+ expect { described_class.puts 'bar' }.to output("bar\n").to_stdout
23
+ end
23
24
 
24
- it 'concatenates multiple arguments' do
25
- expect { described_class.puts 'bar', 'baz' }.to output("bar\nbaz\n").to_stdout
26
- end
25
+ it 'concatenates multiple arguments' do
26
+ expect { described_class.puts 'bar', 'baz' }.to output("bar\nbaz\n").to_stdout
27
27
  end
28
+ end
28
29
 
29
- describe '#errs' do
30
- it 'is callable on the module' do
31
- expect(described_class.respond_to?(:errs)).to be true
32
- end
30
+ describe '#errs' do
31
+ it 'is callable on the module' do
32
+ expect(described_class.respond_to?(:errs)).to be true
33
+ end
33
34
 
34
- it 'is private on the instance' do
35
- expect(printer.respond_to?(:errs)).to be false
36
- end
35
+ it 'is private on the instance' do
36
+ expect(printer.respond_to?(:errs)).to be false
37
+ end
37
38
 
38
- it 'prints to STDERR' do
39
- expect { described_class.errs 'bar' }.to output("bar\n").to_stderr
40
- end
39
+ it 'prints to STDERR' do
40
+ expect { described_class.errs 'bar' }.to output("bar\n").to_stderr
41
+ end
41
42
 
42
- it 'concatenates multiple arguments' do
43
- expect { described_class.errs 'bar', 'baz' }.to output("bar\nbaz\n").to_stderr
44
- end
43
+ it 'concatenates multiple arguments' do
44
+ expect { described_class.errs 'bar', 'baz' }.to output("bar\nbaz\n").to_stderr
45
45
  end
46
+ end
46
47
 
47
- describe '#say' do
48
- it 'is not callable on the module' do
49
- expect(described_class.respond_to?(:say)).to be false
50
- end
48
+ describe '#say' do
49
+ it 'is not callable on the module' do
50
+ expect(described_class.respond_to?(:say)).to be false
51
+ end
51
52
 
52
- it 'is callable on the instance' do
53
- expect(printer.respond_to?(:say)).to be true
54
- end
53
+ it 'is callable on the instance' do
54
+ expect(printer.respond_to?(:say)).to be true
55
+ end
55
56
 
56
- it 'prints the message to STDOUT bolded with newline' do
57
- expect { printer.say('X') }.to output("\e[1;39;49mX\e[0m\n").to_stdout
58
- end
57
+ it 'prints the message to STDOUT bolded with newline' do
58
+ expect { printer.say('X') }.to output("\e[1;39;49mX\e[0m\n").to_stdout
59
+ end
59
60
 
60
- it 'accepts placeholders and replacement strings' do
61
- expect { printer.say('Hello, %s.', 'world') }.to output("\e[1;39;49mHello, world.\e[0m\n").to_stdout
62
- end
61
+ it 'accepts placeholders and replacement strings' do
62
+ expect { printer.say('Hello, %s.', 'world') }.to output("\e[1;39;49mHello, world.\e[0m\n").to_stdout
63
63
  end
64
+ end
64
65
 
65
- describe '#emote' do
66
- it 'is not callable on the module' do
67
- expect(described_class.respond_to?(:emote)).to be false
68
- end
66
+ describe '#emote' do
67
+ it 'is not callable on the module' do
68
+ expect(described_class.respond_to?(:emote)).to be false
69
+ end
69
70
 
70
- it 'is callable on the instance' do
71
- expect(printer.respond_to?(:emote)).to be true
72
- end
71
+ it 'is callable on the instance' do
72
+ expect(printer.respond_to?(:emote)).to be true
73
+ end
73
74
 
74
- it 'prints the message to STDOUT with color and asterisks' do
75
- expect { printer.emote('FOO') }.to output("\e[0;35;49m*FOO*\e[0m\n").to_stdout
76
- end
75
+ it 'prints the message to STDOUT with color and asterisks' do
76
+ expect { printer.emote('FOO') }.to output("\e[0;35;49m*FOO*\e[0m\n").to_stdout
77
77
  end
78
+ end
78
79
 
79
- describe '#alert' do
80
- it 'is not callable on the module' do
81
- expect(described_class.respond_to?(:alert)).to be false
82
- end
80
+ describe '#alert' do
81
+ it 'is not callable on the module' do
82
+ expect(described_class.respond_to?(:alert)).to be false
83
+ end
83
84
 
84
- it 'is callable on the instance' do
85
- expect(printer.respond_to?(:alert)).to be true
86
- end
85
+ it 'is callable on the instance' do
86
+ expect(printer.respond_to?(:alert)).to be true
87
+ end
87
88
 
88
- it 'prints the message to STDERR with color and newline' do
89
- expect { printer.alert('FOO') }.to output("\e[0;91;49mFOO\e[0m\n").to_stderr
90
- end
89
+ it 'prints the message to STDERR with color and newline' do
90
+ expect { printer.alert('FOO') }.to output("\e[0;91;49mFOO\e[0m\n").to_stderr
91
+ end
91
92
 
92
- it 'accepts placeholders and replacement strings' do
93
- expect { printer.alert('Error: %s.', 'foo') }.to output("\e[0;91;49mError: foo.\e[0m\n").to_stderr
94
- end
93
+ it 'accepts placeholders and replacement strings' do
94
+ expect { printer.alert('Error: %s.', 'foo') }.to output("\e[0;91;49mError: foo.\e[0m\n").to_stderr
95
95
  end
96
+ end
96
97
 
97
- describe '#debug' do
98
- it 'is not callable on the module' do
99
- expect(described_class.respond_to?(:debug)).to be false
100
- end
98
+ describe '#debug' do
99
+ it 'is not callable on the module' do
100
+ expect(described_class.respond_to?(:debug)).to be false
101
+ end
101
102
 
102
- it 'is callable on the instance' do
103
- expect(printer.respond_to?(:debug)).to be true
104
- end
103
+ it 'is callable on the instance' do
104
+ expect(printer.respond_to?(:debug)).to be true
105
+ end
105
106
 
106
- context 'in verbose instance' do
107
- it 'prints the message to STDERR with newline' do
108
- expect { verbose_printer.debug('FOO') }.to output("FOO\n").to_stderr
109
- end
107
+ context 'in verbose instance' do
108
+ it 'prints the message to STDERR with newline' do
109
+ expect { verbose_printer.debug('FOO') }.to output("FOO\n").to_stderr
110
+ end
110
111
 
111
- it 'accepts placeholders and replacement strings' do
112
- expect { verbose_printer.debug('Hello, %s.', 'world') }.to output("Hello, world.\n").to_stderr
113
- end
112
+ it 'accepts placeholders and replacement strings' do
113
+ expect { verbose_printer.debug('Hello, %s.', 'world') }.to output("Hello, world.\n").to_stderr
114
114
  end
115
+ end
115
116
 
116
- context 'in default instance' do
117
- it 'does not print anything' do
118
- expect { printer.debug('FOO') }.not_to output.to_stderr
119
- end
117
+ context 'in default instance' do
118
+ it 'does not print anything' do
119
+ expect { printer.debug('FOO') }.not_to output.to_stderr
120
120
  end
121
121
  end
122
122
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ego/robot_error'
2
4
 
3
5
  RSpec.describe Ego::RobotError do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ego/robot'
2
4
 
3
5
  RSpec.describe Ego::Robot do
@@ -5,10 +7,10 @@ RSpec.describe Ego::Robot do
5
7
  let(:options) { double('Ego::Options') }
6
8
  let(:plugin) { double('Ego::Plugin') }
7
9
  subject do
8
- allow(options).to receive_messages({
10
+ allow(options).to receive_messages(
9
11
  robot_name: name,
10
- verbose: false,
11
- })
12
+ verbose: false
13
+ )
12
14
 
13
15
  described_class.new(options)
14
16
  end
@@ -97,7 +99,7 @@ RSpec.describe Ego::Robot do
97
99
  let(:priority) { 9 }
98
100
 
99
101
  before do
100
- subject.on(condition, priority) { }
102
+ subject.on(condition, priority) {}
101
103
  end
102
104
 
103
105
  it 'passes the condition and action to a new handler' do
@@ -114,9 +116,9 @@ RSpec.describe Ego::Robot do
114
116
  context 'given a hash' do
115
117
  before do
116
118
  subject.on(
117
- ->(q) { 'foo' } => 1,
118
- ->(q) { 'bar' } => 2,
119
- ) { }
119
+ ->(_q) { 'foo' } => 1,
120
+ ->(_q) { 'bar' } => 2
121
+ ) {}
120
122
  end
121
123
 
122
124
  it 'creates a new handler for each item' do
@@ -145,7 +147,7 @@ RSpec.describe Ego::Robot do
145
147
  end
146
148
 
147
149
  it 'executes the action in the context of the robot instance' do
148
- expect(subject.run_action(->() { name }, [])).to eq(subject.name)
150
+ expect(subject.run_action(-> { name }, [])).to eq(subject.name)
149
151
  end
150
152
  end
151
153
 
@@ -161,12 +163,12 @@ RSpec.describe Ego::Robot do
161
163
 
162
164
  it 'is run by #run_action' do
163
165
  subject.before_action { print 'Before!' }
164
- expect { subject.run_action(->(p) { true }, 'p') }.to output('Before!').to_stdout
166
+ expect { subject.run_action(->(_p) { true }, 'p') }.to output('Before!').to_stdout
165
167
  end
166
168
 
167
169
  it 'receives the action and action parameters' do
168
- subject.before_action { |action, params| print params }
169
- expect { subject.run_action(->(p) { true }, 'p') }.to output('p').to_stdout
170
+ subject.before_action { |_action, params| print params }
171
+ expect { subject.run_action(->(_p) { true }, 'p') }.to output('p').to_stdout
170
172
  end
171
173
  end
172
174
 
@@ -182,22 +184,22 @@ RSpec.describe Ego::Robot do
182
184
 
183
185
  it 'is run by #run_action' do
184
186
  subject.after_action { print 'After!' }
185
- expect { subject.run_action(->(p) { 'out' }, 'p') }.to output('After!').to_stdout
187
+ expect { subject.run_action(->(_p) { 'out' }, 'p') }.to output('After!').to_stdout
186
188
  end
187
189
 
188
190
  it 'receives the action, parameters, and return value' do
189
- subject.after_action { |action, params, result| print result + params }
190
- expect { subject.run_action(->(p) { 'out' }, 'p') }.to output('outp').to_stdout
191
+ subject.after_action { |_action, params, result| print result + params }
192
+ expect { subject.run_action(->(_p) { 'out' }, 'p') }.to output('outp').to_stdout
191
193
  end
192
194
  end
193
195
 
194
196
  describe '#first_handler_for' do
195
197
  before do
196
198
  subject.on(
197
- ->(q) { {} if 'bar'.match(q) } => 3,
198
- ->(q) { {} if 'foo'.match(q) } => 2,
199
- ->(q) { {} if 'foo'.match(q) } => 1,
200
- ) { }
199
+ ->(q) { {} if /bar/ =~ q } => 3,
200
+ ->(q) { {} if /foo/ =~ q } => 2,
201
+ ->(q) { {} if /foo/ =~ q } => 1
202
+ ) {}
201
203
  end
202
204
 
203
205
  it 'chooses the highest-priority handler that matches the query' do
@@ -212,9 +214,9 @@ RSpec.describe Ego::Robot do
212
214
  describe '#handle' do
213
215
  before do
214
216
  subject.on(
215
- ->(q) { {param: :three} if 'bar'.match(q) } => 3,
216
- ->(q) { {param: :two} if 'foo'.match(q) } => 2,
217
- ->(q) { {param: :one} if 'foo'.match(q) } => 1,
217
+ ->(q) { { param: :three } if /bar/ =~ q } => 3,
218
+ ->(q) { { param: :two } if /foo/ =~ q } => 2,
219
+ ->(q) { { param: :one } if /foo/ =~ q } => 1
218
220
  ) { |param| param }
219
221
  end
220
222
 
@@ -289,7 +291,7 @@ RSpec.describe Ego::Robot do
289
291
  end
290
292
 
291
293
  it 'is not run by #handle when the query is handled' do
292
- subject.on('xxx') { }
294
+ subject.on('xxx') {}
293
295
  expect { subject.handle('xxx') }.not_to output('Oops!').to_stdout
294
296
  end
295
297