ego 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|