philiprehberger-cli_kit 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/CHANGELOG.md +19 -0
- data/LICENSE +21 -0
- data/README.md +97 -0
- data/lib/philiprehberger/cli_kit/parser.rb +87 -0
- data/lib/philiprehberger/cli_kit/prompt.rb +33 -0
- data/lib/philiprehberger/cli_kit/spinner.rb +42 -0
- data/lib/philiprehberger/cli_kit/version.rb +7 -0
- data/lib/philiprehberger/cli_kit.rb +53 -0
- metadata +57 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5f8c44f068b8daee68d4a4f0e2d862a27b8cc9d068ed0c13f1d00c8bca158555
|
|
4
|
+
data.tar.gz: 8a28c59097b7b571375e39f955d7513d1b94f8f193a1f0d9a319086ed085daad
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0bafa11c4295d54dacdfb375b98869763d4f39f71dec7dbd30577176c52a77673fb53bcae5f4497b700ea566d5029bdf03f680749496edc851c5e4c82c27c09e
|
|
7
|
+
data.tar.gz: cd0591f45daddb536940b7398d6d768856ed05b83f185474095af37b6c59d9c0d5c1204cb4dae41fefcbb1c420a6581dc9f22e1f594438f0c1f005fb61c2b76e
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this gem will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-03-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Initial release
|
|
14
|
+
- DSL-based argument parser with flags and options
|
|
15
|
+
- Short and long option aliases
|
|
16
|
+
- Interactive prompt for text input
|
|
17
|
+
- Yes/no confirmation prompt
|
|
18
|
+
- Animated spinner for long-running operations
|
|
19
|
+
- Positional argument collection
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 philiprehberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# philiprehberger-cli_kit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/philiprehberger/rb-cli-kit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/philiprehberger-cli_kit)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
All-in-one CLI toolkit with argument parsing, prompts, and spinners
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Ruby >= 3.1
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Add to your Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem "philiprehberger-cli_kit"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install directly:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install philiprehberger-cli_kit
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require "philiprehberger/cli_kit"
|
|
31
|
+
|
|
32
|
+
result = Philiprehberger::CliKit.parse(ARGV) do
|
|
33
|
+
flag :verbose, short: :v
|
|
34
|
+
option :output, short: :o, default: 'out.txt'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
result.flags[:verbose] # => true/false
|
|
38
|
+
result.options[:output] # => 'out.txt' or user-provided value
|
|
39
|
+
result.arguments # => remaining positional args
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Prompts
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
name = Philiprehberger::CliKit.prompt('What is your name?')
|
|
46
|
+
# What is your name? _
|
|
47
|
+
|
|
48
|
+
confirmed = Philiprehberger::CliKit.confirm('Continue?')
|
|
49
|
+
# Continue? [y/n] _
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Spinners
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
data = Philiprehberger::CliKit.spinner('Loading data...') do
|
|
56
|
+
# long-running operation
|
|
57
|
+
fetch_remote_data
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Argument Parsing Details
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
# Given: mytool --verbose -o report.csv input.txt
|
|
65
|
+
result = Philiprehberger::CliKit.parse(%w[--verbose -o report.csv input.txt]) do
|
|
66
|
+
flag :verbose, short: :v
|
|
67
|
+
option :output, short: :o, default: 'out.txt'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
result.flags[:verbose] # => true
|
|
71
|
+
result.options[:output] # => 'report.csv'
|
|
72
|
+
result.arguments # => ['input.txt']
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
| Method | Description |
|
|
78
|
+
|--------|-------------|
|
|
79
|
+
| `.parse(args) { ... }` | Parse arguments with flag/option DSL |
|
|
80
|
+
| `.prompt(message)` | Display prompt and read input |
|
|
81
|
+
| `.confirm(message)` | Display yes/no confirmation |
|
|
82
|
+
| `.spinner(message) { ... }` | Show spinner during block execution |
|
|
83
|
+
| `Parser#flags` | Hash of boolean flag values |
|
|
84
|
+
| `Parser#options` | Hash of option values |
|
|
85
|
+
| `Parser#arguments` | Array of positional arguments |
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
bundle install
|
|
91
|
+
bundle exec rspec
|
|
92
|
+
bundle exec rubocop
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module CliKit
|
|
5
|
+
# DSL-based argument parser for CLI applications.
|
|
6
|
+
class Parser
|
|
7
|
+
attr_reader :flags, :options, :arguments
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@flag_definitions = {}
|
|
11
|
+
@option_definitions = {}
|
|
12
|
+
@flags = {}
|
|
13
|
+
@options = {}
|
|
14
|
+
@arguments = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Define a boolean flag.
|
|
18
|
+
#
|
|
19
|
+
# @param name [Symbol] the flag name
|
|
20
|
+
# @param short [Symbol, nil] short alias (single character)
|
|
21
|
+
# @return [void]
|
|
22
|
+
def flag(name, short: nil)
|
|
23
|
+
@flag_definitions[name] = { short: short }
|
|
24
|
+
@flags[name] = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Define a value option.
|
|
28
|
+
#
|
|
29
|
+
# @param name [Symbol] the option name
|
|
30
|
+
# @param short [Symbol, nil] short alias (single character)
|
|
31
|
+
# @param default [Object, nil] default value
|
|
32
|
+
# @return [void]
|
|
33
|
+
def option(name, short: nil, default: nil)
|
|
34
|
+
@option_definitions[name] = { short: short, default: default }
|
|
35
|
+
@options[name] = default
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Parse the given argument array.
|
|
39
|
+
#
|
|
40
|
+
# @param args [Array<String>] command-line arguments
|
|
41
|
+
# @return [self]
|
|
42
|
+
def parse(args)
|
|
43
|
+
args = args.dup
|
|
44
|
+
while args.any?
|
|
45
|
+
arg = args.shift
|
|
46
|
+
if arg.start_with?('--')
|
|
47
|
+
parse_long(arg, args)
|
|
48
|
+
elsif arg.start_with?('-') && arg.length > 1
|
|
49
|
+
parse_short(arg, args)
|
|
50
|
+
else
|
|
51
|
+
@arguments << arg
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def parse_long(arg, args)
|
|
60
|
+
name = arg.sub(/\A--/, '').tr('-', '_').to_sym
|
|
61
|
+
if @flag_definitions.key?(name)
|
|
62
|
+
@flags[name] = true
|
|
63
|
+
elsif @option_definitions.key?(name)
|
|
64
|
+
@options[name] = args.shift
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def parse_short(arg, args)
|
|
69
|
+
char = arg.sub(/\A-/, '').to_sym
|
|
70
|
+
|
|
71
|
+
@flag_definitions.each do |name, defn|
|
|
72
|
+
if defn[:short] == char
|
|
73
|
+
@flags[name] = true
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@option_definitions.each do |name, defn|
|
|
79
|
+
if defn[:short] == char
|
|
80
|
+
@options[name] = args.shift
|
|
81
|
+
return
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module CliKit
|
|
5
|
+
# Interactive prompt utilities for CLI applications.
|
|
6
|
+
module Prompt
|
|
7
|
+
# Display a prompt and read user input.
|
|
8
|
+
#
|
|
9
|
+
# @param message [String] the prompt message
|
|
10
|
+
# @param input [IO] input stream (default: $stdin)
|
|
11
|
+
# @param output [IO] output stream (default: $stdout)
|
|
12
|
+
# @return [String] the user's input, stripped of whitespace
|
|
13
|
+
def self.prompt(message, input: $stdin, output: $stdout)
|
|
14
|
+
output.print "#{message} "
|
|
15
|
+
output.flush
|
|
16
|
+
input.gets&.strip || ''
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Display a yes/no confirmation prompt.
|
|
20
|
+
#
|
|
21
|
+
# @param message [String] the confirmation message
|
|
22
|
+
# @param input [IO] input stream (default: $stdin)
|
|
23
|
+
# @param output [IO] output stream (default: $stdout)
|
|
24
|
+
# @return [Boolean] true if user answered yes
|
|
25
|
+
def self.confirm(message, input: $stdin, output: $stdout)
|
|
26
|
+
output.print "#{message} [y/n] "
|
|
27
|
+
output.flush
|
|
28
|
+
answer = input.gets&.strip&.downcase || ''
|
|
29
|
+
%w[y yes].include?(answer)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module CliKit
|
|
5
|
+
# Animated spinner for long-running CLI operations.
|
|
6
|
+
module Spinner
|
|
7
|
+
FRAMES = %w[| / - \\].freeze
|
|
8
|
+
|
|
9
|
+
# Display a spinner while executing a block.
|
|
10
|
+
#
|
|
11
|
+
# @param message [String] the message to display alongside the spinner
|
|
12
|
+
# @param output [IO] output stream (default: $stderr)
|
|
13
|
+
# @yield the block to execute
|
|
14
|
+
# @return [Object] the return value of the block
|
|
15
|
+
def self.spinner(message, output: $stderr, &block)
|
|
16
|
+
done = false
|
|
17
|
+
result = nil
|
|
18
|
+
|
|
19
|
+
thread = Thread.new do
|
|
20
|
+
frame = 0
|
|
21
|
+
until done
|
|
22
|
+
output.print "\r#{FRAMES[frame % FRAMES.length]} #{message}"
|
|
23
|
+
output.flush
|
|
24
|
+
frame += 1
|
|
25
|
+
sleep 0.1
|
|
26
|
+
end
|
|
27
|
+
output.print "\r\e[K"
|
|
28
|
+
output.flush
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
result = block.call
|
|
33
|
+
ensure
|
|
34
|
+
done = true
|
|
35
|
+
thread.join
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
result
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'cli_kit/version'
|
|
4
|
+
require_relative 'cli_kit/parser'
|
|
5
|
+
require_relative 'cli_kit/prompt'
|
|
6
|
+
require_relative 'cli_kit/spinner'
|
|
7
|
+
|
|
8
|
+
module Philiprehberger
|
|
9
|
+
module CliKit
|
|
10
|
+
class Error < StandardError; end
|
|
11
|
+
|
|
12
|
+
# Parse command-line arguments using a DSL block.
|
|
13
|
+
#
|
|
14
|
+
# @param args [Array<String>] command-line arguments
|
|
15
|
+
# @yield [Parser] the parser for defining flags and options
|
|
16
|
+
# @return [Parser] the parsed result with flags, options, and arguments
|
|
17
|
+
def self.parse(args, &block)
|
|
18
|
+
parser = Parser.new
|
|
19
|
+
parser.instance_eval(&block)
|
|
20
|
+
parser.parse(args)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Display a prompt and read user input.
|
|
24
|
+
#
|
|
25
|
+
# @param message [String] the prompt message
|
|
26
|
+
# @param input [IO] input stream
|
|
27
|
+
# @param output [IO] output stream
|
|
28
|
+
# @return [String] the user's input
|
|
29
|
+
def self.prompt(message, input: $stdin, output: $stdout)
|
|
30
|
+
Prompt.prompt(message, input: input, output: output)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Display a yes/no confirmation prompt.
|
|
34
|
+
#
|
|
35
|
+
# @param message [String] the confirmation message
|
|
36
|
+
# @param input [IO] input stream
|
|
37
|
+
# @param output [IO] output stream
|
|
38
|
+
# @return [Boolean] true if user answered yes
|
|
39
|
+
def self.confirm(message, input: $stdin, output: $stdout)
|
|
40
|
+
Prompt.confirm(message, input: input, output: output)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Display a spinner while executing a block.
|
|
44
|
+
#
|
|
45
|
+
# @param message [String] the spinner message
|
|
46
|
+
# @param output [IO] output stream
|
|
47
|
+
# @yield the block to execute
|
|
48
|
+
# @return [Object] the return value of the block
|
|
49
|
+
def self.spinner(message, output: $stderr, &block)
|
|
50
|
+
Spinner.spinner(message, output: output, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: philiprehberger-cli_kit
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Philip Rehberger
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-22 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Lightweight CLI toolkit combining argument parsing with flags and options,
|
|
14
|
+
interactive prompts with confirmation, and animated spinners for long-running operations.
|
|
15
|
+
email:
|
|
16
|
+
- me@philiprehberger.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CHANGELOG.md
|
|
22
|
+
- LICENSE
|
|
23
|
+
- README.md
|
|
24
|
+
- lib/philiprehberger/cli_kit.rb
|
|
25
|
+
- lib/philiprehberger/cli_kit/parser.rb
|
|
26
|
+
- lib/philiprehberger/cli_kit/prompt.rb
|
|
27
|
+
- lib/philiprehberger/cli_kit/spinner.rb
|
|
28
|
+
- lib/philiprehberger/cli_kit/version.rb
|
|
29
|
+
homepage: https://github.com/philiprehberger/rb-cli-kit
|
|
30
|
+
licenses:
|
|
31
|
+
- MIT
|
|
32
|
+
metadata:
|
|
33
|
+
homepage_uri: https://github.com/philiprehberger/rb-cli-kit
|
|
34
|
+
source_code_uri: https://github.com/philiprehberger/rb-cli-kit
|
|
35
|
+
changelog_uri: https://github.com/philiprehberger/rb-cli-kit/blob/main/CHANGELOG.md
|
|
36
|
+
bug_tracker_uri: https://github.com/philiprehberger/rb-cli-kit/issues
|
|
37
|
+
rubygems_mfa_required: 'true'
|
|
38
|
+
post_install_message:
|
|
39
|
+
rdoc_options: []
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 3.1.0
|
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
requirements: []
|
|
53
|
+
rubygems_version: 3.5.22
|
|
54
|
+
signing_key:
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: All-in-one CLI toolkit with argument parsing, prompts, and spinners
|
|
57
|
+
test_files: []
|