mini-cli 0.3.0 → 0.4.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 +4 -4
- data/lib/mini-cli.rb +53 -16
- data/lib/mini-cli/version.rb +1 -1
- data/mini-cli.gemspec +19 -19
- data/rakefile.rb +3 -5
- data/samples/custom_args.rb +14 -11
- data/test/apps/noop +8 -0
- data/test/apps/sequence +28 -0
- data/test/mini-cli/exec_test.rb +96 -0
- data/test/mini-cli/main_test.rb +12 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 969a4421172e3cf6a3b6c6ecc294932e825a170de914ac5f19926fcc4e3da674
|
4
|
+
data.tar.gz: '039fc6a1d177834a3999468142a71a985ef417d179011cbba6b7b57777cb05c8'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8fc8a932a4e508327570bb3c4e062950d78b19cbaf87594456e2f5d340a22bcbe2db32bbffd55c76e7e57e2fdb1ca63118d2f20a67976bb60fb3795e9cf372a
|
7
|
+
data.tar.gz: 3a2d8fa7af6ec17ae701ab0a6505ce03084646540c3cab5a54facb76c5434ad5b29acdbcb9aea35d19e7daa60bdabdb79cf143a8f8a22a2d6af0b6c7d4aeb98e
|
data/lib/mini-cli.rb
CHANGED
@@ -2,8 +2,11 @@
|
|
2
2
|
|
3
3
|
module MiniCli
|
4
4
|
def self.included(mod)
|
5
|
-
|
6
|
-
|
5
|
+
mod.const_set(
|
6
|
+
:MiniCli__,
|
7
|
+
Instance.new(caller_locations(1, 1).first.absolute_path)
|
8
|
+
)
|
9
|
+
mod.private_constant(:MiniCli__)
|
7
10
|
end
|
8
11
|
|
9
12
|
def name(name = nil)
|
@@ -26,42 +29,58 @@ module MiniCli
|
|
26
29
|
__minicli__.show_errors = value ? true : false
|
27
30
|
end
|
28
31
|
|
32
|
+
def error_code
|
33
|
+
__minicli__.error_code
|
34
|
+
end
|
35
|
+
|
29
36
|
def error(code, message = nil)
|
30
37
|
$stderr.puts("#{name}: #{message}") if message && show_errors?
|
31
|
-
exit(code)
|
38
|
+
exit(__minicli__.error_code = code)
|
32
39
|
end
|
33
40
|
|
34
41
|
def parse_argv(argv = nil, &argv_converter)
|
35
42
|
return __minicli__.converter = argv_converter if argv_converter
|
36
|
-
argv
|
43
|
+
argv = Array.new(argv || ARGV)
|
37
44
|
exit(show_help) if argv.index('--help') || argv.index('-h')
|
38
|
-
__minicli__.
|
45
|
+
__minicli__.main(argv, method(:error).to_proc)
|
39
46
|
end
|
40
47
|
|
41
|
-
def main
|
42
|
-
|
43
|
-
yield(
|
48
|
+
def main
|
49
|
+
__minicli__.run do
|
50
|
+
yield(parse_argv)
|
44
51
|
rescue Interrupt
|
45
52
|
error(130, 'aborted')
|
46
53
|
end
|
47
54
|
end
|
48
55
|
|
56
|
+
def before(&callback)
|
57
|
+
callback and __minicli__.before << callback
|
58
|
+
end
|
59
|
+
|
60
|
+
def after(&callback)
|
61
|
+
callback and __minicli__.after << callback
|
62
|
+
end
|
63
|
+
|
49
64
|
private
|
50
65
|
|
51
66
|
def __minicli__
|
52
|
-
self.class
|
67
|
+
self.class.const_get(:MiniCli__)
|
53
68
|
end
|
54
69
|
|
55
70
|
class Instance
|
56
71
|
attr_reader :source
|
57
72
|
attr_writer :converter
|
58
|
-
attr_accessor :show_errors
|
73
|
+
attr_accessor :show_errors, :before, :after, :error_code
|
59
74
|
|
60
75
|
def initialize(source)
|
61
76
|
@source = source
|
62
77
|
@name = File.basename(source, '.*')
|
63
|
-
@parser = @converter = nil
|
78
|
+
@parser = @converter = @main_proc = nil
|
79
|
+
@before, @after = [], []
|
64
80
|
@show_errors = true
|
81
|
+
@before_ok = false
|
82
|
+
@error_code = 0
|
83
|
+
init_main
|
65
84
|
end
|
66
85
|
|
67
86
|
def name(name = nil)
|
@@ -77,16 +96,35 @@ module MiniCli
|
|
77
96
|
true
|
78
97
|
end
|
79
98
|
|
80
|
-
def
|
81
|
-
|
99
|
+
def run(&main_proc)
|
100
|
+
@main_proc = main_proc
|
82
101
|
end
|
83
102
|
|
84
|
-
def
|
103
|
+
def main(argv, error)
|
104
|
+
@before.each(&:call)
|
105
|
+
@before_ok = true
|
106
|
+
args = parser.parse(argv, error)
|
85
107
|
@converter ? @converter.call(args) || args : args
|
86
108
|
end
|
87
109
|
|
88
110
|
private
|
89
111
|
|
112
|
+
def init_main
|
113
|
+
at_exit do
|
114
|
+
next if $! and not ($!.kind_of?(SystemExit) and $!.success?)
|
115
|
+
shutdown unless @after.empty?
|
116
|
+
@main_proc&.call
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def shutdown(pid = Process.pid)
|
121
|
+
at_exit do
|
122
|
+
next if Process.pid != pid
|
123
|
+
@after.reverse_each(&:call) if @before_ok
|
124
|
+
exit(@error_code)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
90
128
|
def parser
|
91
129
|
@parser ||= ArgvParser.new(nil, [])
|
92
130
|
end
|
@@ -121,8 +159,7 @@ module MiniCli
|
|
121
159
|
while (arg = argv.shift)
|
122
160
|
case arg
|
123
161
|
when '--'
|
124
|
-
arguments += argv
|
125
|
-
break
|
162
|
+
break arguments += argv
|
126
163
|
when /\A--([[[:alnum:]]-]+)\z/
|
127
164
|
handle_option(Regexp.last_match[1], argv)
|
128
165
|
when /\A-([[:alnum:]]+)\z/
|
data/lib/mini-cli/version.rb
CHANGED
data/mini-cli.gemspec
CHANGED
@@ -2,30 +2,30 @@
|
|
2
2
|
|
3
3
|
require_relative './lib/mini-cli/version'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'mini-cli'
|
7
|
+
spec.version = MiniCli::VERSION
|
8
|
+
spec.required_ruby_version = '>= 2.5.0'
|
9
|
+
|
10
|
+
spec.summary = 'The lean CLI framework for Ruby'
|
11
|
+
spec.description = <<~DESC
|
10
12
|
This gem is a lean, easy to use CLI framework with a very small footprint.
|
11
13
|
It provides an easy to use argument parsing, help displaying and
|
12
14
|
minimalistic error handling.
|
13
15
|
DESC
|
14
|
-
gem.author = 'Mike Blumtritt'
|
15
|
-
gem.homepage = 'https://github.com/mblumtritt/mini-cli'
|
16
|
-
gem.metadata = {
|
17
|
-
'source_code_uri' => 'https://github.com/mblumtritt/mini-cli',
|
18
|
-
'bug_tracker_uri' => 'https://github.com/mblumtritt/mini-cli/issues'
|
19
|
-
}
|
20
16
|
|
21
|
-
|
17
|
+
spec.author = 'Mike Blumtritt'
|
18
|
+
spec.homepage = 'https://github.com/mblumtritt/mini-cli'
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/mblumtritt/mini-cli'
|
20
|
+
spec.metadata['bug_tracker_uri'] =
|
21
|
+
'https://github.com/mblumtritt/mini-cli/issues'
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
spec.add_development_dependency 'bundler'
|
24
|
+
spec.add_development_dependency 'minitest'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
26
|
|
27
|
-
all_files =
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
all_files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
|
28
|
+
spec.test_files = all_files.grep(%r{^(spec|test)/})
|
29
|
+
spec.files = all_files - spec.test_files
|
30
|
+
spec.extra_rdoc_files = %w[README.md]
|
31
31
|
end
|
data/rakefile.rb
CHANGED
@@ -3,13 +3,11 @@
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'bundler/gem_tasks'
|
5
5
|
|
6
|
-
|
6
|
+
$stdout.sync = $stderr.sync = true
|
7
7
|
|
8
|
-
|
8
|
+
task(:default) { exec('rake --tasks') }
|
9
9
|
|
10
|
-
|
11
|
-
exec "#{$PROGRAM_NAME} --tasks"
|
12
|
-
end
|
10
|
+
CLOBBER << 'prj'
|
13
11
|
|
14
12
|
Rake::TestTask.new(:test) do |t|
|
15
13
|
t.ruby_opts = %w[-w]
|
data/samples/custom_args.rb
CHANGED
@@ -14,15 +14,18 @@ HELP
|
|
14
14
|
main { |cfg| cfg.each_pair { |key, value| puts("#{key}: #{value}") } }
|
15
15
|
|
16
16
|
parse_argv do |args|
|
17
|
-
Struct
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
Struct
|
18
|
+
.new(:target, :sources, :name, :url, :switch, :opt)
|
19
|
+
.new
|
20
|
+
.tap do |cfg|
|
21
|
+
cfg.target = args['TARGET']
|
22
|
+
cfg.sources = args['FILES'] # args['FILES'] is an array containing all surplus arguments
|
23
|
+
source = args['SOURCE'] || ENV['SOURCE']
|
24
|
+
cfg.sources.unshift(source) if source
|
25
|
+
cfg.sources << 'STDIN' if cfg.sources.empty?
|
26
|
+
cfg.name = args['NAME'] || 'default_name'
|
27
|
+
cfg.url = args['URL'] || 'www.url.test'
|
28
|
+
cfg.switch = args.key?('switch')
|
29
|
+
cfg.opt = args.key?('opt')
|
30
|
+
end
|
28
31
|
end
|
data/test/apps/noop
ADDED
data/test/apps/sequence
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# demonstrates the call sequence
|
5
|
+
|
6
|
+
require_relative '../../lib/mini-cli'
|
7
|
+
include(MiniCli)
|
8
|
+
|
9
|
+
help <<~HELP
|
10
|
+
-x, --exit early exit
|
11
|
+
-e, --error exit with error
|
12
|
+
HELP
|
13
|
+
|
14
|
+
main do |*args|
|
15
|
+
puts('main' + args.inspect)
|
16
|
+
exit if args.first['exit']
|
17
|
+
error(42, '!error!') if args.first['error']
|
18
|
+
end
|
19
|
+
|
20
|
+
before { |*args| puts('before_1' + args.inspect) }
|
21
|
+
after { |*args| puts('after_1' + args.inspect) }
|
22
|
+
before { |*args| puts('before_2' + args.inspect) }
|
23
|
+
after { |*args| puts('after_2' + args.inspect) }
|
24
|
+
|
25
|
+
parse_argv do |*args|
|
26
|
+
puts('parse_argv' + args.inspect)
|
27
|
+
args.first
|
28
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'shellwords'
|
5
|
+
require_relative '../helper'
|
6
|
+
|
7
|
+
class ExecTest < Minitest::Test
|
8
|
+
parallelize_me!
|
9
|
+
|
10
|
+
def test_noop
|
11
|
+
assert_empty(assert_no_err('noop'))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_noop_help
|
15
|
+
assert_equal("Usage: noop\n", assert_no_err('noop', '--help'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_sequence
|
19
|
+
expected = [
|
20
|
+
'before_1[]',
|
21
|
+
'before_2[]',
|
22
|
+
"parse_argv[{\"FILES\"=>[]}]",
|
23
|
+
"main[{\"FILES\"=>[]}]",
|
24
|
+
'after_2[]',
|
25
|
+
'after_1[]'
|
26
|
+
]
|
27
|
+
assert_equal(expected, assert_no_err('sequence').split("\n"))
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_sequence_help
|
31
|
+
expected = [
|
32
|
+
'Usage: sequence [OPTIONS]',
|
33
|
+
'',
|
34
|
+
'Options:',
|
35
|
+
'-x, --exit early exit',
|
36
|
+
'-e, --error exit with error'
|
37
|
+
]
|
38
|
+
assert_equal(expected, assert_no_err('sequence', '--help').split("\n"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_sequence_early_exit
|
42
|
+
expected = [
|
43
|
+
'before_1[]',
|
44
|
+
'before_2[]',
|
45
|
+
"parse_argv[{\"exit\"=>true, \"FILES\"=>[]}]",
|
46
|
+
"main[{\"exit\"=>true, \"FILES\"=>[]}]",
|
47
|
+
'after_2[]',
|
48
|
+
'after_1[]'
|
49
|
+
]
|
50
|
+
assert_equal(expected, assert_no_err('sequence', '-x').split("\n"))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_sequence_error
|
54
|
+
expected = [
|
55
|
+
'before_1[]',
|
56
|
+
'before_2[]',
|
57
|
+
"parse_argv[{\"error\"=>true, \"FILES\"=>[]}]",
|
58
|
+
"main[{\"error\"=>true, \"FILES\"=>[]}]",
|
59
|
+
'after_2[]',
|
60
|
+
'after_1[]'
|
61
|
+
]
|
62
|
+
std, err, status = invoke('sequence', '-e')
|
63
|
+
assert_same(42, status.exitstatus)
|
64
|
+
assert_equal("sequence: !error!\n", err)
|
65
|
+
assert_equal(expected, std.split("\n"))
|
66
|
+
end
|
67
|
+
|
68
|
+
def assert_no_err(...)
|
69
|
+
std, err = assert_success(...)
|
70
|
+
assert_empty(err)
|
71
|
+
std
|
72
|
+
end
|
73
|
+
|
74
|
+
def assert_success(...)
|
75
|
+
std, err, status = invoke(...)
|
76
|
+
assert(status.success?)
|
77
|
+
return std, err
|
78
|
+
end
|
79
|
+
|
80
|
+
def invoke(name, *args)
|
81
|
+
Open3.capture3(
|
82
|
+
Shellwords.join(
|
83
|
+
[
|
84
|
+
RbConfig.ruby,
|
85
|
+
'--disable',
|
86
|
+
'gems',
|
87
|
+
'--disable',
|
88
|
+
'did_you_mean',
|
89
|
+
'--disable',
|
90
|
+
'rubyopt',
|
91
|
+
File.expand_path("../apps/#{name}", __dir__)
|
92
|
+
] + args
|
93
|
+
)
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
data/test/mini-cli/main_test.rb
CHANGED
@@ -13,7 +13,10 @@ class MainTest < Test
|
|
13
13
|
subject = Class.new { include MiniCli }.new
|
14
14
|
|
15
15
|
expected_methods = %i[
|
16
|
+
after
|
17
|
+
before
|
16
18
|
error
|
19
|
+
error_code
|
17
20
|
help
|
18
21
|
main
|
19
22
|
name
|
@@ -176,4 +179,13 @@ class MainTest < Test
|
|
176
179
|
result = subject.parse_argv(as_argv('-nup name port in out opt file'))
|
177
180
|
assert_equal(expected, result)
|
178
181
|
end
|
182
|
+
|
183
|
+
def test_run
|
184
|
+
call_sequence = []
|
185
|
+
subject.main { call_sequence << :main }
|
186
|
+
subject.before { call_sequence << :start_1 }
|
187
|
+
subject.after { call_sequence << :end_1 }
|
188
|
+
subject.before { call_sequence << :start_2 }
|
189
|
+
subject.after { call_sequence << :end_2 }
|
190
|
+
end
|
179
191
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -74,7 +74,10 @@ files:
|
|
74
74
|
- samples/custom_args.rb
|
75
75
|
- samples/demo.rb
|
76
76
|
- samples/simple.rb
|
77
|
+
- test/apps/noop
|
78
|
+
- test/apps/sequence
|
77
79
|
- test/helper.rb
|
80
|
+
- test/mini-cli/exec_test.rb
|
78
81
|
- test/mini-cli/main_test.rb
|
79
82
|
- test/mini-cli/run_test.rb
|
80
83
|
homepage: https://github.com/mblumtritt/mini-cli
|
@@ -97,11 +100,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
100
|
- !ruby/object:Gem::Version
|
98
101
|
version: '0'
|
99
102
|
requirements: []
|
100
|
-
rubygems_version: 3.
|
103
|
+
rubygems_version: 3.2.9
|
101
104
|
signing_key:
|
102
105
|
specification_version: 4
|
103
106
|
summary: The lean CLI framework for Ruby
|
104
107
|
test_files:
|
108
|
+
- test/apps/noop
|
109
|
+
- test/apps/sequence
|
105
110
|
- test/helper.rb
|
111
|
+
- test/mini-cli/exec_test.rb
|
106
112
|
- test/mini-cli/main_test.rb
|
107
113
|
- test/mini-cli/run_test.rb
|