command_kit-completion 0.1.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 +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +27 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +8 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +48 -0
- data/Rakefile +30 -0
- data/command_kit-completion.gemspec +59 -0
- data/examples/cli/config/get.rb +47 -0
- data/examples/cli/config/set.rb +44 -0
- data/examples/cli/config.rb +23 -0
- data/examples/cli/list.rb +35 -0
- data/examples/cli/update.rb +47 -0
- data/examples/cli.rb +55 -0
- data/gemspec.yml +27 -0
- data/lib/command_kit/completion/task.rb +204 -0
- data/lib/command_kit/completion/version.rb +8 -0
- data/spec/fixtures/additional_rules.yml +3 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/task_spec.rb +474 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ed090b5e927e5c88118a00518943d89d5dc405896469291c0bcd50ec44ea243
|
4
|
+
data.tar.gz: 3786b5ae7c7fa784ace3c2f173ce1b5121529674bbcb5899e45bf0bf5b6e79da
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e23917b5fb372dfaeed9316015b0e7a21f7e748c8afa8d8737e82008c8c8a45c365ae97dbf093537766bd67ce30a61487e9d062744b77ad1fcf72cf177a9f7db
|
7
|
+
data.tar.gz: 8de5d327ece13f2c287663a18c62859635f5dd13ae29c5052f405898cafbacc17c2619d27e7d3877492f86b285c18274b5916b7c2005f7b88a6475faf261ced4
|
data/.document
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [ push, pull_request ]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
tests:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
ruby:
|
12
|
+
- 3.0
|
13
|
+
- 3.1
|
14
|
+
- 3.2
|
15
|
+
- jruby
|
16
|
+
- truffleruby
|
17
|
+
name: OS ${{ matrix.os }} / Ruby ${{ matrix.ruby }}
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
- name: Set up Ruby
|
21
|
+
uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
24
|
+
- name: Install Ruby dependencies
|
25
|
+
run: bundle install --jobs 4 --retry 3
|
26
|
+
- name: Run tests
|
27
|
+
run: bundle exec rake test
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "CommandKit Documentation" --protected
|
data/ChangeLog.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
### 0.1.0 / 2023-12-18
|
2
|
+
|
3
|
+
* Initial release:
|
4
|
+
* Supports automatically generating completion rules from a [command_kit] CLI
|
5
|
+
class's options and sub-commands.
|
6
|
+
* Supports loading additional completion rules from a YAML file.
|
7
|
+
|
8
|
+
[command_kit]: https://github.com/postmodern/command_kit.rb#readme
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'rake'
|
7
|
+
gem 'rubygems-tasks', '~> 0.2'
|
8
|
+
|
9
|
+
gem 'rspec', '~> 3.0'
|
10
|
+
gem 'simplecov', '~> 0.20', require: false
|
11
|
+
|
12
|
+
gem 'kramdown'
|
13
|
+
gem 'redcarpet', platform: :mri
|
14
|
+
gem 'yard', '~> 0.9'
|
15
|
+
gem 'yard-spellcheck', require: false
|
16
|
+
gem 'dead_end'
|
17
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2023 Hal Brodigan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# command_kit-completion
|
2
|
+
|
3
|
+
[](https://github.com/postmodern/command_kit-completion/actions/workflows/ruby.yml)
|
4
|
+
[](https://codeclimate.com/github/postmodern/command_kit-completion)
|
5
|
+
[](https://badge.fury.io/rb/wordlist)
|
6
|
+
|
7
|
+
* [Source](https://github.com/postmodern/command_kit-completion#readme)
|
8
|
+
* [Issues](https://github.com/postmodern/command_kit-completion/issues)
|
9
|
+
* [Documentation](https://rubydoc.info/gems/command_kit-complete)
|
10
|
+
|
11
|
+
## Description
|
12
|
+
|
13
|
+
Adds a rake task that generates shell completion rules for a [command_kit] CLI.
|
14
|
+
The rake task loads the CLI class and uses the [completely] library to generate
|
15
|
+
the shell completion rules.
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
* Supports automatically generating completion rules from a [command_kit] CLI
|
20
|
+
class's options and sub-commands.
|
21
|
+
* Supports loading additional completion rules from a YAML file.
|
22
|
+
|
23
|
+
## Examples
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'command_kit/completion/task'
|
27
|
+
CommandKit::Completion::Task.new(
|
28
|
+
class_file: './examples/cli',
|
29
|
+
class_name: 'Foo::CLI',
|
30
|
+
output_file: 'completion.sh'
|
31
|
+
)
|
32
|
+
```
|
33
|
+
|
34
|
+
## Requirements
|
35
|
+
|
36
|
+
* [Ruby] >= 3.0.0
|
37
|
+
* [command_kit] ~> 0.1
|
38
|
+
* [completely] ~> 0.6
|
39
|
+
|
40
|
+
## License
|
41
|
+
|
42
|
+
Copyright (c) 2023 Hal Brodigan
|
43
|
+
|
44
|
+
See {file:LICENSE.txt} for details.
|
45
|
+
|
46
|
+
[Ruby]: https://www.ruby-lang.org/
|
47
|
+
[command_kit]: https://github.com/postmodern/command_kit.rb#readme
|
48
|
+
[completely]: https://rubygems.org/gems/completely
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError => e
|
6
|
+
abort e.message
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rubygems/tasks'
|
11
|
+
Gem::Tasks.new
|
12
|
+
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
RSpec::Core::RakeTask.new
|
15
|
+
|
16
|
+
task :test => :spec
|
17
|
+
task :default => :spec
|
18
|
+
|
19
|
+
require 'yard'
|
20
|
+
YARD::Rake::YardocTask.new
|
21
|
+
task :doc => :yard
|
22
|
+
|
23
|
+
namespace :example do
|
24
|
+
require 'command_kit/completion/task'
|
25
|
+
CommandKit::Completion::Task.new(
|
26
|
+
class_file: './examples/cli',
|
27
|
+
class_name: 'Foo::CLI',
|
28
|
+
output_file: 'example-completion.sh'
|
29
|
+
)
|
30
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gemspec = YAML.load_file('gemspec.yml')
|
5
|
+
|
6
|
+
gem.name = gemspec.fetch('name')
|
7
|
+
gem.version = gemspec.fetch('version') do
|
8
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
9
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
10
|
+
|
11
|
+
require 'command_kit/completion/version'
|
12
|
+
CommandKit::Completion::VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
gem.summary = gemspec['summary']
|
16
|
+
gem.description = gemspec['description']
|
17
|
+
gem.licenses = Array(gemspec['license'])
|
18
|
+
gem.authors = Array(gemspec['authors'])
|
19
|
+
gem.email = gemspec['email']
|
20
|
+
gem.homepage = gemspec['homepage']
|
21
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
22
|
+
|
23
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
24
|
+
|
25
|
+
gem.files = if gemspec['files'] then glob[gemspec['files']]
|
26
|
+
else `git ls-files`.split($/)
|
27
|
+
end
|
28
|
+
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
31
|
+
end
|
32
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
33
|
+
|
34
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
35
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
36
|
+
|
37
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
38
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
39
|
+
})
|
40
|
+
|
41
|
+
gem.requirements = Array(gemspec['requirements'])
|
42
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
43
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
44
|
+
gem.post_install_message = gemspec['post_install_message']
|
45
|
+
|
46
|
+
split = lambda { |string| string.split(/,\s*/) }
|
47
|
+
|
48
|
+
if gemspec['dependencies']
|
49
|
+
gemspec['dependencies'].each do |name,versions|
|
50
|
+
gem.add_dependency(name,split[versions])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if gemspec['development_dependencies']
|
55
|
+
gemspec['development_dependencies'].each do |name,versions|
|
56
|
+
gem.add_development_dependency(name,split[versions])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'command_kit/command'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class CLI
|
5
|
+
class Config < CommandKit::Command
|
6
|
+
#
|
7
|
+
# The `config get` sub-command.
|
8
|
+
#
|
9
|
+
class Get < CommandKit::Command
|
10
|
+
|
11
|
+
usage '[options] NAME'
|
12
|
+
|
13
|
+
argument :name, required: false,
|
14
|
+
desc: 'Configuration variable name'
|
15
|
+
|
16
|
+
description 'Gets a configuration variable'
|
17
|
+
|
18
|
+
CONFIG = {
|
19
|
+
'name' => 'John Smith',
|
20
|
+
'email' => 'john.smith@example.com'
|
21
|
+
}
|
22
|
+
|
23
|
+
#
|
24
|
+
# Runs the `config get` sub-command.
|
25
|
+
#
|
26
|
+
# @param [String, nil] name
|
27
|
+
# The optional name argument.
|
28
|
+
#
|
29
|
+
def run(name=nil)
|
30
|
+
if name
|
31
|
+
unless CONFIG.has_key?(name)
|
32
|
+
print_error "unknown config variable: #{name}"
|
33
|
+
exit(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
puts CONFIG.fetch(name)
|
37
|
+
else
|
38
|
+
CONFIG.each do |name,value|
|
39
|
+
puts "#{name}:\t#{value}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'command_kit/command'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class CLI
|
5
|
+
class Config < CommandKit::Command
|
6
|
+
#
|
7
|
+
# The `config set` sub-command.
|
8
|
+
#
|
9
|
+
class Set < CommandKit::Command
|
10
|
+
|
11
|
+
usage '[options] NAME'
|
12
|
+
|
13
|
+
argument :name, required: true,
|
14
|
+
desc: 'Configuration variable name to set'
|
15
|
+
|
16
|
+
argument :value, required: true,
|
17
|
+
desc: 'Configuration variable value to set'
|
18
|
+
|
19
|
+
description 'Sets a configuration variable'
|
20
|
+
|
21
|
+
CONFIG = {
|
22
|
+
'name' => 'John Smith',
|
23
|
+
'email' => 'john.smith@example.com'
|
24
|
+
}
|
25
|
+
|
26
|
+
#
|
27
|
+
# Runs the `config get` sub-command.
|
28
|
+
#
|
29
|
+
# @param [String] name
|
30
|
+
# The name argument.
|
31
|
+
#
|
32
|
+
def run(name,value)
|
33
|
+
unless CONFIG.has_key?(name)
|
34
|
+
print_error "unknown config variable: #{name}"
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "Configuration variable #{name} was #{CONFIG.fetch(name)}, but is now #{value}"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'command_kit/command'
|
2
|
+
require 'command_kit/commands'
|
3
|
+
|
4
|
+
require_relative 'config/get'
|
5
|
+
require_relative 'config/set'
|
6
|
+
|
7
|
+
module Foo
|
8
|
+
class CLI
|
9
|
+
#
|
10
|
+
# The `config` sub-command.
|
11
|
+
#
|
12
|
+
class Config < CommandKit::Command
|
13
|
+
|
14
|
+
include CommandKit::Commands
|
15
|
+
|
16
|
+
command Get
|
17
|
+
command Set
|
18
|
+
|
19
|
+
description 'Get or set the configuration'
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'command_kit/command'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class CLI
|
5
|
+
#
|
6
|
+
# The `list` sub-command.
|
7
|
+
#
|
8
|
+
class List < CommandKit::Command
|
9
|
+
|
10
|
+
usage '[options] [NAME]'
|
11
|
+
|
12
|
+
argument :name, required: false,
|
13
|
+
desc: 'Optional name to list'
|
14
|
+
|
15
|
+
description 'Lists the contents'
|
16
|
+
|
17
|
+
ITEMS = %w[foo bar baz]
|
18
|
+
|
19
|
+
#
|
20
|
+
# Runs the `list` sub-command.
|
21
|
+
#
|
22
|
+
# @param [String, nil] name
|
23
|
+
# The optional name argument.
|
24
|
+
#
|
25
|
+
def run(name=nil)
|
26
|
+
if name
|
27
|
+
puts ITEMS.grep(name)
|
28
|
+
else
|
29
|
+
puts ITEMS
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'command_kit/command'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class CLI
|
5
|
+
#
|
6
|
+
# The `update` sub-command.
|
7
|
+
#
|
8
|
+
class Update < CommandKit::Command
|
9
|
+
|
10
|
+
usage '[options] [NAME]'
|
11
|
+
|
12
|
+
option :quiet, short: '-q',
|
13
|
+
desc: 'Suppresses logging messages'
|
14
|
+
|
15
|
+
argument :name, required: false,
|
16
|
+
desc: 'Optional name to update'
|
17
|
+
|
18
|
+
description 'Updates an item or all items'
|
19
|
+
|
20
|
+
ITEMS = %w[foo bar baz]
|
21
|
+
|
22
|
+
#
|
23
|
+
# Runs the `update` sub-command.
|
24
|
+
#
|
25
|
+
# @param [String, nil] name
|
26
|
+
# The optional name argument.
|
27
|
+
#
|
28
|
+
def run(name=nil)
|
29
|
+
if name
|
30
|
+
unless ITEMS.include?(name)
|
31
|
+
print_error "unknown item: #{name}"
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "Updating #{name} ..." unless options[:quiet]
|
36
|
+
sleep 1
|
37
|
+
puts "Item #{name} updated." unless options[:quiet]
|
38
|
+
else
|
39
|
+
puts "Updating ..." unless options[:quiet]
|
40
|
+
sleep 2
|
41
|
+
puts "All items updated." unless options[:quiet]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/examples/cli.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../../lib',__FILE__))
|
4
|
+
|
5
|
+
require 'command_kit/commands'
|
6
|
+
|
7
|
+
require_relative 'cli/config'
|
8
|
+
require_relative 'cli/list'
|
9
|
+
require_relative 'cli/update'
|
10
|
+
|
11
|
+
module Foo
|
12
|
+
#
|
13
|
+
# The main CLI command.
|
14
|
+
#
|
15
|
+
class CLI
|
16
|
+
|
17
|
+
include CommandKit::Commands
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# The global configuration file setting.
|
21
|
+
#
|
22
|
+
# @return [String, nil]
|
23
|
+
attr_accessor :config_file
|
24
|
+
end
|
25
|
+
|
26
|
+
command_name 'foo'
|
27
|
+
|
28
|
+
# Commands must be explicitly registered, unless
|
29
|
+
# CommandKit::Commands::AutoLoad.new(...) is included.
|
30
|
+
command Config
|
31
|
+
command List
|
32
|
+
command Update
|
33
|
+
|
34
|
+
# Commands may have aliases
|
35
|
+
command_aliases['ls'] = 'list'
|
36
|
+
command_aliases['up'] = 'update'
|
37
|
+
|
38
|
+
# Global options may be defined which are parsed before the sub-command's
|
39
|
+
# options are parsed and the sub-command is executed.
|
40
|
+
option :config_file, short: '-C',
|
41
|
+
value: {
|
42
|
+
type: String,
|
43
|
+
usage: 'FILE'
|
44
|
+
},
|
45
|
+
desc: 'Global option to set the config file' do |file|
|
46
|
+
CLI.config_file = file
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if $0 == __FILE__
|
53
|
+
# Normally you would invoke Foo::CLI.start from a bin/ script.
|
54
|
+
Foo::CLI.start
|
55
|
+
end
|
data/gemspec.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
name: command_kit-completion
|
2
|
+
summary: Generate shell completions for command_kit commands
|
3
|
+
description:
|
4
|
+
Adds a rake task that generates shell completion rules for a command_kit CLI.
|
5
|
+
The rake task loads the CLI class and uses the 'completely' library to
|
6
|
+
generate shell completion rules.
|
7
|
+
|
8
|
+
license: MIT
|
9
|
+
authors: Postmodern
|
10
|
+
email: postmodern.mod3@gmail.com
|
11
|
+
homepage: https://github.com/postmodern/command_kit-completion#readme
|
12
|
+
|
13
|
+
metadata:
|
14
|
+
documentation_uri: https://rubydoc.info/gems/command_kit-completion
|
15
|
+
source_code_uri: https://github.com/postmodern/command_kit-completion
|
16
|
+
bug_tracker_uri: https://github.com/postmodern/command_kit-completion/issues
|
17
|
+
changelog_uri: https://github.com/postmodern/command_kit-completion/blob/main/ChangeLog.md
|
18
|
+
rubygems_mfa_required: 'true'
|
19
|
+
|
20
|
+
required_ruby_version: ">= 3.0.0"
|
21
|
+
|
22
|
+
dependencies:
|
23
|
+
command_kit: ~> 0.1
|
24
|
+
completely: ~> 0.6
|
25
|
+
|
26
|
+
development_dependencies:
|
27
|
+
bundler: ~> 2.0
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake/tasklib'
|
4
|
+
|
5
|
+
require 'command_kit/options'
|
6
|
+
require 'command_kit/commands'
|
7
|
+
require 'completely'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
module CommandKit
|
11
|
+
module Completion
|
12
|
+
class Task < Rake::TaskLib
|
13
|
+
|
14
|
+
# The file that the command_kit CLI is defined in.
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :class_file
|
18
|
+
|
19
|
+
# The class name of the command_kit CLI.
|
20
|
+
#
|
21
|
+
# @return [String]
|
22
|
+
attr_reader :class_name
|
23
|
+
|
24
|
+
# The output file to write the shell completions to.
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
attr_reader :output_file
|
28
|
+
|
29
|
+
# Optional input YAML file to read additional shell completions from.
|
30
|
+
#
|
31
|
+
# @return [String, nil]
|
32
|
+
attr_reader :input_file
|
33
|
+
|
34
|
+
# Specifies whether the shell completion logic should be wrapped in a
|
35
|
+
# function.
|
36
|
+
#
|
37
|
+
# @return [Boolean]
|
38
|
+
attr_reader :wrap_function
|
39
|
+
|
40
|
+
# Optional function name to wrap the shell completions within.
|
41
|
+
#
|
42
|
+
# @return [String, nil]
|
43
|
+
attr_reader :function_name
|
44
|
+
|
45
|
+
#
|
46
|
+
# Initializes the `command_kit:completion` task.
|
47
|
+
#
|
48
|
+
# @param [String] class_file
|
49
|
+
# The file that contains the comand_kit CLI.
|
50
|
+
#
|
51
|
+
# @param [String] class_name
|
52
|
+
# The class name of the command_kit CLI.
|
53
|
+
#
|
54
|
+
# @param [String] output_file
|
55
|
+
# The output file to write the completions rules to.
|
56
|
+
#
|
57
|
+
# @param [String, nil] input_file
|
58
|
+
# The optional YAML input file of additional completion rules.
|
59
|
+
# See [completely examples] for YAML syntax.
|
60
|
+
#
|
61
|
+
# [completely examples]: https://github.com/DannyBen/completely?tab=readme-ov-file#using-the-completely-command-line
|
62
|
+
#
|
63
|
+
def initialize(class_file: ,
|
64
|
+
class_name: ,
|
65
|
+
output_file: ,
|
66
|
+
input_file: nil,
|
67
|
+
wrap_function: false,
|
68
|
+
function_name: nil)
|
69
|
+
@class_file = class_file
|
70
|
+
@class_name = class_name
|
71
|
+
@output_file = output_file
|
72
|
+
|
73
|
+
@input_file = input_file
|
74
|
+
@wrap_function = wrap_function
|
75
|
+
@function_name = function_name
|
76
|
+
|
77
|
+
define
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Defines the `command_kit:completion` task.
|
82
|
+
#
|
83
|
+
def define
|
84
|
+
task(@output_file) do
|
85
|
+
completions = Completely::Completions.new(completion_rules)
|
86
|
+
shell_script = if @wrap_function
|
87
|
+
completions.wrap_function(*@function_name)
|
88
|
+
else
|
89
|
+
completions.script
|
90
|
+
end
|
91
|
+
|
92
|
+
File.write(@output_file,shell_script)
|
93
|
+
end
|
94
|
+
|
95
|
+
desc 'Generates the shell completions'
|
96
|
+
task 'command_kit:completion' => @output_file
|
97
|
+
|
98
|
+
task :completion => 'command_kit:completion'
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Loads the {#class_name} from the {#class_file}.
|
103
|
+
#
|
104
|
+
# @return [Class]
|
105
|
+
#
|
106
|
+
def load_class
|
107
|
+
require(@class_file)
|
108
|
+
Object.const_get(@class_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Mapping of command usage strings to completely `<keyword>`s.
|
112
|
+
USAGE_COMPLETIONS = {
|
113
|
+
'FILE' => '<file>',
|
114
|
+
'DIR' => '<directory>',
|
115
|
+
'HOST' => '<hostname>',
|
116
|
+
'USER' => '<user>'
|
117
|
+
}
|
118
|
+
|
119
|
+
#
|
120
|
+
# Generates the completion rules for the given [command_kit] command
|
121
|
+
# class.
|
122
|
+
#
|
123
|
+
# [command_kit]: https://github.com/postmodern/command_kit.rb#readme
|
124
|
+
#
|
125
|
+
# @param [Class] command_class
|
126
|
+
# The command class.
|
127
|
+
#
|
128
|
+
# @return [Hash{String => Array<String>}]
|
129
|
+
# The completion rules for the command class and any sub-commands.
|
130
|
+
#
|
131
|
+
def completion_rules_for(command_class)
|
132
|
+
command_name = command_class.command_name
|
133
|
+
completions = {command_name => []}
|
134
|
+
|
135
|
+
# options
|
136
|
+
if command_class.include?(CommandKit::Options)
|
137
|
+
# add all long option flags
|
138
|
+
command_class.options.each_value do |option|
|
139
|
+
completions[command_name] << option.long
|
140
|
+
|
141
|
+
if option.value
|
142
|
+
if (option_value_completion = USAGE_COMPLETIONS[option.value.usage])
|
143
|
+
# add a special rule if the option's value USAGE maps to a
|
144
|
+
# 'completely' completion keyword (ex: `FILE` -> `<file>`).
|
145
|
+
completions["#{command_name}*#{option.long}"] = [
|
146
|
+
option_value_completion
|
147
|
+
]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# sub-commands
|
154
|
+
if command_class.include?(CommandKit::Commands)
|
155
|
+
command_class.commands.each do |subcommand_name,subcommand|
|
156
|
+
# add all sub-command names
|
157
|
+
completions[command_name] << subcommand_name
|
158
|
+
|
159
|
+
# generate completions for the sub-command and merge them in
|
160
|
+
completion_rules_for(subcommand.command).each do |subcommand_string,subcommand_completions|
|
161
|
+
completions["#{command_name} #{subcommand_string}"] = subcommand_completions
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
completions[command_name].concat(command_class.command_aliases.keys)
|
166
|
+
end
|
167
|
+
|
168
|
+
# filter out any command's that have no options/sub-commands
|
169
|
+
completions.reject! do |command_string,command_completions|
|
170
|
+
command_completions.empty?
|
171
|
+
end
|
172
|
+
|
173
|
+
return completions
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Builds the completion rules for the command_kit CLI command, and merges
|
178
|
+
# in any additional completion rules from the input file.
|
179
|
+
#
|
180
|
+
# @return [Hash{String => Array<String>}]
|
181
|
+
#
|
182
|
+
def completion_rules
|
183
|
+
completion_rules = completion_rules_for(load_class)
|
184
|
+
|
185
|
+
if @input_file
|
186
|
+
# load the additional rules from the input file
|
187
|
+
additional_completion_rules = YAML.load_file(@input_file)
|
188
|
+
|
189
|
+
# merge the additional completion rules
|
190
|
+
additional_completion_rules.each do |command_string,completions|
|
191
|
+
if completion_rules[command_string]
|
192
|
+
completion_rules[command_string].concat(completions)
|
193
|
+
else
|
194
|
+
completion_rules[command_string] = completions
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
return completion_rules
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/task_spec.rb
ADDED
@@ -0,0 +1,474 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/completion/task'
|
3
|
+
|
4
|
+
require 'tempfile'
|
5
|
+
require 'command_kit/command'
|
6
|
+
require 'command_kit/commands'
|
7
|
+
|
8
|
+
describe CommandKit::Completion::Task do
|
9
|
+
let(:class_file) { './examples/cli' }
|
10
|
+
let(:class_name) { 'Foo::CLI' }
|
11
|
+
let(:tempfile) { Tempfile.new(['command_kit-completion','.sh']) }
|
12
|
+
let(:output_file) { tempfile.path }
|
13
|
+
|
14
|
+
let(:fixtures_dir) { File.join(__dir__,'fixtures') }
|
15
|
+
|
16
|
+
subject do
|
17
|
+
described_class.new(
|
18
|
+
class_file: class_file,
|
19
|
+
class_name: class_name,
|
20
|
+
output_file: output_file
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#define" do
|
25
|
+
before { subject }
|
26
|
+
|
27
|
+
it "must define a task for the output file" do
|
28
|
+
expect(Rake::Task[output_file]).to_not be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must define a 'command_kit:completion' task" do
|
32
|
+
expect(Rake::Task['command_kit:completion']).to_not be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "must define a 'completion' task" do
|
36
|
+
expect(Rake::Task['completion']).to_not be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#initialize" do
|
41
|
+
it "must set #class_file" do
|
42
|
+
expect(subject.class_file).to eq(class_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must set #class_name" do
|
46
|
+
expect(subject.class_name).to eq(class_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must set #output_file" do
|
50
|
+
expect(subject.output_file).to eq(output_file)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "must default #input_file to nil" do
|
54
|
+
expect(subject.input_file).to be(nil)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "must default #wrap_function to false" do
|
58
|
+
expect(subject.wrap_function).to be(false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must default #function_name to nil" do
|
62
|
+
expect(subject.function_name).to be(nil)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#load_class" do
|
67
|
+
it "must return the Class object for #class_name in #class_file" do
|
68
|
+
expect(subject.load_class).to be(Foo::CLI)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#completion_rules_for" do
|
73
|
+
context "when given a simple CommandKit::Command class" do
|
74
|
+
class TestBasicCommand < CommandKit::Command
|
75
|
+
|
76
|
+
command_name 'test'
|
77
|
+
|
78
|
+
option :foo, desc: 'Foo option'
|
79
|
+
|
80
|
+
option :bar, value: {
|
81
|
+
type: String
|
82
|
+
},
|
83
|
+
desc: 'Bar option'
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:command_class) { TestBasicCommand }
|
88
|
+
|
89
|
+
it "must return a Hash of completion rules for the command" do
|
90
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
91
|
+
{
|
92
|
+
"test" => %w[--foo --bar]
|
93
|
+
}
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when one of the options accepts a FILE value" do
|
98
|
+
class TestCommandWithFILEOption < CommandKit::Command
|
99
|
+
|
100
|
+
command_name 'test'
|
101
|
+
|
102
|
+
option :foo, desc: 'Foo option'
|
103
|
+
|
104
|
+
option :bar, value: {
|
105
|
+
type: String,
|
106
|
+
usage: 'FILE'
|
107
|
+
},
|
108
|
+
desc: 'Bar option'
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
let(:command_class) { TestCommandWithFILEOption }
|
113
|
+
|
114
|
+
it "must add a separate completion rule for the option using the <file> keyword" do
|
115
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
116
|
+
{
|
117
|
+
"test" => %w[--foo --bar],
|
118
|
+
'test*--bar' => %w[<file>]
|
119
|
+
}
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when one of the options accepts a DIR value" do
|
125
|
+
class TestCommandWithDIROption < CommandKit::Command
|
126
|
+
|
127
|
+
command_name 'test'
|
128
|
+
|
129
|
+
option :foo, desc: 'Foo option'
|
130
|
+
|
131
|
+
option :bar, value: {
|
132
|
+
type: String,
|
133
|
+
usage: 'DIR'
|
134
|
+
},
|
135
|
+
desc: 'Bar option'
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
let(:command_class) { TestCommandWithDIROption }
|
140
|
+
|
141
|
+
it "must add a separate completion rule for the option using the <directory> keyword" do
|
142
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
143
|
+
{
|
144
|
+
"test" => %w[--foo --bar],
|
145
|
+
'test*--bar' => %w[<directory>]
|
146
|
+
}
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when one of the options accepts a HOST value" do
|
152
|
+
class TestCommandWithHOSTOption < CommandKit::Command
|
153
|
+
|
154
|
+
command_name 'test'
|
155
|
+
|
156
|
+
option :foo, desc: 'Foo option'
|
157
|
+
|
158
|
+
option :bar, value: {
|
159
|
+
type: String,
|
160
|
+
usage: 'HOST'
|
161
|
+
},
|
162
|
+
desc: 'Bar option'
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
let(:command_class) { TestCommandWithHOSTOption }
|
167
|
+
|
168
|
+
it "must add a separate completion rule for the option using the <hostname> keyword" do
|
169
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
170
|
+
{
|
171
|
+
"test" => %w[--foo --bar],
|
172
|
+
'test*--bar' => %w[<hostname>]
|
173
|
+
}
|
174
|
+
)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "when one of the options accepts a USER value" do
|
179
|
+
class TestCommandWithUSEROption < CommandKit::Command
|
180
|
+
|
181
|
+
command_name 'test'
|
182
|
+
|
183
|
+
option :foo, desc: 'Foo option'
|
184
|
+
|
185
|
+
option :bar, value: {
|
186
|
+
type: String,
|
187
|
+
usage: 'USER'
|
188
|
+
},
|
189
|
+
desc: 'Bar option'
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
let(:command_class) { TestCommandWithUSEROption }
|
194
|
+
|
195
|
+
it "must add a separate completion rule for the option using the <user> keyword" do
|
196
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
197
|
+
{
|
198
|
+
"test" => %w[--foo --bar],
|
199
|
+
'test*--bar' => %w[<user>]
|
200
|
+
}
|
201
|
+
)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "but the command class does not include CommandKit::Options" do
|
206
|
+
class TestCommandWithoutOptions
|
207
|
+
include CommandKit::CommandName
|
208
|
+
include CommandKit::Usage
|
209
|
+
include CommandKit::Arguments
|
210
|
+
|
211
|
+
command_name 'test'
|
212
|
+
end
|
213
|
+
|
214
|
+
let(:command_class) { TestCommandWithoutOptions }
|
215
|
+
|
216
|
+
it "must return an empty Hash" do
|
217
|
+
expect(subject.completion_rules_for(command_class)).to eq({})
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context "when the command class includes CommandKit::Commands" do
|
223
|
+
class TestCommandWithSubCommands < CommandKit::Command
|
224
|
+
include CommandKit::Commands
|
225
|
+
|
226
|
+
option :global_option, short: '-g',
|
227
|
+
desc: 'A global option'
|
228
|
+
|
229
|
+
class Foo < CommandKit::Command
|
230
|
+
|
231
|
+
option :foo_opt1, desc: 'Foo option 1'
|
232
|
+
|
233
|
+
option :foo_opt2, value: {
|
234
|
+
type: String
|
235
|
+
},
|
236
|
+
desc: 'Foo option 2'
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
class Bar < CommandKit::Command
|
241
|
+
|
242
|
+
option :bar_opt1, desc: 'Bar option 1'
|
243
|
+
|
244
|
+
option :bar_opt2, value: {
|
245
|
+
type: String
|
246
|
+
},
|
247
|
+
desc: 'Bar option 2'
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
command_name 'test'
|
252
|
+
command Foo
|
253
|
+
command Bar
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
let(:command_class) { TestCommandWithSubCommands }
|
258
|
+
|
259
|
+
it "must add completion rules for the other commands" do
|
260
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
261
|
+
{
|
262
|
+
"test" => %w[--global-option help foo bar],
|
263
|
+
"test foo" => %w[--foo-opt1 --foo-opt2],
|
264
|
+
"test bar" => %w[--bar-opt1 --bar-opt2]
|
265
|
+
}
|
266
|
+
)
|
267
|
+
end
|
268
|
+
|
269
|
+
context "when the command has command aliases" do
|
270
|
+
class TestCommandWithSubCommandsAndCommandAliases < CommandKit::Command
|
271
|
+
include CommandKit::Commands
|
272
|
+
|
273
|
+
option :global_option, short: '-g',
|
274
|
+
desc: 'A global option'
|
275
|
+
|
276
|
+
class Foo < CommandKit::Command
|
277
|
+
|
278
|
+
option :foo_opt1, desc: 'Foo option 1'
|
279
|
+
|
280
|
+
option :foo_opt2, value: {
|
281
|
+
type: String
|
282
|
+
},
|
283
|
+
desc: 'Foo option 2'
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
class Bar < CommandKit::Command
|
288
|
+
|
289
|
+
option :bar_opt1, desc: 'Bar option 1'
|
290
|
+
|
291
|
+
option :bar_opt2, value: {
|
292
|
+
type: String
|
293
|
+
},
|
294
|
+
desc: 'Bar option 2'
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
command_name 'test'
|
299
|
+
command Foo
|
300
|
+
command Bar
|
301
|
+
|
302
|
+
command_aliases['foo2'] = 'foo'
|
303
|
+
command_aliases['bar2'] = 'bar'
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
let(:command_class) { TestCommandWithSubCommandsAndCommandAliases }
|
308
|
+
|
309
|
+
it "must include the command aliases in the completion rules" do
|
310
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
311
|
+
{
|
312
|
+
"test" => %w[--global-option help foo bar foo2 bar2],
|
313
|
+
"test foo" => %w[--foo-opt1 --foo-opt2],
|
314
|
+
"test bar" => %w[--bar-opt1 --bar-opt2]
|
315
|
+
}
|
316
|
+
)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context "but when one of the commands does not define any options" do
|
321
|
+
class TestCommandWithSubCommandsWithNoOptions < CommandKit::Command
|
322
|
+
include CommandKit::Commands
|
323
|
+
|
324
|
+
option :global_option, short: '-g',
|
325
|
+
desc: 'A global option'
|
326
|
+
|
327
|
+
class Foo < CommandKit::Command
|
328
|
+
|
329
|
+
option :foo_opt1, desc: 'Foo option 1'
|
330
|
+
|
331
|
+
option :foo_opt2, value: {
|
332
|
+
type: String
|
333
|
+
},
|
334
|
+
desc: 'Foo option 2'
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
class Bar < CommandKit::Command
|
339
|
+
end
|
340
|
+
|
341
|
+
command_name 'test'
|
342
|
+
command Foo
|
343
|
+
command Bar
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
let(:command_class) { TestCommandWithSubCommandsWithNoOptions }
|
348
|
+
|
349
|
+
it "must omit the command from the completion rules" do
|
350
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
351
|
+
{
|
352
|
+
"test" => %w[--global-option help foo bar],
|
353
|
+
"test foo" => %w[--foo-opt1 --foo-opt2]
|
354
|
+
}
|
355
|
+
)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
context "and when one of the sub-commands also includes CommandKit::Commands" do
|
360
|
+
class TestCommandWithSubSubCommands < CommandKit::Command
|
361
|
+
include CommandKit::Commands
|
362
|
+
|
363
|
+
option :global_option, short: '-g',
|
364
|
+
desc: 'A global option'
|
365
|
+
|
366
|
+
class Foo < CommandKit::Command
|
367
|
+
|
368
|
+
option :foo_opt1, desc: 'Foo option 1'
|
369
|
+
|
370
|
+
option :foo_opt2, value: {
|
371
|
+
type: String
|
372
|
+
},
|
373
|
+
desc: 'Foo option 2'
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
class Bar < CommandKit::Command
|
378
|
+
|
379
|
+
include CommandKit::Commands
|
380
|
+
|
381
|
+
option :bar_opt1, desc: 'Bar option 1'
|
382
|
+
|
383
|
+
option :bar_opt2, value: {
|
384
|
+
type: String
|
385
|
+
},
|
386
|
+
desc: 'Bar option 2'
|
387
|
+
|
388
|
+
class Baz < CommandKit::Command
|
389
|
+
|
390
|
+
option :baz_opt1, desc: 'Baz option 1'
|
391
|
+
|
392
|
+
option :baz_opt2, value: {
|
393
|
+
type: String
|
394
|
+
},
|
395
|
+
desc: 'Baz option 2'
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
class Qux < CommandKit::Command
|
400
|
+
|
401
|
+
option :qux_opt1, desc: 'Qux option 1'
|
402
|
+
|
403
|
+
option :qux_opt2, value: {
|
404
|
+
type: String
|
405
|
+
},
|
406
|
+
desc: 'Qux option 2'
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
command Baz
|
411
|
+
command Qux
|
412
|
+
|
413
|
+
end
|
414
|
+
|
415
|
+
command_name 'test'
|
416
|
+
command Foo
|
417
|
+
command Bar
|
418
|
+
|
419
|
+
end
|
420
|
+
|
421
|
+
let(:command_class) { TestCommandWithSubSubCommands }
|
422
|
+
|
423
|
+
it "must recursively include completion rules for the sub-sub-commands" do
|
424
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
425
|
+
{
|
426
|
+
"test" => %w[--global-option help foo bar],
|
427
|
+
"test foo" => %w[--foo-opt1 --foo-opt2],
|
428
|
+
"test bar" => %w[--bar-opt1 --bar-opt2 help baz qux],
|
429
|
+
"test bar baz" => %w[--baz-opt1 --baz-opt2],
|
430
|
+
"test bar qux" => %w[--qux-opt1 --qux-opt2]
|
431
|
+
}
|
432
|
+
)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
describe "#completion_rules" do
|
439
|
+
it "must load the class from #class_file and return the generated completion rules for it" do
|
440
|
+
expect(subject.completion_rules).to eq(
|
441
|
+
{
|
442
|
+
"foo" => %w[--config-file help config list update ls up],
|
443
|
+
"foo config" => %w[help get set],
|
444
|
+
"foo update" => %w[--quiet],
|
445
|
+
"foo*--config-file" => %w[<file>]
|
446
|
+
}
|
447
|
+
)
|
448
|
+
end
|
449
|
+
|
450
|
+
context "when #input_file is set" do
|
451
|
+
let(:input_file) { File.join(fixtures_dir,'additional_rules.yml') }
|
452
|
+
|
453
|
+
subject do
|
454
|
+
described_class.new(
|
455
|
+
class_file: class_file,
|
456
|
+
class_name: class_name,
|
457
|
+
output_file: output_file,
|
458
|
+
input_file: input_file
|
459
|
+
)
|
460
|
+
end
|
461
|
+
|
462
|
+
it "must merge the additional completion rules with the generated ones" do
|
463
|
+
expect(subject.completion_rules).to eq(
|
464
|
+
{
|
465
|
+
"foo" => %w[--config-file help config list update ls up],
|
466
|
+
"foo config" => %w[help get set],
|
467
|
+
"foo update" => ['--quiet', '$(foo list)'],
|
468
|
+
"foo*--config-file" => %w[<file>]
|
469
|
+
}
|
470
|
+
)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: command_kit-completion
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Postmodern
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: command_kit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: completely
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
description: Adds a rake task that generates shell completion rules for a command_kit
|
56
|
+
CLI. The rake task loads the CLI class and uses the 'completely' library to generate
|
57
|
+
shell completion rules.
|
58
|
+
email: postmodern.mod3@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files:
|
62
|
+
- ChangeLog.md
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
files:
|
66
|
+
- ".document"
|
67
|
+
- ".github/workflows/ruby.yml"
|
68
|
+
- ".gitignore"
|
69
|
+
- ".rspec"
|
70
|
+
- ".yardopts"
|
71
|
+
- ChangeLog.md
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- command_kit-completion.gemspec
|
77
|
+
- examples/cli.rb
|
78
|
+
- examples/cli/config.rb
|
79
|
+
- examples/cli/config/get.rb
|
80
|
+
- examples/cli/config/set.rb
|
81
|
+
- examples/cli/list.rb
|
82
|
+
- examples/cli/update.rb
|
83
|
+
- gemspec.yml
|
84
|
+
- lib/command_kit/completion/task.rb
|
85
|
+
- lib/command_kit/completion/version.rb
|
86
|
+
- spec/fixtures/additional_rules.yml
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/task_spec.rb
|
89
|
+
homepage: https://github.com/postmodern/command_kit-completion#readme
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata:
|
93
|
+
documentation_uri: https://rubydoc.info/gems/command_kit-completion
|
94
|
+
source_code_uri: https://github.com/postmodern/command_kit-completion
|
95
|
+
bug_tracker_uri: https://github.com/postmodern/command_kit-completion/issues
|
96
|
+
changelog_uri: https://github.com/postmodern/command_kit-completion/blob/main/ChangeLog.md
|
97
|
+
rubygems_mfa_required: 'true'
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 3.0.0
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubygems_version: 3.4.10
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Generate shell completions for command_kit commands
|
117
|
+
test_files: []
|