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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb611ff121ae25f5f4b8cbe926d7742a28885e2408cabb2e589fce724d67b85c
4
- data.tar.gz: '008ba658f43ec5177037e31f0bf4e78aafbfcbb866065e1cbd702117815495f3'
3
+ metadata.gz: f964195592d079499e1ac64d97966be5041cec718b12d7dbdcad3a13a78a987c
4
+ data.tar.gz: 19eb60e90e5d136ac43762f8c897b7f3b9d0197074e12c3a7237ad96230034e2
5
5
  SHA512:
6
- metadata.gz: 9362523877d4147af5ffdbbb53a54158ffee4b2a5709c6e3aa854197da105f391861fd6daacd80bedf0d1b7b4fbb1cd520e9a5abb56cdc4dd83b384ba0d8504a
7
- data.tar.gz: b5603912acb40ff3a2d4e0cdf2c8734a86cef9572139b9087e31d33e84d833bd081c47f7429716aa18a8a6ed0804780004234090eb82a68f4b28cbbad39ab976
6
+ metadata.gz: 85b055c56a7fd6c9752449275766126f57a51aa2a74e976246b62b25b4a7625cc858b794121d5443b03020cee8407cc00b4fdb79be1c3cbb8b7d738255d10dbf
7
+ data.tar.gz: 943acef312431e8176115bea9c3dcdbcef4960640eb409f391a731442b1098f7dbafb5562546c120e00f01524c4087d54b98cd505688923d5de3bcc3a18ff109
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.9.0-alpha First full fledged Implementation
4
+
3
5
  ## 0.3.0 Inital Skeleton
data/Gemfile CHANGED
@@ -7,3 +7,5 @@ gemspec
7
7
 
8
8
  gem "rspec", "~> 3.0"
9
9
  gem "standard"
10
+ gem "dry-cli"
11
+ gem "pry"
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Tobias Bielohlawek
3
+ Copyright (c) 2022 Tobias Bielohlawek (rngtng)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # Dry::Cli::Completion
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
- ## About
5
+ ---
8
6
 
9
- Extension Command for Dry::CLI which generates a completion script for bash/zsh.
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
- ## Installation
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
- TODO: Write usage instructions here
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
- ## Development
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
- For local development, this project comes with a Dockerimage and Makefile. After checking out the repo, run the following to enter development console:
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
- make build dev
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
- Then, run `rake spec` to run the tests.
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
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dry
4
- module Cli
4
+ class CLI
5
5
  module Completion
6
- VERSION = "0.3.0"
6
+ VERSION = "0.9.0-alpha"
7
7
  end
8
8
  end
9
9
  end
@@ -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
- module Cli
7
+ class CLI
7
8
  module Completion
8
- class Error < StandardError; end
9
- # Your code goes here...
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.3.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-07-24 00:00:00.000000000 Z
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
- - Rakefile
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: '0'
67
+ version: 1.3.1
68
68
  requirements: []
69
69
  rubygems_version: 3.3.7
70
70
  signing_key:
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,9 +0,0 @@
1
- require: standard
2
-
3
- inherit_gem:
4
- standard: config/base.yml
5
-
6
- AllCops:
7
- TargetRubyVersion: 2.7
8
- Exclude:
9
- - 'vendor/**/*'
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
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- require "rubocop/rake_task"
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[spec rubocop]
@@ -1,8 +0,0 @@
1
- module Dry
2
- module Cli
3
- module Completion
4
- VERSION: String
5
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
6
- end
7
- end
8
- end