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.
- checksums.yaml +4 -4
- data/.rubocop.yml +20 -0
- data/.rubocop_todo.yml +36 -0
- data/Gemfile +2 -0
- data/Guardfile +9 -2
- data/Rakefile +5 -1
- data/bin/ego +2 -0
- data/ego.gemspec +22 -17
- data/lib/ego.rb +3 -1
- data/lib/ego/capability.rb +2 -0
- data/lib/ego/filesystem.rb +2 -0
- data/lib/ego/handler.rb +8 -2
- data/lib/ego/options.rb +13 -8
- data/lib/ego/plugin.rb +3 -1
- data/lib/ego/plugin_helper.rb +18 -16
- data/lib/ego/plugins/capabilities.rb +9 -3
- data/lib/ego/plugins/fallback.rb +9 -7
- data/lib/ego/plugins/robot_io.rb +2 -0
- data/lib/ego/plugins/social.rb +3 -1
- data/lib/ego/plugins/status.rb +2 -0
- data/lib/ego/plugins/system.rb +4 -2
- data/lib/ego/printer.rb +9 -5
- data/lib/ego/robot.rb +9 -6
- data/lib/ego/robot_error.rb +2 -0
- data/lib/ego/runner.rb +12 -7
- data/lib/ego/version.rb +3 -1
- data/spec/ego/acceptance/help_spec.rb +9 -0
- data/spec/ego/acceptance/no_args_spec.rb +9 -0
- data/spec/ego/acceptance/shell_spec.rb +11 -0
- data/spec/ego/acceptance/simple_query_spec.rb +9 -0
- data/spec/ego/acceptance/template_spec.rb +43 -0
- data/spec/ego/acceptance/usage_error_spec.rb +17 -0
- data/spec/ego/acceptance/version_spec.rb +9 -0
- data/spec/ego/capability_spec.rb +2 -0
- data/spec/ego/handler_spec.rb +18 -6
- data/spec/ego/options_spec.rb +8 -1
- data/spec/ego/plugin_helper_spec.rb +4 -2
- data/spec/ego/plugin_spec.rb +5 -4
- data/spec/ego/plugins/capabilities_spec.rb +4 -4
- data/spec/ego/plugins/fallback_spec.rb +16 -6
- data/spec/ego/plugins/robot_io_spec.rb +3 -3
- data/spec/ego/plugins/social_spec.rb +3 -3
- data/spec/ego/plugins/status_spec.rb +3 -3
- data/spec/ego/plugins/system_spec.rb +8 -8
- data/spec/ego/printer_spec.rb +86 -86
- data/spec/ego/robot_error_spec.rb +2 -0
- data/spec/ego/robot_spec.rb +24 -22
- data/spec/ego/runner_spec.rb +12 -0
- data/spec/spec_helper.rb +5 -48
- data/spec/support/aruba.rb +3 -0
- data/spec/support/plugin_helper.rb +64 -0
- metadata +71 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cb81d8a1088b04177d530c9e48535cf5aac9836
|
4
|
+
data.tar.gz: e73d083cb652574fda45ae050434c5317afa9690
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0804236f4b6316062857aeb92ab2376c7b10150b5e83588f1a57f9c9ea57ec7ded723872c25d3a557fc40eb9d0bb96656323086c722fe1fffe270f6c1fb7d4c
|
7
|
+
data.tar.gz: d618ba73954abebffd2eaac1b1ee71f275729b41ea12b926cc199cf525d523bb83656393216ad822ace7c925c2c980c6c0c5e77a59eaae3dab276c8e964b8a70
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.3
|
5
|
+
|
6
|
+
Metrics/BlockLength:
|
7
|
+
Exclude:
|
8
|
+
- '*.gemspec'
|
9
|
+
- 'spec/**/*_spec.rb'
|
10
|
+
- 'lib/ego/options.rb'
|
11
|
+
- 'lib/ego/plugins/*.rb'
|
12
|
+
|
13
|
+
Style/Semicolon:
|
14
|
+
Exclude:
|
15
|
+
- 'spec/**/*_spec.rb'
|
16
|
+
|
17
|
+
Style/SingleLineMethods:
|
18
|
+
Exclude:
|
19
|
+
- 'spec/**/*_spec.rb'
|
20
|
+
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2018-02-05 09:02:49 -0500 using RuboCop version 0.52.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 2
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 27
|
12
|
+
|
13
|
+
# Offense count: 1
|
14
|
+
Metrics/CyclomaticComplexity:
|
15
|
+
Max: 9
|
16
|
+
|
17
|
+
# Offense count: 3
|
18
|
+
# Configuration parameters: CountComments.
|
19
|
+
Metrics/MethodLength:
|
20
|
+
Max: 31
|
21
|
+
|
22
|
+
# Offense count: 4
|
23
|
+
Style/ClassVars:
|
24
|
+
Exclude:
|
25
|
+
- 'lib/ego/plugin.rb'
|
26
|
+
|
27
|
+
# Offense count: 1
|
28
|
+
Style/Documentation:
|
29
|
+
Exclude:
|
30
|
+
- 'lib/ego.rb'
|
31
|
+
|
32
|
+
# Offense count: 32
|
33
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
34
|
+
# URISchemes: http, https
|
35
|
+
Metrics/LineLength:
|
36
|
+
Max: 160
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
4
|
+
require 'guard/rspec/dsl'
|
3
5
|
dsl = Guard::RSpec::Dsl.new(self)
|
4
6
|
|
5
7
|
# RSpec files
|
@@ -12,3 +14,8 @@ guard :rspec, cmd: "bundle exec rspec" do
|
|
12
14
|
ruby = dsl.ruby
|
13
15
|
dsl.watch_spec_files_for(ruby.lib_files)
|
14
16
|
end
|
17
|
+
|
18
|
+
guard :rubocop do
|
19
|
+
watch(/.+\.rb$/)
|
20
|
+
watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
|
21
|
+
end
|
data/Rakefile
CHANGED
data/bin/ego
CHANGED
data/ego.gemspec
CHANGED
@@ -1,35 +1,40 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
lib = File.expand_path('../lib', __FILE__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require 'ego/version'
|
5
7
|
|
6
8
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
9
|
+
spec.name = 'ego'
|
8
10
|
spec.version = Ego::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description = <<-
|
11
|
+
spec.authors = ['Noah Frederick']
|
12
|
+
spec.email = ['acc.rubygems@noahfrederick.com']
|
13
|
+
spec.summary = 'An extensible personal command-line assistant'
|
14
|
+
spec.description = <<-DESC
|
13
15
|
Ego is a personal command-line assistant that provides a flexible, natural
|
14
16
|
language interface (sort of) for interacting with other programs. Think of
|
15
17
|
it as a single-user IRC bot that can be extended with handlers for various
|
16
18
|
natural-language queries.
|
17
|
-
|
18
|
-
spec.homepage =
|
19
|
-
spec.license =
|
19
|
+
DESC
|
20
|
+
spec.homepage = 'https://github.com/noahfrederick/ego'
|
21
|
+
spec.license = 'GPL-3.0+'
|
20
22
|
|
21
23
|
spec.files = `git ls-files -z`.split("\x0")
|
22
24
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
25
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
-
spec.require_paths = [
|
26
|
+
spec.require_paths = ['lib']
|
25
27
|
|
26
|
-
spec.required_ruby_version =
|
28
|
+
spec.required_ruby_version = '~> 2.3'
|
27
29
|
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
30
|
+
spec.add_development_dependency 'aruba', '~> 1.0.0.pre.alpha.2'
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
32
|
+
spec.add_development_dependency 'guard-rspec'
|
33
|
+
spec.add_development_dependency 'guard-rubocop'
|
34
|
+
spec.add_development_dependency 'rake'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.7'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.52.1'
|
32
37
|
|
33
|
-
spec.add_runtime_dependency
|
34
|
-
spec.add_runtime_dependency
|
38
|
+
spec.add_runtime_dependency 'colorize', '~> 0.7'
|
39
|
+
spec.add_runtime_dependency 'hooks', '~> 0.4'
|
35
40
|
end
|
data/lib/ego.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'ego/filesystem'
|
2
4
|
require_relative 'ego/robot'
|
3
5
|
require_relative 'ego/plugin'
|
@@ -12,7 +14,7 @@ module Ego
|
|
12
14
|
# automatically at runtime. Each plug-in goes in it's own file with an `.rb`
|
13
15
|
# extension (e.g., `~/.config/ego/plugins/my_plugin.rb`).
|
14
16
|
#
|
15
|
-
# Be careful
|
17
|
+
# Be careful---ego will execute any Ruby scripts in this directory
|
16
18
|
# indiscriminately.
|
17
19
|
#
|
18
20
|
# @example Create and register a new plug-in
|
data/lib/ego/capability.rb
CHANGED
data/lib/ego/filesystem.rb
CHANGED
data/lib/ego/handler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'robot_error'
|
2
4
|
|
3
5
|
module Ego
|
@@ -58,10 +60,14 @@ module Ego
|
|
58
60
|
# @return [false] if condition doesn't match
|
59
61
|
# @return [Array] parameters to pass to the action
|
60
62
|
def handle(query)
|
61
|
-
return false unless result = @condition.call(query)
|
63
|
+
return false unless (result = @condition.call(query))
|
62
64
|
|
63
65
|
@action.parameters.each_with_object([]) do |param, arr|
|
64
|
-
|
66
|
+
begin
|
67
|
+
arr << result[param.pop]
|
68
|
+
rescue IndexError
|
69
|
+
arr << nil # Match group isn't defined.
|
70
|
+
end
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
data/lib/ego/options.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
2
4
|
|
3
5
|
module Ego
|
4
6
|
# Parse command-line options and set defaults.
|
5
7
|
class Options
|
6
|
-
|
7
8
|
attr_reader :mode,
|
8
9
|
:plugins,
|
9
10
|
:robot_name,
|
@@ -18,7 +19,7 @@ module Ego
|
|
18
19
|
@plugins = true
|
19
20
|
@verbose = false
|
20
21
|
parse(argv)
|
21
|
-
@query = argv.join(
|
22
|
+
@query = argv.join(' ')
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
@@ -33,28 +34,32 @@ module Ego
|
|
33
34
|
@robot_name = opts.program_name.capitalize
|
34
35
|
opts.banner = "Usage: #{opts.program_name} [ options ] query..."
|
35
36
|
|
36
|
-
opts.on(
|
37
|
+
opts.on('-n', '--no-plugins', 'Skip loading user plug-ins') do
|
37
38
|
@plugins = false
|
38
39
|
end
|
39
40
|
|
40
|
-
opts.on(
|
41
|
+
opts.on('-s', '--shell', 'Start in REPL-mode') do
|
41
42
|
@mode = :shell
|
42
43
|
end
|
43
44
|
|
44
|
-
opts.on(
|
45
|
+
opts.on('-t', '--template', 'Create a new plug-in') do
|
46
|
+
@mode = :template
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('-v', '--version', 'Print version number') do
|
45
50
|
@mode = :version
|
46
51
|
end
|
47
52
|
|
48
|
-
opts.on(
|
53
|
+
opts.on('-V', '--verbose', 'Include debugging info in output') do
|
49
54
|
@verbose = true
|
50
55
|
end
|
51
56
|
|
52
|
-
opts.on(
|
57
|
+
opts.on('-h', '--help', 'Show this message') do
|
53
58
|
@mode = :help
|
54
59
|
end
|
55
60
|
|
56
61
|
begin
|
57
|
-
argv = [
|
62
|
+
argv = ['-h'] if argv.empty?
|
58
63
|
opts.parse!(argv)
|
59
64
|
rescue OptionParser::ParseError => e
|
60
65
|
@usage_error = e.message
|
data/lib/ego/plugin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Ego
|
2
4
|
# A plug-in extends Ego with new handlers and other functionality, through a
|
3
5
|
# domain-specific language (DSL).
|
@@ -47,7 +49,7 @@ module Ego
|
|
47
49
|
# @param obj [Object] the object to decorate
|
48
50
|
# @return [Object] the decorated object
|
49
51
|
def self.decorate(obj)
|
50
|
-
@@plugins.
|
52
|
+
@@plugins.each_value do |plugin|
|
51
53
|
@@context = plugin
|
52
54
|
plugin.body.call(obj)
|
53
55
|
@@context = nil
|
data/lib/ego/plugin_helper.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'filesystem'
|
2
4
|
|
3
5
|
module Ego
|
4
6
|
# The PluginHelper assists the user in writing extensions by generating
|
@@ -8,9 +10,9 @@ module Ego
|
|
8
10
|
class PluginHelper
|
9
11
|
# @param query [String] example user query
|
10
12
|
# @param program_name [String] the executable name
|
11
|
-
def initialize(query
|
12
|
-
@query = query
|
13
|
-
@program_name = program_name
|
13
|
+
def initialize(query: nil, program_name: nil)
|
14
|
+
@query = query || 'My new plugin'
|
15
|
+
@program_name = program_name || 'ego'
|
14
16
|
end
|
15
17
|
|
16
18
|
# Derive a slug from the user query.
|
@@ -18,13 +20,13 @@ module Ego
|
|
18
20
|
# @return [String] slug
|
19
21
|
def slug
|
20
22
|
@slug ||= @query
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
24
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
25
|
+
.tr('\'', '')
|
26
|
+
.gsub(/\W+/, '_')
|
27
|
+
.gsub(/__+/, '_')
|
28
|
+
.sub(/_$/, '')
|
29
|
+
.downcase
|
28
30
|
end
|
29
31
|
|
30
32
|
# Derive a plug-in path from the user query.
|
@@ -32,7 +34,7 @@ module Ego
|
|
32
34
|
# @return [String] plug-in path
|
33
35
|
def path
|
34
36
|
@path ||= Filesystem.config("plugins/#{slug}.rb")
|
35
|
-
|
37
|
+
.sub(/^#{ENV['HOME']}/, '~')
|
36
38
|
end
|
37
39
|
|
38
40
|
# Provide a hint for initializing a new plug-in.
|
@@ -40,19 +42,19 @@ module Ego
|
|
40
42
|
# @return [String] hint text
|
41
43
|
def hint
|
42
44
|
require 'shellwords'
|
43
|
-
@hint ||= <<~
|
45
|
+
@hint ||= <<~HINT
|
44
46
|
I don't understand "#{@query}".
|
45
47
|
|
46
48
|
If you would like to add this capability, start by running:
|
47
49
|
#{@program_name} #{@query.shellescape} > #{path}
|
48
|
-
|
50
|
+
HINT
|
49
51
|
end
|
50
52
|
|
51
53
|
# Provide a template for initializing a new plug-in.
|
52
54
|
#
|
53
55
|
# @return [String] template contents
|
54
56
|
def template
|
55
|
-
@template ||= <<~
|
57
|
+
@template ||= <<~TEMPLATE
|
56
58
|
Ego.plugin do |robot|
|
57
59
|
robot.can 'do something new'
|
58
60
|
|
@@ -60,7 +62,7 @@ module Ego
|
|
60
62
|
alert 'Not implemented yet. Go ahead and edit #{path}.'
|
61
63
|
end
|
62
64
|
end
|
63
|
-
|
65
|
+
TEMPLATE
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
@@ -1,17 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Ego.plugin do |robot|
|
2
4
|
robot.can 'list capabilities'
|
3
5
|
|
4
6
|
robot.on(
|
5
7
|
/^(show me|show|tell me|list)\s+(handlers|what you can do|what (?:you are|you're) able to do|what you do|what (?:queries )?you (?:can )?understand)$/i => 5,
|
6
8
|
/^what (?:can you|are you able to|do you) (?:do|handle|understand)\??$/i => 5,
|
7
|
-
/^help/i => 2
|
9
|
+
/^help/i => 2
|
8
10
|
) do
|
9
11
|
say 'I can...'
|
10
12
|
|
11
13
|
@capabilities.each do |cap|
|
12
14
|
builtin = cap.plugin.builtin ? '*' : ''
|
13
|
-
plugin =
|
14
|
-
|
15
|
+
plugin = format('(%<name>s%<builtin>s)',
|
16
|
+
name: cap.plugin.name,
|
17
|
+
builtin: builtin).magenta
|
18
|
+
printf("- %<desc>s %<plugin>s\n",
|
19
|
+
desc: cap.to_s,
|
20
|
+
plugin: plugin)
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
data/lib/ego/plugins/fallback.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Ego.plugin do |robot|
|
2
4
|
robot.can 'help you write plug-ins'
|
3
5
|
|
4
6
|
robot.on_unhandled_query do |query|
|
5
|
-
|
7
|
+
require_relative '../plugin_helper'
|
6
8
|
|
7
9
|
helper = Ego::PluginHelper.new(
|
8
10
|
query: query,
|
9
11
|
program_name: options.usage.program_name
|
10
12
|
)
|
11
13
|
|
12
|
-
if $stdout.isatty
|
13
|
-
|
14
|
-
|
14
|
+
alert helper.hint if $stdout.isatty
|
15
|
+
|
16
|
+
puts helper.template if verbose? || !$stdout.isatty
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
+
robot.on(/^$/) do
|
20
|
+
say %w[Yes? Hello? ...?].sample
|
19
21
|
end
|
20
22
|
end
|