dry-cli-completion 0.3.0 → 0.9.0.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/dry-cli-completion.svg)](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