dry-cli-completion 0.3.0 → 0.9.0.pre.alpha
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/CHANGELOG.md +2 -0
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +106 -12
- data/dry-cli-completion.gemspec +29 -0
- data/lib/dry/cli/completion/command.rb +40 -0
- data/lib/dry/cli/completion/generator.rb +31 -0
- data/lib/dry/cli/completion/input.rb +80 -0
- data/lib/dry/cli/completion/version.rb +2 -2
- data/lib/dry/cli/completion.rb +6 -3
- metadata +10 -10
- data/.rspec +0 -3
- data/.rubocop.yml +0 -9
- data/Dockerfile +0 -19
- data/Makefile +0 -20
- data/Rakefile +0 -12
- data/sig/dry/cli/completion.rbs +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f964195592d079499e1ac64d97966be5041cec718b12d7dbdcad3a13a78a987c
|
4
|
+
data.tar.gz: 19eb60e90e5d136ac43762f8c897b7f3b9d0197074e12c3a7237ad96230034e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85b055c56a7fd6c9752449275766126f57a51aa2a74e976246b62b25b4a7625cc858b794121d5443b03020cee8407cc00b4fdb79be1c3cbb8b7d738255d10dbf
|
7
|
+
data.tar.gz: 943acef312431e8176115bea9c3dcdbcef4960640eb409f391a731442b1098f7dbafb5562546c120e00f01524c4087d54b98cd505688923d5de3bcc3a18ff109
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
# Dry::
|
2
|
-
|
3
|
-
Dry::CLI Command to generate a completion script for bash/zsh
|
1
|
+
# Dry::CLI::Completion
|
4
2
|
|
5
3
|
[](https://badge.fury.io/rb/dry-cli-completion)
|
6
4
|
|
7
|
-
|
5
|
+
---
|
8
6
|
|
9
|
-
|
7
|
+
[Dry::CLI](https://github.com/dry-rb/dry-cli) extension & drop-in Command to generate a completion
|
8
|
+
script for bash/zsh. It heavily relies on the great work of https://github.com/dannyben/completely.
|
10
9
|
|
11
|
-
|
10
|
+
---
|
12
11
|
|
12
|
+
## Installation
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
15
|
```ruby
|
@@ -25,18 +25,112 @@ Or install it yourself as:
|
|
25
25
|
$ gem install dry-cli-completion
|
26
26
|
|
27
27
|
## Usage
|
28
|
+
The gems architecture consits of three layers which each abstracts & simplifies the completion script generation and its usage:
|
28
29
|
|
29
|
-
|
30
|
+
1. Command layer - drop-in dry-cli command to print the completion script for given shell
|
31
|
+
2. Generator layer - the actual script generation leveraging [completely](https://github.com/dannyben/completely)
|
32
|
+
3. Input layer - interspecting the dry-cli registry to extract each command with it options, arguements and aliases
|
30
33
|
|
31
|
-
|
34
|
+
### 1. Command layer
|
35
|
+
Simplest usage is to drop in the `Dry::CLI::Completion::Command` to your existing registry:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
module MyRegistry
|
39
|
+
extend Dry::CLI::Registry
|
40
|
+
|
41
|
+
register "cmd1", MyCmd1
|
42
|
+
#....
|
43
|
+
|
44
|
+
register "completion", Dry::CLI::Completion::Command[self]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
32
48
|
|
49
|
+
This will extend your cli for a new command `completion` with following usage:
|
50
|
+
|
51
|
+
```sh
|
52
|
+
Usage:
|
53
|
+
foo-cli completion [SHELL]
|
54
|
+
|
55
|
+
Description:
|
56
|
+
Print tab completion script for given shell
|
57
|
+
|
58
|
+
Arguments:
|
59
|
+
SHELL # Shell for which to print the completion script: (bash/zsh)
|
60
|
+
|
61
|
+
Options:
|
62
|
+
--[no-]include-aliases, -a # Include command aliases when true, default: false
|
63
|
+
--help, -h # Print this help
|
64
|
+
|
65
|
+
Examples:
|
66
|
+
foo-cli completion bash # Print tab completion script for bash
|
67
|
+
foo-cli completion zsh # Print tab completion script for zsh
|
68
|
+
foo-cli completion -a bash # Include command aliases for bash
|
69
|
+
```
|
70
|
+
|
71
|
+
### 2. Generator Layer
|
72
|
+
In case you want to change/extend the completion script, create a custom command and leverage just the generator:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class MyCommand < Dry::CLI::Command
|
76
|
+
desc "Custom completion script command"
|
77
|
+
|
78
|
+
def call(**)
|
79
|
+
script = Dry::CLI::Completion::Generator.new(MyRegistry).call(shell: "bash")
|
80
|
+
# ... further processing here ...
|
81
|
+
puts script
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
33
85
|
|
34
|
-
|
86
|
+
### 3. Input layer
|
87
|
+
Lastly, if the script generation input needs to be adjusted, leverage the input layer. Here the commands, arguments, options and their values/types extracted and put in an input format for `completely`. See [completely Readme](https://github.com/dannyben/completely) for details.
|
35
88
|
|
89
|
+
```ruby
|
90
|
+
input = Dry::CLI::Completion::Input.new(MyRegistry, "foo").call(include_aliases: false)
|
91
|
+
# ... further processing here ...
|
92
|
+
puts Completely::Completions.new(input)
|
36
93
|
```
|
37
|
-
|
94
|
+
|
95
|
+
## Development
|
96
|
+
For local development, this project comes dockerized - with a Dockerimage and Makefile. After checking out the repo, run the following to enter development console:
|
97
|
+
|
98
|
+
$ make build dev
|
99
|
+
|
100
|
+
With that, any dependencies are maintained and no ruby version manager is required.
|
101
|
+
|
102
|
+
### Testing
|
103
|
+
The gem comes with a full-fledged rspec testsuite. To execute all tests run in developer console:
|
104
|
+
|
105
|
+
$ rspec
|
106
|
+
|
107
|
+
### Manual Testing
|
108
|
+
The foo registry is used in unit test is available as `spec/foo-cli` for manual testing. First source the comepltion script:
|
109
|
+
|
110
|
+
$ source <(spec/foo-cli completion bash)
|
111
|
+
|
112
|
+
Then try the tab completion yourself:
|
113
|
+
|
114
|
+
```sh
|
115
|
+
$ spec/foo-cli <tab>
|
116
|
+
completion echo exec help start stop version
|
38
117
|
```
|
39
118
|
|
40
|
-
|
119
|
+
### Linting
|
120
|
+
For liniting, the gem leverages the [standard Readme](https://github.com/testdouble/standard) and [rubocop](https://github.com/rubocop/rubocop) rules. To execute just run:
|
121
|
+
|
122
|
+
$ rubocop
|
123
|
+
|
124
|
+
### Releasing
|
125
|
+
To release a new version, update the version number in `version.rb`, push commits to GitHub and then create a release. This will create a git tag for the version, and push the `.gem` file to [rubygems.org](https://rubygems.org) as well as GitHub packages.
|
126
|
+
See GitHub actions in `.github` for more.
|
127
|
+
|
128
|
+
## Supported Ruby versions
|
129
|
+
|
130
|
+
This library officially supports the following Ruby versions:
|
131
|
+
|
132
|
+
* MRI `>= 2.7.0`
|
133
|
+
|
134
|
+
## License
|
41
135
|
|
42
|
-
|
136
|
+
See `LICENSE` file.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/dry/cli/completion/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "dry-cli-completion"
|
7
|
+
spec.version = Dry::CLI::Completion::VERSION
|
8
|
+
spec.authors = ["rngtng"]
|
9
|
+
spec.email = ["tobi@rngtng.com"]
|
10
|
+
spec.licenses = ["MIT"]
|
11
|
+
|
12
|
+
spec.summary = "Dry::CLI Command to generate a completion script for bash/zsh"
|
13
|
+
spec.description = "Extension Command for Dry::CLI which generates a completion script for bash/zsh."
|
14
|
+
spec.homepage = "https://github.com/rngtng/dry-cli-completion"
|
15
|
+
spec.metadata = {
|
16
|
+
"homepage_uri" => spec.homepage,
|
17
|
+
"source_code_uri" => "https://github.com/rngtng/dry-cli-completion",
|
18
|
+
"changelog_uri" => "https://github.com/rngtng/dry-cli-completion/CHANGELOG.md",
|
19
|
+
"github_repo" => "ssh://github.com/rngtng/dry-cli-completion",
|
20
|
+
"rubygems_mfa_required" => "true"
|
21
|
+
}
|
22
|
+
|
23
|
+
spec.files = Dir["lib/**/*"] + %w[Gemfile LICENSE README.md CHANGELOG.md dry-cli-completion.gemspec]
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.required_ruby_version = ">= 2.7.6"
|
27
|
+
|
28
|
+
spec.add_dependency "completely", "~> 0.4"
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/cli/completion"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
class CLI
|
7
|
+
module Completion
|
8
|
+
class Command < Dry::CLI::Command
|
9
|
+
desc "Print tab completion script for given shell"
|
10
|
+
|
11
|
+
example [
|
12
|
+
"bash # Print tab completion script for bash",
|
13
|
+
"zsh # Print tab completion script for zsh",
|
14
|
+
"-a bash # Include command aliases for bash"
|
15
|
+
]
|
16
|
+
|
17
|
+
option :include_aliases, required: true, type: :boolean, default: false, aliases: ["a"],
|
18
|
+
desc: "Include command aliases when true"
|
19
|
+
argument :shell, required: false, type: :string, values: Dry::CLI::Completion::SUPPORTED_SHELLS,
|
20
|
+
desc: "Shell for which to print the completion script"
|
21
|
+
|
22
|
+
def call(shell:, include_aliases: false, **)
|
23
|
+
puts Generator.new(self.class.registry).call(
|
24
|
+
shell: shell,
|
25
|
+
include_aliases: include_aliases
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.[](registry)
|
30
|
+
@registry = registry
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
attr_reader :registry
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "input"
|
4
|
+
require "completely"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
class CLI
|
8
|
+
module Completion
|
9
|
+
class Generator
|
10
|
+
def initialize(registry, program_name: nil)
|
11
|
+
@registry = registry
|
12
|
+
@program_name = program_name || Dry::CLI::ProgramName.call
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(shell:, include_aliases: false, out: StringIO.new)
|
16
|
+
raise ArgumentError, "Unknown shell" unless SUPPORTED_SHELLS.include?(shell)
|
17
|
+
if shell == ZSH
|
18
|
+
out.puts "# enable bash completion support, see https://github.com/dannyben/completely#completions-in-zsh"
|
19
|
+
out.puts "autoload -Uz +X compinit && compinit"
|
20
|
+
out.puts "autoload -Uz +X bashcompinit && bashcompinit"
|
21
|
+
end
|
22
|
+
|
23
|
+
out.puts Completely::Completions.new(
|
24
|
+
Input.new(@registry, @program_name).call(include_aliases: include_aliases)
|
25
|
+
).script
|
26
|
+
out.string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
class CLI
|
5
|
+
module Completion
|
6
|
+
class Input
|
7
|
+
def initialize(registry, program_name)
|
8
|
+
@registry = registry
|
9
|
+
@program_name = program_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(include_aliases:)
|
13
|
+
nodes = root_node.children.dup
|
14
|
+
nodes.merge!(root_node.aliases.dup) if include_aliases
|
15
|
+
|
16
|
+
commands = nodes.each_with_object({}) do |(name, sub_node), hash|
|
17
|
+
next unless sub_node.command
|
18
|
+
hash[name] = command(sub_node.command, include_aliases: include_aliases)
|
19
|
+
end
|
20
|
+
|
21
|
+
commands.each_with_object({
|
22
|
+
@program_name => commands.keys + ["help"]
|
23
|
+
}) do |(name, config), input|
|
24
|
+
input_line(input, "#{@program_name} #{name}", config[:arguments].shift, config)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def root_node
|
31
|
+
@registry.get({}).instance_variable_get(:@node)
|
32
|
+
end
|
33
|
+
|
34
|
+
def command(command, include_aliases: false)
|
35
|
+
{
|
36
|
+
options: {
|
37
|
+
"--help" => []
|
38
|
+
},
|
39
|
+
arguments: command.arguments.map { |arg|
|
40
|
+
[arg.name, argument_values(arg)]
|
41
|
+
}
|
42
|
+
}.tap do |hash|
|
43
|
+
command.options.each do |opt|
|
44
|
+
hash[:options]["--#{opt.name}"] = option_values(opt)
|
45
|
+
next unless include_aliases
|
46
|
+
opt.aliases.each { |arg|
|
47
|
+
hash[:options]["-#{arg}"] = option_values(opt)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def argument_values(argument)
|
54
|
+
return ["<file>"] if argument.name.to_s.include?("path")
|
55
|
+
return argument.values if argument.values
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def option_values(option)
|
60
|
+
return ["<file>"] if option.name.to_s.include?("path")
|
61
|
+
return option.values if option.values
|
62
|
+
return [] if option.type != :boolean
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def input_line(input, name, argument, config)
|
67
|
+
return if name.include?("<file>")
|
68
|
+
if argument
|
69
|
+
arg_values = argument.last || []
|
70
|
+
input[name] = arg_values + config[:options].keys
|
71
|
+
argument = config[:arguments].shift
|
72
|
+
arg_values.each { |v| input_line(input, "#{name}*#{v}", argument, config) }
|
73
|
+
else
|
74
|
+
input[name] = config[:options].keys
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/dry/cli/completion.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "completion/version"
|
4
|
+
require_relative "completion/generator"
|
4
5
|
|
5
6
|
module Dry
|
6
|
-
|
7
|
+
class CLI
|
7
8
|
module Completion
|
8
|
-
|
9
|
-
|
9
|
+
SUPPORTED_SHELLS = [
|
10
|
+
BASH = "bash",
|
11
|
+
ZSH = "zsh"
|
12
|
+
]
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-cli-completion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0.pre.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rngtng
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: completely
|
@@ -32,18 +32,16 @@ executables: []
|
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
|
-
- ".rspec"
|
36
|
-
- ".rubocop.yml"
|
37
35
|
- CHANGELOG.md
|
38
|
-
- Dockerfile
|
39
36
|
- Gemfile
|
40
37
|
- LICENSE
|
41
|
-
- Makefile
|
42
38
|
- README.md
|
43
|
-
-
|
39
|
+
- dry-cli-completion.gemspec
|
44
40
|
- lib/dry/cli/completion.rb
|
41
|
+
- lib/dry/cli/completion/command.rb
|
42
|
+
- lib/dry/cli/completion/generator.rb
|
43
|
+
- lib/dry/cli/completion/input.rb
|
45
44
|
- lib/dry/cli/completion/version.rb
|
46
|
-
- sig/dry/cli/completion.rbs
|
47
45
|
homepage: https://github.com/rngtng/dry-cli-completion
|
48
46
|
licenses:
|
49
47
|
- MIT
|
@@ -51,6 +49,8 @@ metadata:
|
|
51
49
|
homepage_uri: https://github.com/rngtng/dry-cli-completion
|
52
50
|
source_code_uri: https://github.com/rngtng/dry-cli-completion
|
53
51
|
changelog_uri: https://github.com/rngtng/dry-cli-completion/CHANGELOG.md
|
52
|
+
github_repo: ssh://github.com/rngtng/dry-cli-completion
|
53
|
+
rubygems_mfa_required: 'true'
|
54
54
|
post_install_message:
|
55
55
|
rdoc_options: []
|
56
56
|
require_paths:
|
@@ -62,9 +62,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
62
|
version: 2.7.6
|
63
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- - "
|
65
|
+
- - ">"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 1.3.1
|
68
68
|
requirements: []
|
69
69
|
rubygems_version: 3.3.7
|
70
70
|
signing_key:
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
data/Dockerfile
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
FROM ruby:2.7-slim
|
2
|
-
|
3
|
-
RUN set -ex \
|
4
|
-
&& apt update \
|
5
|
-
&& apt install -y --no-install-recommends build-essential git
|
6
|
-
|
7
|
-
RUN mkdir /app
|
8
|
-
|
9
|
-
# COPY Gemfile Gemfile.lock /app/
|
10
|
-
|
11
|
-
WORKDIR /app
|
12
|
-
# RUN bundle install
|
13
|
-
# RUN bundle binstubs --all --path /bin
|
14
|
-
|
15
|
-
COPY . /app
|
16
|
-
|
17
|
-
ENV HISTCONTROL=ignoreboth:erasedups
|
18
|
-
|
19
|
-
ENTRYPOINT ["bash"]
|
data/Makefile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
PROJECT ?= rngtng/dry-cli-completion
|
2
|
-
BUILD_TAG ?= dev
|
3
|
-
REGISTRY_TAG = $(PROJECT):$(BUILD_TAG)
|
4
|
-
|
5
|
-
.PHONY: help # List all documented targets
|
6
|
-
help:
|
7
|
-
@grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 $(shell echo "\t") \2/' | sort | expand -t20
|
8
|
-
|
9
|
-
.PHONY: build # Build docker image with `dev` tag
|
10
|
-
build:
|
11
|
-
docker build -t $(REGISTRY_TAG) .
|
12
|
-
|
13
|
-
.PHONY: test-gh-action # Test github actions locally with https://github.com/nektos/act
|
14
|
-
test-gh-action:
|
15
|
-
echo '{ "inputs": { "tag": "0.1.0" } }' > /tmp/act.json
|
16
|
-
act --artifact-server-path /tmp/artifacts workflow_dispatch -e /tmp/act.json
|
17
|
-
|
18
|
-
.PHONY: dev # Build docker image, run and ssh inside
|
19
|
-
dev:
|
20
|
-
docker run --rm -it -v "$(shell pwd):/app" $(REGISTRY_TAG)
|
data/Rakefile
DELETED