ego 0.4.0 → 0.5.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 -1
- data/README.md +7 -11
- data/ego.gemspec +1 -1
- data/lib/ego.rb +6 -8
- data/lib/ego/capability.rb +5 -4
- data/lib/ego/handler.rb +7 -3
- data/lib/ego/plugin.rb +13 -5
- data/lib/ego/plugin_helper.rb +66 -0
- data/lib/ego/plugins/capabilities.rb +17 -1
- data/lib/ego/plugins/fallback.rb +9 -25
- data/lib/ego/plugins/robot_io.rb +3 -3
- data/lib/ego/plugins/social.rb +1 -1
- data/lib/ego/plugins/status.rb +19 -0
- data/lib/ego/plugins/system.rb +1 -1
- data/lib/ego/printer.rb +5 -6
- data/lib/ego/robot.rb +25 -14
- data/lib/ego/version.rb +1 -1
- data/spec/ego/capability_spec.rb +7 -3
- data/spec/ego/handler_spec.rb +21 -3
- data/spec/ego/plugin_helper_spec.rb +59 -0
- data/spec/ego/plugin_spec.rb +12 -2
- data/spec/ego/plugins/capabilities_spec.rb +73 -0
- data/spec/ego/plugins/fallback_spec.rb +22 -0
- data/spec/ego/plugins/robot_io_spec.rb +28 -0
- data/spec/ego/plugins/social_spec.rb +32 -0
- data/spec/ego/plugins/status_spec.rb +58 -0
- data/spec/ego/plugins/system_spec.rb +72 -0
- data/spec/ego/printer_spec.rb +3 -0
- data/spec/ego/robot_spec.rb +35 -34
- data/spec/ego/runner_spec.rb +55 -0
- data/spec/spec_helper.rb +47 -0
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8250ad3de4494ebfced808df3a5cb09de9707a38
|
4
|
+
data.tar.gz: 333930e6ddc866ec268016395b38061bc26aa9ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de4f362f46c4347e659330f418524a4cc3ce3f3ee0f1bdd8adcd97a63fb8257b6b61f9a34e31e9a339ba0725efc02f4faa590ef6ef1edb5f56dfd5415cc77d43
|
7
|
+
data.tar.gz: df7fadaf3e23e57fec7634623da1a2a56135ff6c9ec8e3b5b501fd87168d5aac8dc7057f3523a2aab4991772e5c77adfc1bddd580f8ccfb17ee6a0dfe14fe00a
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -36,7 +36,7 @@ looks like that responds to a query beginning with "hello...", "hi...", or
|
|
36
36
|
Ego.plugin do |robot|
|
37
37
|
robot.can 'greet you'
|
38
38
|
|
39
|
-
robot.on /^(hello|hi|hey)/i
|
39
|
+
robot.on /^(hello|hi|hey)/i do
|
40
40
|
say [
|
41
41
|
'Hello.',
|
42
42
|
'Hi.',
|
@@ -59,15 +59,11 @@ This adds a new "capability", which serves as documentation for the user and
|
|
59
59
|
answers the question "What can this plug-in do?"
|
60
60
|
|
61
61
|
```ruby
|
62
|
-
robot.on /^(hello|hi|hey)/i
|
62
|
+
robot.on /^(hello|hi|hey)/i ...
|
63
63
|
```
|
64
64
|
|
65
65
|
This is the condition that determines what queries should invoke the following
|
66
|
-
action.
|
67
|
-
Sometimes you may want to match very specific things and sometimes something
|
68
|
-
broader. To help ego respond the right way when two or more patterns match
|
69
|
-
your query, you can optionally specify a priority (higher number = higher
|
70
|
-
priority) as the second argument.
|
66
|
+
action. A regular expression is specified to match the query against.
|
71
67
|
|
72
68
|
```ruby
|
73
69
|
... do
|
@@ -83,14 +79,14 @@ This is the part that gets run when the pattern matches the query. From here
|
|
83
79
|
you can do anything you want including deferring to external programs. The
|
84
80
|
`robot` provides various methods to you to respond to the user. Usually, you'll
|
85
81
|
want to make use of part of the query inside the action. You can access named
|
86
|
-
match groups
|
82
|
+
match groups as block arguments:
|
87
83
|
|
88
84
|
```ruby
|
89
85
|
Ego.plugin do |robot|
|
90
86
|
robot.can 'repeat what you say'
|
91
87
|
|
92
|
-
robot.on /^say (?<input>.+)/i do |
|
93
|
-
say
|
88
|
+
robot.on /^say (?<input>.+)/i do |input|
|
89
|
+
say input
|
94
90
|
end
|
95
91
|
end
|
96
92
|
```
|
@@ -113,7 +109,7 @@ execute any Ruby scripts in this directory indiscriminately.
|
|
113
109
|
|
114
110
|
## License
|
115
111
|
|
116
|
-
Copyright (C) 2016-
|
112
|
+
Copyright (C) 2016-2018 Noah Frederick
|
117
113
|
|
118
114
|
This program is free software: you can redistribute it and/or modify
|
119
115
|
it under the terms of the GNU General Public License as published by
|
data/ego.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.required_ruby_version = "~> 2.
|
26
|
+
spec.required_ruby_version = "~> 2.3"
|
27
27
|
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.6"
|
29
29
|
spec.add_development_dependency "rake"
|
data/lib/ego.rb
CHANGED
@@ -20,22 +20,20 @@ module Ego
|
|
20
20
|
# Ego.plugin do |robot|
|
21
21
|
# robot.can 'repeat what you say'
|
22
22
|
#
|
23
|
-
# robot.on /^say (?<input>.+)/i do |
|
24
|
-
# say
|
23
|
+
# robot.on /^say (?<input>.+)/i do |input|
|
24
|
+
# say input
|
25
25
|
# end
|
26
26
|
# end
|
27
27
|
#
|
28
28
|
# @param name [String, nil] the plug-in name (uses plug-in file's basename if given `nil`)
|
29
|
-
# @param builtin [Boolean] whether to register as a built-in plug-in
|
30
29
|
# @param body the plug-in body
|
31
30
|
# @return [Plugin] the instantiated plug-in
|
32
31
|
#
|
33
32
|
# @see Robot
|
34
|
-
def self.plugin(name = nil,
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
33
|
+
def self.plugin(name = nil, &body)
|
34
|
+
path = caller_locations(1, 1)[0].absolute_path
|
35
|
+
name ||= File.basename(path, '.*')
|
36
|
+
builtin = path.start_with?(__dir__)
|
39
37
|
|
40
38
|
Plugin.register(name, body, builtin: builtin)
|
41
39
|
end
|
data/lib/ego/capability.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
require_relative 'plugin'
|
2
|
+
|
1
3
|
module Ego
|
2
4
|
# A capability defines functionality added to a `Robot` instance by a
|
3
5
|
# plug-in.
|
4
6
|
#
|
5
7
|
# @note New capabilities should be specified by plug-ins using the
|
6
|
-
# `
|
8
|
+
# `Robot#can` method.
|
7
9
|
#
|
8
10
|
# @example Add a capability to the robot instance
|
9
11
|
# Ego.plugin do |robot|
|
@@ -16,10 +18,9 @@ module Ego
|
|
16
18
|
attr_reader :desc, :plugin
|
17
19
|
|
18
20
|
# @param desc [String] the capability description answering "What can the robot do?"
|
19
|
-
|
20
|
-
def initialize(desc, plugin)
|
21
|
+
def initialize(desc)
|
21
22
|
@desc = desc
|
22
|
-
@plugin =
|
23
|
+
@plugin = Plugin.context
|
23
24
|
end
|
24
25
|
|
25
26
|
# @return [String] the capability description
|
data/lib/ego/handler.rb
CHANGED
@@ -3,7 +3,7 @@ require_relative 'robot_error'
|
|
3
3
|
module Ego
|
4
4
|
# Handlers map user queries to actions.
|
5
5
|
#
|
6
|
-
# @note Handlers should be registered by plug-ins using the `
|
6
|
+
# @note Handlers should be registered by plug-ins using the `Robot#on`
|
7
7
|
# method.
|
8
8
|
#
|
9
9
|
# @example Add a handler to the robot instance
|
@@ -56,9 +56,13 @@ module Ego
|
|
56
56
|
#
|
57
57
|
# @param query [String] the query to match the condition against
|
58
58
|
# @return [false] if condition doesn't match
|
59
|
-
# @return
|
59
|
+
# @return [Array] parameters to pass to the action
|
60
60
|
def handle(query)
|
61
|
-
@condition.call(query)
|
61
|
+
return false unless result = @condition.call(query)
|
62
|
+
|
63
|
+
@action.parameters.each_with_object([]) do |param, arr|
|
64
|
+
arr << result[param.pop]
|
65
|
+
end
|
62
66
|
end
|
63
67
|
|
64
68
|
protected
|
data/lib/ego/plugin.rb
CHANGED
@@ -6,6 +6,8 @@ module Ego
|
|
6
6
|
class Plugin
|
7
7
|
# Manifest of all registered plug-ins
|
8
8
|
@@plugins = {}
|
9
|
+
# Current plug-in context
|
10
|
+
@@context = nil
|
9
11
|
|
10
12
|
attr_reader :name, :body, :builtin
|
11
13
|
|
@@ -18,12 +20,12 @@ module Ego
|
|
18
20
|
@builtin = builtin
|
19
21
|
end
|
20
22
|
|
21
|
-
#
|
23
|
+
# Load all given plug-in paths
|
22
24
|
#
|
23
25
|
# @param paths [Array] absolute paths to plug-in files
|
24
26
|
# @return [void]
|
25
27
|
def self.load(paths)
|
26
|
-
paths.each { |path|
|
28
|
+
paths.each { |path| Kernel.load path }
|
27
29
|
end
|
28
30
|
|
29
31
|
# Register a new plug-in
|
@@ -46,13 +48,19 @@ module Ego
|
|
46
48
|
# @return [Object] the decorated object
|
47
49
|
def self.decorate(obj)
|
48
50
|
@@plugins.each do |name, plugin|
|
49
|
-
|
50
|
-
obj.context = plugin
|
51
|
-
end
|
51
|
+
@@context = plugin
|
52
52
|
plugin.body.call(obj)
|
53
|
+
@@context = nil
|
53
54
|
end
|
54
55
|
|
55
56
|
obj
|
56
57
|
end
|
58
|
+
|
59
|
+
# Get the currently executing plug-in.
|
60
|
+
#
|
61
|
+
# @return [Plugin] currently executing plugin
|
62
|
+
def self.context
|
63
|
+
@@context
|
64
|
+
end
|
57
65
|
end
|
58
66
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'ego/filesystem'
|
2
|
+
|
3
|
+
module Ego
|
4
|
+
# The PluginHelper assists the user in writing extensions by generating
|
5
|
+
# boilerplate code.
|
6
|
+
#
|
7
|
+
# @see Plugin
|
8
|
+
class PluginHelper
|
9
|
+
# @param query [String] example user query
|
10
|
+
# @param program_name [String] the executable name
|
11
|
+
def initialize(query:, program_name:)
|
12
|
+
@query = query
|
13
|
+
@program_name = program_name
|
14
|
+
end
|
15
|
+
|
16
|
+
# Derive a slug from the user query.
|
17
|
+
#
|
18
|
+
# @return [String] slug
|
19
|
+
def slug
|
20
|
+
@slug ||= @query
|
21
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
22
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
23
|
+
.tr('\'', '')
|
24
|
+
.gsub(/\W+/, '_')
|
25
|
+
.gsub(/__+/, '_')
|
26
|
+
.sub(/_$/, '')
|
27
|
+
.downcase
|
28
|
+
end
|
29
|
+
|
30
|
+
# Derive a plug-in path from the user query.
|
31
|
+
#
|
32
|
+
# @return [String] plug-in path
|
33
|
+
def path
|
34
|
+
@path ||= Filesystem.config("plugins/#{slug}.rb")
|
35
|
+
.sub(/^#{ENV['HOME']}/, '~')
|
36
|
+
end
|
37
|
+
|
38
|
+
# Provide a hint for initializing a new plug-in.
|
39
|
+
#
|
40
|
+
# @return [String] hint text
|
41
|
+
def hint
|
42
|
+
require 'shellwords'
|
43
|
+
@hint ||= <<~EOF
|
44
|
+
I don't understand "#{@query}".
|
45
|
+
|
46
|
+
If you would like to add this capability, start by running:
|
47
|
+
#{@program_name} #{@query.shellescape} > #{path}
|
48
|
+
EOF
|
49
|
+
end
|
50
|
+
|
51
|
+
# Provide a template for initializing a new plug-in.
|
52
|
+
#
|
53
|
+
# @return [String] template contents
|
54
|
+
def template
|
55
|
+
@template ||= <<~EOF
|
56
|
+
Ego.plugin do |robot|
|
57
|
+
robot.can 'do something new'
|
58
|
+
|
59
|
+
robot.on(/^#{@query}$/i) do |params|
|
60
|
+
alert 'Not implemented yet. Go ahead and edit #{path}.'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
EOF
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Ego.plugin
|
1
|
+
Ego.plugin do |robot|
|
2
2
|
robot.can 'list capabilities'
|
3
3
|
|
4
4
|
robot.on(
|
@@ -14,4 +14,20 @@ Ego.plugin builtin: true do |robot|
|
|
14
14
|
printf("- %s %s\n", cap.to_s, plugin)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
# Returns `true` if any registered handler can handle the given query.
|
19
|
+
#
|
20
|
+
# @param query [String] user query
|
21
|
+
# @return [Boolean] whether any handler matches the query
|
22
|
+
robot.provide :understand? do |query|
|
23
|
+
!first_handler_for(query).nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
robot.on(/^(can|do|would) you understand\s+(?<query>.+)/i => 6) do |query|
|
27
|
+
if understand?(query)
|
28
|
+
say 'Yes, I understand that.'
|
29
|
+
else
|
30
|
+
say 'No, I do not understand that.'
|
31
|
+
end
|
32
|
+
end
|
17
33
|
end
|
data/lib/ego/plugins/fallback.rb
CHANGED
@@ -1,36 +1,20 @@
|
|
1
|
-
Ego.plugin
|
2
|
-
robot.can 'help you write
|
1
|
+
Ego.plugin do |robot|
|
2
|
+
robot.can 'help you write plug-ins'
|
3
3
|
|
4
4
|
robot.on_unhandled_query do |query|
|
5
|
-
|
6
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
7
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
8
|
-
.tr('\'', '')
|
9
|
-
.gsub(/\W+/, '_')
|
10
|
-
.gsub(/__+/, '_')
|
11
|
-
.downcase
|
5
|
+
require 'ego/plugin_helper'
|
12
6
|
|
13
|
-
|
14
|
-
|
7
|
+
helper = Ego::PluginHelper.new(
|
8
|
+
query: query,
|
9
|
+
program_name: options.usage.program_name
|
10
|
+
)
|
15
11
|
|
16
12
|
if $stdout.isatty
|
17
|
-
|
18
|
-
alert %q(I don't understand "%s".), query
|
19
|
-
alert ''
|
20
|
-
alert 'If you would like to add this capability, start by running:'
|
21
|
-
alert ' %s %s > %s', $PROGRAM_NAME, query.shellescape, plugin_path
|
13
|
+
alert helper.hint
|
22
14
|
end
|
23
15
|
|
24
16
|
if verbose? || !$stdout.isatty
|
25
|
-
puts
|
26
|
-
Ego.plugin do |robot|
|
27
|
-
robot.can 'do something new'
|
28
|
-
|
29
|
-
robot.on(/^#{query}$/i) do |params|
|
30
|
-
alert 'Not implemented yet. Go ahead and edit #{plugin_path}.'
|
31
|
-
end
|
32
|
-
end
|
33
|
-
EOF
|
17
|
+
puts helper.template
|
34
18
|
end
|
35
19
|
end
|
36
20
|
end
|
data/lib/ego/plugins/robot_io.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Ego.plugin
|
1
|
+
Ego.plugin do |robot|
|
2
2
|
robot.can 'output text to the terminal'
|
3
3
|
|
4
4
|
# Provide #say, #emote, #alert, and #debug
|
@@ -10,7 +10,7 @@ Ego.plugin builtin: true do |robot|
|
|
10
10
|
end
|
11
11
|
|
12
12
|
robot.can 'repeat what you say'
|
13
|
-
robot.on(/^(?:say|echo)\s+(?<input>.+)/i) do |
|
14
|
-
say
|
13
|
+
robot.on(/^(?:say|echo)\s+(?<input>.+)/i) do |input|
|
14
|
+
say input
|
15
15
|
end
|
16
16
|
end
|
data/lib/ego/plugins/social.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
Ego.plugin do |robot|
|
2
|
+
robot.can 'report robot status'
|
3
|
+
|
4
|
+
robot.define_hook :on_status
|
5
|
+
|
6
|
+
robot.on_ready do
|
7
|
+
@startup_time = Time.now
|
8
|
+
end
|
9
|
+
|
10
|
+
robot.on_status do
|
11
|
+
printf "uptime: %i seconds\n", Time.now - @startup_time
|
12
|
+
printf "verbosity: %s\n", (verbose? ? 'verbose' : 'normal')
|
13
|
+
end
|
14
|
+
|
15
|
+
robot.on(/(status|diagnostic|uptime)/i => 1) do
|
16
|
+
emote 'running self-diagnostics'
|
17
|
+
run_hook :on_status
|
18
|
+
end
|
19
|
+
end
|
data/lib/ego/plugins/system.rb
CHANGED
data/lib/ego/printer.rb
CHANGED
@@ -21,7 +21,7 @@ module Ego
|
|
21
21
|
|
22
22
|
# Write stylized message to `$stdout` indicating an emote.
|
23
23
|
#
|
24
|
-
# Plug-ins may use this method to
|
24
|
+
# Plug-ins may use this method to indicate what the robot is doing.
|
25
25
|
#
|
26
26
|
# @example
|
27
27
|
# robot.emote 'runs away'
|
@@ -48,16 +48,15 @@ module Ego
|
|
48
48
|
errs sprintf(message, *replacements).light_red
|
49
49
|
end
|
50
50
|
|
51
|
-
# Write stylized message to `$stderr` indicating a debugging message
|
52
|
-
# message.
|
51
|
+
# Write stylized message to `$stderr` indicating a debugging message.
|
53
52
|
#
|
54
53
|
# Plug-ins may use this method to provide extra information when the
|
55
54
|
# `--verbose` flag is supplied at the command-line.
|
56
55
|
#
|
57
56
|
# @example
|
58
|
-
#
|
59
|
-
# robot.
|
60
|
-
# # => "
|
57
|
+
# result = 'output'
|
58
|
+
# robot.debug 'Result: %s.', result
|
59
|
+
# # => "Result: output"
|
61
60
|
#
|
62
61
|
# @param message [Object] message to write
|
63
62
|
# @param *replacements [Object, ...] `printf`-style replacements
|
data/lib/ego/robot.rb
CHANGED
@@ -16,8 +16,6 @@ module Ego
|
|
16
16
|
include Hooks::InstanceHooks
|
17
17
|
|
18
18
|
attr_reader :name, :options, :capabilities
|
19
|
-
# Set/get currently executing plug-in
|
20
|
-
attr_accessor :context
|
21
19
|
|
22
20
|
alias_method :provide, :define_singleton_method
|
23
21
|
|
@@ -31,7 +29,6 @@ module Ego
|
|
31
29
|
def initialize(options)
|
32
30
|
@name = options.robot_name
|
33
31
|
@options = options
|
34
|
-
@context = nil
|
35
32
|
@capabilities = []
|
36
33
|
@handlers = []
|
37
34
|
end
|
@@ -70,10 +67,7 @@ module Ego
|
|
70
67
|
#
|
71
68
|
# @see Capability
|
72
69
|
def can(desc)
|
73
|
-
|
74
|
-
raise RobotError, 'Cannot add capability outside of plug-in context'
|
75
|
-
end
|
76
|
-
@capabilities << Capability.new(desc, @context)
|
70
|
+
@capabilities << Capability.new(desc)
|
77
71
|
end
|
78
72
|
|
79
73
|
# Register a new query handler.
|
@@ -136,13 +130,14 @@ module Ego
|
|
136
130
|
# @return result of the action
|
137
131
|
def run_action(action, params)
|
138
132
|
run_hook :before_action, action, params
|
139
|
-
result = instance_exec(params, &action)
|
133
|
+
result = instance_exec(*params, &action)
|
140
134
|
run_hook :after_action, action, params, result
|
141
135
|
result
|
142
136
|
end
|
143
137
|
|
144
|
-
#
|
145
|
-
#
|
138
|
+
# Run the action for the highest-priority handler that can handle the given
|
139
|
+
# query and return the result. Associated hooks are run before and after
|
140
|
+
# running the action.
|
146
141
|
#
|
147
142
|
# @hook before_handle_query
|
148
143
|
# @hook after_handle_query
|
@@ -156,16 +151,32 @@ module Ego
|
|
156
151
|
def handle(query)
|
157
152
|
run_hook :before_handle_query, query
|
158
153
|
|
159
|
-
|
160
|
-
|
161
|
-
result = run_action(handler.action, params)
|
154
|
+
first_handler_for(query) do |handler, params|
|
155
|
+
return run_action(handler.action, params).tap do |result|
|
162
156
|
run_hook :after_handle_query, query, handler
|
163
|
-
return result
|
164
157
|
end
|
165
158
|
end
|
166
159
|
|
167
160
|
run_hook :on_unhandled_query, query
|
168
161
|
false
|
169
162
|
end
|
163
|
+
|
164
|
+
# Find the highest-priority handler for a given query and return it. When a
|
165
|
+
# block is passed, the block is called if and only if a handler is found,
|
166
|
+
# passing the handler and parsed params as the block's arguments.
|
167
|
+
#
|
168
|
+
# @param query [String] user query
|
169
|
+
# @return [nil] if no handler can handle query
|
170
|
+
# @return [Handler] the first matching handler
|
171
|
+
def first_handler_for(query)
|
172
|
+
@handlers.sort.reverse_each do |handler|
|
173
|
+
if params = handler.handle(query)
|
174
|
+
yield(handler, params) if block_given?
|
175
|
+
return handler
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
nil
|
180
|
+
end
|
170
181
|
end
|
171
182
|
end
|
data/lib/ego/version.rb
CHANGED
data/spec/ego/capability_spec.rb
CHANGED
@@ -3,20 +3,24 @@ require 'ego/capability'
|
|
3
3
|
RSpec.describe Ego::Capability do
|
4
4
|
let(:desc) { 'my desc' }
|
5
5
|
let(:plugin) { double('Ego::Plugin') }
|
6
|
-
subject { described_class.new(desc, plugin) }
|
7
6
|
|
8
|
-
|
7
|
+
describe '#initialize' do
|
9
8
|
it 'sets its description' do
|
9
|
+
allow(Ego::Plugin).to receive(:context) { plugin }
|
10
|
+
subject = described_class.new(desc)
|
10
11
|
expect(subject.desc).to eq(desc)
|
11
12
|
end
|
12
13
|
|
13
|
-
it 'sets
|
14
|
+
it 'sets the plug-in context' do
|
15
|
+
allow(Ego::Plugin).to receive(:context) { plugin }
|
16
|
+
subject = described_class.new(desc)
|
14
17
|
expect(subject.plugin).to be plugin
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
describe '#to_s' do
|
19
22
|
it 'returns the description' do
|
23
|
+
subject = described_class.new(desc)
|
20
24
|
expect(subject.to_s).to eq(desc)
|
21
25
|
end
|
22
26
|
end
|
data/spec/ego/handler_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'ego/handler'
|
2
2
|
|
3
3
|
RSpec.describe Ego::Handler do
|
4
|
-
let(:condition) { ->(q) { 'bar' if q == 'foo' } }
|
4
|
+
let(:condition) { ->(q) { {p: 'bar', q: 'baz'} if q == 'foo' } }
|
5
5
|
let(:regexp) { /^baz/i }
|
6
6
|
let(:action) { ->(p) { puts p } }
|
7
7
|
let(:priority) { 2 }
|
@@ -55,8 +55,26 @@ RSpec.describe Ego::Handler do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
context 'when the query can be handled' do
|
58
|
-
it 'returns
|
59
|
-
expect(subject.handle('foo')).to
|
58
|
+
it 'returns an array of parameters' do
|
59
|
+
expect(subject.handle('foo')).to be_a Array
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns parameters specified as action arguments' do
|
63
|
+
expect(subject.handle('foo')).to include('bar')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'does not return parameters not specified as action arguments' do
|
67
|
+
expect(subject.handle('foo')).not_to include('baz')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'respects the order of action arguments' do
|
71
|
+
subject = described_class.new(condition, ->(q, p) { }, priority)
|
72
|
+
expect(subject.handle('foo')).to eq(['baz', 'bar'])
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'gracefully handles extra action arguments' do
|
76
|
+
subject = described_class.new(condition, ->(p, q, r) { }, priority)
|
77
|
+
expect { subject.handle('foo') }.not_to raise_error
|
60
78
|
end
|
61
79
|
end
|
62
80
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'ego/plugin_helper'
|
2
|
+
|
3
|
+
RSpec.describe Ego::PluginHelper do
|
4
|
+
let(:query) { 'Do something new!' }
|
5
|
+
let(:program_name) { 'ego' }
|
6
|
+
subject { described_class.new(query: query, program_name: program_name) }
|
7
|
+
|
8
|
+
describe '#slug' do
|
9
|
+
it 'slugifies the query' do
|
10
|
+
expect(subject.slug).to eq('do_something_new')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#path' do
|
15
|
+
it 'returns a path to the plugins directory' do
|
16
|
+
expect(subject.path).to match(/\/plugins\//)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'uses a tilde for the home directory' do
|
20
|
+
expect(subject.path).to match(/^~\//)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'names the file after the slug' do
|
24
|
+
expect(subject.path).to match(subject.slug)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'appends an extension' do
|
28
|
+
expect(subject.path).to match(/\.rb$/)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#hint' do
|
33
|
+
it 'contains the original query' do
|
34
|
+
expect(subject.hint).to match(query)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'contains the program name followed by the shell-escaped query' do
|
38
|
+
expect(subject.hint).to match(/ego Do\\ something\\ new\\! > /)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'contains the suggested plug-in path' do
|
42
|
+
expect(subject.hint).to match(subject.path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#template' do
|
47
|
+
it 'contains ruby code to bootstrap a new plug-in' do
|
48
|
+
expect(subject.template).to match(/^Ego\.plugin do \|robot\|/)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'contains the original query as a regex' do
|
52
|
+
expect(subject.template).to match(query)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'suggests editing the plug-in path' do
|
56
|
+
expect(subject.template).to match("edit #{subject.path}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/spec/ego/plugin_spec.rb
CHANGED
@@ -38,6 +38,7 @@ RSpec.describe Ego::Plugin do
|
|
38
38
|
|
39
39
|
before do
|
40
40
|
described_class.class_variable_set :@@plugins, {}
|
41
|
+
described_class.class_variable_set :@@context, nil
|
41
42
|
described_class.register('a', proc { |obj|
|
42
43
|
obj.a = 'foo'
|
43
44
|
})
|
@@ -46,9 +47,18 @@ RSpec.describe Ego::Plugin do
|
|
46
47
|
})
|
47
48
|
end
|
48
49
|
|
49
|
-
it 'sets
|
50
|
-
|
50
|
+
it 'sets self.context to each registered plugin' do
|
51
|
+
described_class.register('c', proc { |obj|
|
52
|
+
obj.context = described_class.context
|
53
|
+
})
|
54
|
+
described_class.decorate(obj)
|
55
|
+
expect(obj.context).to be_instance_of(described_class)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sets resets self.context to nil' do
|
59
|
+
expect(described_class.context).to be_nil
|
51
60
|
described_class.decorate(obj)
|
61
|
+
expect(described_class.context).to be_nil
|
52
62
|
end
|
53
63
|
|
54
64
|
it 'calls each plugin body passing the obj' do
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with capabilities plug-in' do
|
4
|
+
subject { robot_with_plugin('capabilities') }
|
5
|
+
|
6
|
+
describe '#understand?' do
|
7
|
+
it 'is defined on the robot instance' do
|
8
|
+
expect(subject.respond_to?(:understand?)).to be true
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns false for queries the robot cannot handle' do
|
12
|
+
expect(subject.understand?('xxx')).to be false
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns true for queries the robot can handle' do
|
16
|
+
subject.on(/^zzz$/) { }
|
17
|
+
expect(subject.understand?('zzz')).to be true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it { should be_able_to 'list capabilities' }
|
22
|
+
|
23
|
+
it { should handle_query 'list what you can do' }
|
24
|
+
it { should handle_query 'list handlers' }
|
25
|
+
it { should handle_query 'show me handlers' }
|
26
|
+
it { should handle_query 'show me what you can do' }
|
27
|
+
it { should handle_query 'show me what queries you understand' }
|
28
|
+
it { should handle_query 'show me what queries you can understand' }
|
29
|
+
it { should handle_query 'tell me what you can do' }
|
30
|
+
it { should handle_query 'tell me what you are able to do' }
|
31
|
+
it { should handle_query 'tell me what you can understand' }
|
32
|
+
it { should handle_query 'tell me what queries you can understand' }
|
33
|
+
it { should handle_query 'help' }
|
34
|
+
it { should handle_query 'help me' }
|
35
|
+
it { should handle_query 'what can you do' }
|
36
|
+
it { should handle_query 'what can you understand' }
|
37
|
+
it { should handle_query 'what are you able to do' }
|
38
|
+
it { should handle_query 'what do you do' }
|
39
|
+
it { should handle_query 'what do you understand' }
|
40
|
+
it { should handle_query 'what are you able to handle' }
|
41
|
+
|
42
|
+
it 'prints list of capabilities' do
|
43
|
+
expect { subject.handle('help') }.to output(
|
44
|
+
<<~OUT
|
45
|
+
I can...
|
46
|
+
- list capabilities (capabilities*)
|
47
|
+
OUT
|
48
|
+
).to_stdout
|
49
|
+
end
|
50
|
+
|
51
|
+
it { should handle_query 'can you understand x' }
|
52
|
+
it { should handle_query 'can you understand x?' }
|
53
|
+
it { should handle_query 'do you understand x' }
|
54
|
+
it { should handle_query 'would you understand x' }
|
55
|
+
it { should_not handle_query 'do you understand' }
|
56
|
+
it { should_not handle_query 'do you understand?' }
|
57
|
+
|
58
|
+
it 'prints a message when it can understand' do
|
59
|
+
expect { subject.handle('do you understand can you understand x') }.to output(
|
60
|
+
<<~OUT
|
61
|
+
Yes, I understand that.
|
62
|
+
OUT
|
63
|
+
).to_stdout
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'prints a message when it can not understand' do
|
67
|
+
expect { subject.handle('do you understand xxx') }.to output(
|
68
|
+
<<~OUT
|
69
|
+
No, I do not understand that.
|
70
|
+
OUT
|
71
|
+
).to_stdout
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with fallback plug-in' do
|
4
|
+
subject { robot_with_plugin('fallback') }
|
5
|
+
let(:unhandlable_query) { 'xxx' }
|
6
|
+
|
7
|
+
it { should be_able_to 'help you write plug-ins' }
|
8
|
+
|
9
|
+
it { should_not handle_query :unhandlable_query }
|
10
|
+
|
11
|
+
it 'prints a hint when a query is unhandled' do
|
12
|
+
expect { subject.handle('xxx') }.to output(
|
13
|
+
/^Ego\.plugin/
|
14
|
+
).to_stdout
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'prints a hint containing the original query' do
|
18
|
+
expect { subject.handle('xxx') }.to output(
|
19
|
+
/xxx/
|
20
|
+
).to_stdout
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with robot_io plug-in' do
|
4
|
+
subject { robot_with_plugin('robot_io') }
|
5
|
+
|
6
|
+
it { should be_able_to 'output text to the terminal' }
|
7
|
+
|
8
|
+
describe '#verbose?' do
|
9
|
+
it 'is defined on the robot instance' do
|
10
|
+
expect(subject.respond_to?(:verbose?)).to be true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it { should be_able_to 'repeat what you say' }
|
15
|
+
|
16
|
+
it { should handle_query 'say hello' }
|
17
|
+
it { should handle_query 'echo hello' }
|
18
|
+
it { should_not handle_query 'whatever you say' }
|
19
|
+
it { should_not handle_query 'there is an echo in here' }
|
20
|
+
|
21
|
+
it 'prints the input' do
|
22
|
+
expect { subject.handle('say hello, robot') }.to output(
|
23
|
+
<<~OUT
|
24
|
+
hello, robot
|
25
|
+
OUT
|
26
|
+
).to_stdout
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with social plug-in' do
|
4
|
+
subject { robot_with_plugin('social') }
|
5
|
+
|
6
|
+
it { should be_able_to 'socialize' }
|
7
|
+
|
8
|
+
it { should handle_query 'who are you' }
|
9
|
+
it { should handle_query 'what are you' }
|
10
|
+
it { should handle_query 'what is your name' }
|
11
|
+
it { should handle_query 'what\'s your name' }
|
12
|
+
|
13
|
+
it 'prints its name' do
|
14
|
+
expect { subject.handle('who are you') }.to output(
|
15
|
+
/^(I'm TestBot|This is TestBot, a robot)\./
|
16
|
+
).to_stdout
|
17
|
+
end
|
18
|
+
|
19
|
+
it { should handle_query 'hello' }
|
20
|
+
it { should handle_query 'salve' }
|
21
|
+
it { should handle_query 'ave' }
|
22
|
+
it { should handle_query 'hi' }
|
23
|
+
it { should handle_query 'hey' }
|
24
|
+
it { should handle_query 'ciao' }
|
25
|
+
it { should handle_query 'hej' }
|
26
|
+
|
27
|
+
it 'greets you' do
|
28
|
+
expect { subject.handle('hello') }.to output(
|
29
|
+
/^[[:upper:]].+\./
|
30
|
+
).to_stdout
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with status plug-in' do
|
4
|
+
subject { robot_with_plugin('status') }
|
5
|
+
|
6
|
+
it { should be_able_to 'report robot status' }
|
7
|
+
|
8
|
+
it { should handle_query 'status' }
|
9
|
+
it { should handle_query 'what is your status' }
|
10
|
+
it { should handle_query 'diagnostic' }
|
11
|
+
it { should handle_query 'diagnostics' }
|
12
|
+
it { should handle_query 'do self-diagnostic' }
|
13
|
+
it { should handle_query 'uptime' }
|
14
|
+
it { should handle_query 'what is your uptime' }
|
15
|
+
|
16
|
+
describe '#on_status' do
|
17
|
+
it 'is defined' do
|
18
|
+
expect(subject.respond_to?(:on_status)).to be true
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can be hooked into' do
|
22
|
+
subject.on_status { print '--status--' }
|
23
|
+
expect { subject.run_hook :on_status }.to output(/--status--/).to_stdout
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'handler' do
|
28
|
+
it 'runs the on_status hook' do
|
29
|
+
allow(subject).to receive(:puts)
|
30
|
+
allow(subject).to receive(:run_hook)
|
31
|
+
|
32
|
+
expect(subject).to receive(:run_hook).with(:on_status)
|
33
|
+
subject.handle('status')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'prints an emote' do
|
37
|
+
allow(subject).to receive(:run_hook)
|
38
|
+
|
39
|
+
expect { subject.handle('status') }.to output(
|
40
|
+
<<~OUT
|
41
|
+
*running self-diagnostics*
|
42
|
+
OUT
|
43
|
+
).to_stdout
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'prints robot uptime' do
|
47
|
+
expect { subject.handle('status') }.to output(
|
48
|
+
/uptime: \d+ seconds\n/
|
49
|
+
).to_stdout
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'prints robot verbosity' do
|
53
|
+
expect { subject.handle('status') }.to output(
|
54
|
+
/verbosity: (normal|verbose)\n/
|
55
|
+
).to_stdout
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'ego/robot'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Robot, 'with system plug-in' do
|
4
|
+
subject { robot_with_plugin('system') }
|
5
|
+
|
6
|
+
it { should be_able_to 'execute system commands' }
|
7
|
+
|
8
|
+
describe '#system' do
|
9
|
+
let(:args) { ['foo', 'bar'] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(Kernel).to receive(:system).and_return(true)
|
13
|
+
allow(subject).to receive(:debug)
|
14
|
+
allow(subject).to receive(:alert)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is defined' do
|
18
|
+
expect(subject.respond_to?(:system)).to be true
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'calls Kernel.system' do
|
22
|
+
expect(Kernel).to receive(:system).with(*args)
|
23
|
+
subject.system *args
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'prints a debug message' do
|
27
|
+
expect(subject).to receive(:debug).with(
|
28
|
+
'Running system with arguments %s.',
|
29
|
+
args
|
30
|
+
)
|
31
|
+
subject.system *args
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'prints nothing on success' do
|
35
|
+
expect(subject).not_to receive(:alert)
|
36
|
+
subject.system *args
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'prints an alert on error' do
|
40
|
+
allow(Kernel).to receive(:system).with(*args).and_return(false)
|
41
|
+
expect(subject).to receive(:alert).with(
|
42
|
+
'Sorry, there was a problem running %s.',
|
43
|
+
args.first
|
44
|
+
)
|
45
|
+
subject.system *args
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it { should be_able_to 'tell you your login name' }
|
50
|
+
|
51
|
+
it { should handle_query 'what is my name' }
|
52
|
+
it { should handle_query 'what is my user name' }
|
53
|
+
it { should handle_query 'what is my username' }
|
54
|
+
it { should handle_query 'what is my login name' }
|
55
|
+
it { should handle_query 'what\'s my name' }
|
56
|
+
it { should handle_query 'what\'s my user name' }
|
57
|
+
it { should handle_query 'what\'s my username' }
|
58
|
+
it { should handle_query 'what\'s my login name' }
|
59
|
+
it { should handle_query 'who am I' }
|
60
|
+
it { should handle_query 'who am I logged in as' }
|
61
|
+
it { should_not handle_query 'what is your name' }
|
62
|
+
it { should_not handle_query 'who are you' }
|
63
|
+
|
64
|
+
it 'tells you your login name' do
|
65
|
+
expect(subject).to receive(:system).with('who').and_return(true)
|
66
|
+
expect { subject.handle('who am I') }.to output(
|
67
|
+
<<~OUT
|
68
|
+
You are currently logged in as:
|
69
|
+
OUT
|
70
|
+
).to_stdout
|
71
|
+
end
|
72
|
+
end
|
data/spec/ego/printer_spec.rb
CHANGED
@@ -5,6 +5,9 @@ module Ego
|
|
5
5
|
let(:verbose_printer) { (Class.new { include Printer; def verbose?; true; end }).new }
|
6
6
|
let(:printer) { (Class.new { include Printer }).new }
|
7
7
|
|
8
|
+
before(:all) { String.disable_colorization = false }
|
9
|
+
after(:all) { String.disable_colorization = true }
|
10
|
+
|
8
11
|
describe '#puts' do
|
9
12
|
it 'is callable on the module' do
|
10
13
|
expect(described_class.respond_to?(:puts)).to be true
|
data/spec/ego/robot_spec.rb
CHANGED
@@ -77,34 +77,17 @@ RSpec.describe Ego::Robot do
|
|
77
77
|
end
|
78
78
|
|
79
79
|
describe '#can' do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
it 'adds a capability' do
|
81
|
+
expect(subject.capabilities).to be_empty
|
82
|
+
subject.can('do A')
|
83
|
+
expect(subject.capabilities.count).to eq(1)
|
84
|
+
subject.can('do B')
|
85
|
+
expect(subject.capabilities.count).to eq(2)
|
84
86
|
end
|
85
87
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
88
|
+
it 'sets the capability description' do
|
89
|
+
subject.can('succeed')
|
90
|
+
expect(subject.capabilities.last.desc).to eq('succeed')
|
108
91
|
end
|
109
92
|
end
|
110
93
|
|
@@ -158,11 +141,11 @@ RSpec.describe Ego::Robot do
|
|
158
141
|
|
159
142
|
describe '#run_action' do
|
160
143
|
it 'calls the action with supplied parameters' do
|
161
|
-
expect(subject.run_action(->(params) { params }, 'foo')).to eq('foo')
|
144
|
+
expect(subject.run_action(->(params) { params }, ['foo'])).to eq('foo')
|
162
145
|
end
|
163
146
|
|
164
147
|
it 'executes the action in the context of the robot instance' do
|
165
|
-
expect(subject.run_action(->(
|
148
|
+
expect(subject.run_action(->() { name }, [])).to eq(subject.name)
|
166
149
|
end
|
167
150
|
end
|
168
151
|
|
@@ -208,20 +191,38 @@ RSpec.describe Ego::Robot do
|
|
208
191
|
end
|
209
192
|
end
|
210
193
|
|
211
|
-
describe '#
|
194
|
+
describe '#first_handler_for' do
|
212
195
|
before do
|
213
196
|
subject.on(
|
214
|
-
->(q) {
|
215
|
-
->(q) {
|
216
|
-
->(q) {
|
217
|
-
) {
|
197
|
+
->(q) { {} if 'bar'.match(q) } => 3,
|
198
|
+
->(q) { {} if 'foo'.match(q) } => 2,
|
199
|
+
->(q) { {} if 'foo'.match(q) } => 1,
|
200
|
+
) { }
|
218
201
|
end
|
219
202
|
|
220
203
|
it 'chooses the highest-priority handler that matches the query' do
|
204
|
+
expect(subject.first_handler_for('foo').priority).to eq(2)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'returns nil when no handlers match' do
|
208
|
+
expect(subject.first_handler_for('xxx')).to be_nil
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#handle' do
|
213
|
+
before do
|
214
|
+
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,
|
218
|
+
) { |param| param }
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'returns the result of the action' do
|
221
222
|
expect(subject.handle('foo')).to eq(:two)
|
222
223
|
end
|
223
224
|
|
224
|
-
it 'returns false when
|
225
|
+
it 'returns false when the query is unhandled' do
|
225
226
|
expect(subject.handle('xxx')).to be false
|
226
227
|
end
|
227
228
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'ego/runner'
|
2
|
+
|
3
|
+
RSpec.describe Ego::Runner do
|
4
|
+
context 'with empty arguments' do
|
5
|
+
subject { described_class.new([]) }
|
6
|
+
|
7
|
+
it 'prints usage help' do
|
8
|
+
expect { subject.run }.to output(
|
9
|
+
/^Usage:/
|
10
|
+
).to_stdout
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with --help' do
|
15
|
+
subject { described_class.new(['--help']) }
|
16
|
+
|
17
|
+
it 'prints usage help' do
|
18
|
+
expect { subject.run }.to output(
|
19
|
+
/^Usage:/
|
20
|
+
).to_stdout
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with --version' do
|
25
|
+
subject { described_class.new(['--version']) }
|
26
|
+
|
27
|
+
it 'prints gem version' do
|
28
|
+
expect { subject.run }.to output(
|
29
|
+
"ego v#{Ego::VERSION}\n"
|
30
|
+
).to_stdout
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with invalid arguments' do
|
35
|
+
subject { described_class.new(['--invalid-flag']) }
|
36
|
+
|
37
|
+
it 'prints usage error and help' do
|
38
|
+
expect { subject.run }.to raise_exception(SystemExit).and output(
|
39
|
+
/^invalid option:/
|
40
|
+
).to_stderr.and output(
|
41
|
+
/^Usage:/
|
42
|
+
).to_stdout
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with simple query' do
|
47
|
+
subject { described_class.new(['--no-plugins', 'echo hello']) }
|
48
|
+
|
49
|
+
it 'prints a response' do
|
50
|
+
expect { subject.run }.to output(
|
51
|
+
/hello/
|
52
|
+
).to_stdout
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,3 +21,50 @@ RSpec.configure do |config|
|
|
21
21
|
# be too noisy due to issues in dependencies.
|
22
22
|
config.warnings = true
|
23
23
|
end
|
24
|
+
|
25
|
+
# Get a new robot instance with plugin.
|
26
|
+
#
|
27
|
+
# @param plugin [String] basename of plugin script
|
28
|
+
# @return [Ego::Robot] the decorated robot instance
|
29
|
+
def robot_with_plugin(plugin)
|
30
|
+
require 'ego'
|
31
|
+
|
32
|
+
options = double('Ego::Options')
|
33
|
+
opt_parser = double('OptionParser')
|
34
|
+
|
35
|
+
allow(opt_parser).to receive_messages({
|
36
|
+
program_name: 'ego',
|
37
|
+
})
|
38
|
+
|
39
|
+
allow(options).to receive_messages({
|
40
|
+
robot_name: 'TestBot',
|
41
|
+
verbose: false,
|
42
|
+
usage: opt_parser,
|
43
|
+
})
|
44
|
+
|
45
|
+
robot = Ego::Robot.new(options)
|
46
|
+
robot.extend(Ego::Printer) # Needed to test most robot output
|
47
|
+
String.disable_colorization = true
|
48
|
+
|
49
|
+
paths = Ego::Filesystem.builtin_plugins.select do |path|
|
50
|
+
path.end_with?("/#{plugin}.rb")
|
51
|
+
end
|
52
|
+
|
53
|
+
Ego::Plugin.class_variable_set :@@plugins, {}
|
54
|
+
Ego::Plugin.load paths
|
55
|
+
Ego::Plugin.decorate(robot).ready
|
56
|
+
end
|
57
|
+
|
58
|
+
RSpec::Matchers.define :handle_query do |query|
|
59
|
+
match do |robot|
|
60
|
+
!robot.first_handler_for(query).nil?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
RSpec::Matchers.define :be_able_to do |desc|
|
65
|
+
match do |robot|
|
66
|
+
robot.capabilities.select do |capability|
|
67
|
+
capability.desc == desc
|
68
|
+
end.any?
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ego
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Frederick
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -123,10 +123,12 @@ files:
|
|
123
123
|
- lib/ego/handler.rb
|
124
124
|
- lib/ego/options.rb
|
125
125
|
- lib/ego/plugin.rb
|
126
|
+
- lib/ego/plugin_helper.rb
|
126
127
|
- lib/ego/plugins/capabilities.rb
|
127
128
|
- lib/ego/plugins/fallback.rb
|
128
129
|
- lib/ego/plugins/robot_io.rb
|
129
130
|
- lib/ego/plugins/social.rb
|
131
|
+
- lib/ego/plugins/status.rb
|
130
132
|
- lib/ego/plugins/system.rb
|
131
133
|
- lib/ego/printer.rb
|
132
134
|
- lib/ego/robot.rb
|
@@ -136,10 +138,18 @@ files:
|
|
136
138
|
- spec/ego/capability_spec.rb
|
137
139
|
- spec/ego/handler_spec.rb
|
138
140
|
- spec/ego/options_spec.rb
|
141
|
+
- spec/ego/plugin_helper_spec.rb
|
139
142
|
- spec/ego/plugin_spec.rb
|
143
|
+
- spec/ego/plugins/capabilities_spec.rb
|
144
|
+
- spec/ego/plugins/fallback_spec.rb
|
145
|
+
- spec/ego/plugins/robot_io_spec.rb
|
146
|
+
- spec/ego/plugins/social_spec.rb
|
147
|
+
- spec/ego/plugins/status_spec.rb
|
148
|
+
- spec/ego/plugins/system_spec.rb
|
140
149
|
- spec/ego/printer_spec.rb
|
141
150
|
- spec/ego/robot_error_spec.rb
|
142
151
|
- spec/ego/robot_spec.rb
|
152
|
+
- spec/ego/runner_spec.rb
|
143
153
|
- spec/spec_helper.rb
|
144
154
|
homepage: https://github.com/noahfrederick/ego
|
145
155
|
licenses:
|
@@ -153,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
163
|
requirements:
|
154
164
|
- - "~>"
|
155
165
|
- !ruby/object:Gem::Version
|
156
|
-
version: '2.
|
166
|
+
version: '2.3'
|
157
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
168
|
requirements:
|
159
169
|
- - ">="
|
@@ -169,8 +179,16 @@ test_files:
|
|
169
179
|
- spec/ego/capability_spec.rb
|
170
180
|
- spec/ego/handler_spec.rb
|
171
181
|
- spec/ego/options_spec.rb
|
182
|
+
- spec/ego/plugin_helper_spec.rb
|
172
183
|
- spec/ego/plugin_spec.rb
|
184
|
+
- spec/ego/plugins/capabilities_spec.rb
|
185
|
+
- spec/ego/plugins/fallback_spec.rb
|
186
|
+
- spec/ego/plugins/robot_io_spec.rb
|
187
|
+
- spec/ego/plugins/social_spec.rb
|
188
|
+
- spec/ego/plugins/status_spec.rb
|
189
|
+
- spec/ego/plugins/system_spec.rb
|
173
190
|
- spec/ego/printer_spec.rb
|
174
191
|
- spec/ego/robot_error_spec.rb
|
175
192
|
- spec/ego/robot_spec.rb
|
193
|
+
- spec/ego/runner_spec.rb
|
176
194
|
- spec/spec_helper.rb
|