mini-cli 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3f71b96747e645a7e4ab1131c3e52840f63f22af4035d06b98f2d21172716d9b
4
+ data.tar.gz: a8ec28b1326a313f16ec8986f85a56b60f1b8c9832583324b79fd6a55c6a6228
5
+ SHA512:
6
+ metadata.gz: 72575dc73beedd924a2080b8cb436dcb11b78d9897e4f9eb87836dff6af028845d077c069540b06a5b7b93c6a2719c2de3a53a4e19996476a8c5871332fe97bb
7
+ data.tar.gz: 6848f5981ef7ce5bb4545a015b309f549450796a5d6530f4fd0f56fd3c315e7347da2afa318048facdb077db0eeee21676cd305b5cd17a863cb2037f5323cf32
@@ -0,0 +1,4 @@
1
+ idea/
2
+ tmp/
3
+ pkg/
4
+ gems.locked
@@ -0,0 +1,64 @@
1
+ # Mini Cli
2
+
3
+ This gem is a minimalistic, easy to use CLI framework with a very small footprint. I provides an easy to use argument parsing, help displaying, minimalistic error handling and some tools like executing external programs and gather their output.
4
+
5
+ ## Installation
6
+
7
+ To use Mini CLI just install the gem with
8
+
9
+ ```shell
10
+ gem install mini-cli
11
+ ```
12
+
13
+ or include it to you project's gemspec:
14
+
15
+ ```ruby
16
+ gem 'mini-cli'
17
+ ```
18
+
19
+ ## Sample
20
+
21
+ A very minimalistic program may look like this sample program:
22
+
23
+ ```ruby
24
+ require 'mini-cli'
25
+
26
+ include MiniCli
27
+
28
+ help <<~HELP, %w[TARGET [SOURCE]]
29
+ -n, --name NAME option requires NAME argument, has shortcut
30
+ --url URL option requires URL argument
31
+ -s, --switch option without any argument, has shortcut
32
+ --opt option without any argument
33
+
34
+ This is a sample application only.
35
+ HELP
36
+
37
+ main do |args|
38
+ puts "TARGET: #{args['TARGET']}"
39
+ puts "SOURCE: #{args['SOURCE']}" if args.key?('SOURCE')
40
+ puts "NAME: #{args['NAME']}" if args.key?('NAME')
41
+ puts "URL: #{args['URL']}" if args.key?('URL')
42
+ puts "FILES: #{args['FILES']}" unless args['FILES'].empty?
43
+ puts '--switch was given' if args.key?('switch')
44
+ puts '--opt was given' if args.key?('opt')
45
+ end
46
+ ```
47
+
48
+ The sample uses the powerful `#help` method to generate an argument parser which handles the command line for you. You only need to handle the given `Hash` parameter (named `args` in the sample) in the body of your `#main` block.
49
+
50
+ Executing the sample with `--help` or `-h` will provide following help screen:
51
+
52
+ ```
53
+ Usage: sample [OPTIONS] TARGET [SOURCE]
54
+
55
+ Valid Options:
56
+ -n, --name NAME option requires NAME argument, has shortcut
57
+ --url URL option requires URL argument
58
+ -s, --switch option without any argument, has shortcut
59
+ --opt option without any argument
60
+
61
+ This is a sample application only.
62
+ ```
63
+
64
+ See the `./samples` directory for more sample programs…
data/gems.rb ADDED
@@ -0,0 +1 @@
1
+ gemspec
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniCli
4
+ def self.included(_)
5
+ return if const_defined?(:SRC)
6
+ const_set(:SRC, caller_locations(1, 1).first.absolute_path)
7
+ end
8
+
9
+ def name(name = nil)
10
+ return name ? @__name = name : @__name if defined?(@__name)
11
+ @__name = name || File.basename(MiniCli::SRC, '.*')
12
+ end
13
+
14
+ def help(helptext, *args)
15
+ @__argv_parser = ArgvParser.new(helptext, args)
16
+ end
17
+
18
+ def show_help
19
+ __argv_parser.show_help(name)
20
+ true
21
+ end
22
+
23
+ def error(code, message)
24
+ $stderr.puts("#{name}: #{message}")
25
+ exit(code)
26
+ end
27
+
28
+ def parse_argv(argv = nil, &block)
29
+ return @__argv_converter = block if block
30
+ argv ||= ARGV.dup
31
+ exit(show_help) if argv.index('--help') || argv.index('-h')
32
+ args = __argv_parser.parse(argv, method(:error).to_proc)
33
+ defined?(@__argv_converter) ? @__argv_converter.call(args) || args : args
34
+ end
35
+
36
+ def main(args = nil)
37
+ at_exit do
38
+ yield(args || parse_argv)
39
+ rescue Interrupt
40
+ error(130, 'aborted')
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def __argv_parser
47
+ @__argv_parser ||= ArgvParser.new(nil, [])
48
+ end
49
+
50
+ class ArgvParser
51
+ def initialize(helptext, args)
52
+ @helptext = helptext.to_s
53
+ @args = args.flatten.map!(&:to_s).uniq
54
+ @options = nil
55
+ end
56
+
57
+ def show_help(name)
58
+ parse_help! unless @options
59
+ print("Usage: #{name}")
60
+ print(' [OPTIONS]') unless @options.empty?
61
+ print(' ', @args.join(' ')) unless @args.empty?
62
+ puts
63
+ puts(nil, 'Valid Options:') unless @options.empty?
64
+ puts(@helptext) unless @helptext.empty?
65
+ end
66
+
67
+ def parse(argv, error)
68
+ @error = error
69
+ parse_help! unless @options
70
+ @result, arguments = {}, []
71
+ loop do
72
+ case arg = argv.shift
73
+ when nil
74
+ break
75
+ when '--'
76
+ arguments += argv
77
+ break
78
+ when /\A--([[[:alnum:]]-]+)\z/
79
+ handle_option(Regexp.last_match[1], argv)
80
+ when /\A-([[:alnum:]]+)\z/
81
+ parse_options(Regexp.last_match[1], argv)
82
+ else
83
+ arguments << arg
84
+ end
85
+ end
86
+ process(arguments)
87
+ end
88
+
89
+ private
90
+
91
+ def error(msg)
92
+ @error.call(1, msg)
93
+ end
94
+
95
+ def process(arguments)
96
+ @args.each do |arg|
97
+ next if arg.index('..')
98
+ value = arguments.shift
99
+ if arg.start_with?('[')
100
+ @result[arg[1..-2]] = value if value
101
+ else
102
+ @result[arg] = value || error("parameter expected - #{arg}")
103
+ end
104
+ end
105
+ arguments.unshift(@result['FILES']) if @result.key?('FILES')
106
+ @result['FILES'] = arguments
107
+ @result
108
+ end
109
+
110
+ def handle_option(option, argv)
111
+ key = @options[option] || error("unknown option - #{option}")
112
+ return @result[key] = true if option == key
113
+ @result[key] = value = argv.shift
114
+ return unless value.nil? || value.start_with?('-')
115
+ error("parameter #{key} expected - --#{option}")
116
+ end
117
+
118
+ def parse_options(options, argv)
119
+ options.each_char do |opt|
120
+ key = @options[opt] || error("unknown option - #{opt}")
121
+ next @result[key] = true if key == key.downcase
122
+ @result[key] = value = argv.shift
123
+ next unless value.nil? || value.start_with?('-')
124
+ error("parameter #{key} expected - -#{opt}")
125
+ end
126
+ end
127
+
128
+ def parse_help!
129
+ @options = {}
130
+ @helptext.each_line do |line|
131
+ case line
132
+ when /-([[:alnum:]]), --([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
133
+ named_option(Regexp.last_match)
134
+ when /--([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
135
+ named_option_short(Regexp.last_match)
136
+ when /-([[:alnum:]]), --([[[:alnum:]]-]+)\s+\S+/
137
+ option(Regexp.last_match)
138
+ when /--([[[:alnum:]]-]+)\s+\S+/
139
+ option_short(Regexp.last_match)
140
+ end
141
+ end
142
+ end
143
+
144
+ def named_option(match)
145
+ @options[match[1]] = @options[match[2]] = match[3]
146
+ end
147
+
148
+ def named_option_short(match)
149
+ @options[match[1]] = match[2]
150
+ end
151
+
152
+ def option(match)
153
+ @options[match[1]] = @options[match[2]] = match[2]
154
+ end
155
+
156
+ def option_short(match)
157
+ @options[match[1]] = match[1]
158
+ end
159
+ end
160
+
161
+ private_constant(:ArgvParser)
162
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module MiniCli
6
+ def run(*cmd)
7
+ opts = Hash === cmd.last ? __run_opt(cmd.last) : [:stdout]
8
+ opts.delete(:stderr) ? __run3(opts, cmd) : __run2(opts, cmd)
9
+ rescue SystemCallError
10
+ nil
11
+ end
12
+
13
+ private
14
+
15
+ def __run3(opts, cmd)
16
+ result = Open3.capture3(*cmd)
17
+ result.shift unless opts.first == :stdout
18
+ result.pop unless opts.last == :status
19
+ result.size == 1 ? result.first : result
20
+ end
21
+
22
+ def __run2(opts, cmd)
23
+ result = Open3.capture2e(*cmd)
24
+ return result.last.success? if opts.empty?
25
+ return result if opts.size == 2
26
+ opts.first == :status ? result.last : result.first
27
+ end
28
+
29
+ def __run_opt(opts)
30
+ %i[stdout stderr status].keep_if{ |s| opts.delete(s) }
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniCli
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './lib/mini-cli/version'
4
+
5
+ GemSpec = Gem::Specification.new do |gem|
6
+ gem.name = 'mini-cli'
7
+ gem.version = MiniCli::VERSION
8
+ gem.summary = 'The minimalistic CLI framework for Ruby'
9
+ gem.description = <<~DESC
10
+ This gem is a minimalistic, easy to use CLI framework with a very small
11
+ footprint. I provides an easy to use argument parsing, help displaying and
12
+ minimalistic error handling.
13
+ 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
+
21
+ gem.required_ruby_version = '>= 2.5.0'
22
+
23
+ gem.add_development_dependency 'bundler'
24
+ gem.add_development_dependency 'minitest'
25
+ gem.add_development_dependency 'rake'
26
+
27
+ all_files = %x(git ls-files -z).split(0.chr)
28
+ gem.test_files = all_files.grep(%r{^(spec|test)/})
29
+ gem.files = all_files - gem.test_files
30
+ # gem.extra_rdoc_files = %w[README.MD]
31
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/testtask'
4
+ require 'bundler/gem_tasks'
5
+
6
+ STDOUT.sync = STDERR.sync = true
7
+
8
+ CLOBBER << 'prj'
9
+
10
+ task :default do
11
+ exec "#{$PROGRAM_NAME} --tasks"
12
+ end
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.ruby_opts = %w[-w]
16
+ t.verbose = true
17
+ t.test_files = FileList['test/**/*_test.rb']
18
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/mini-cli'
4
+
5
+ include MiniCli
6
+
7
+ help <<~HELP, %w[TARGET [SOURCE]]
8
+ -n, --name NAME option requires NAME argument, has shortcut
9
+ --url URL option requires URL argument
10
+ -s, --switch option without any argument, has shortcut
11
+ --opt option without any argument
12
+ HELP
13
+
14
+ main do |cfg|
15
+ cfg.each_pair{ |key, value| puts("#{key}: #{value}") }
16
+ end
17
+
18
+ parse_argv do |args|
19
+ Struct.new(:target, :sources, :name, :url, :switch, :opt).new.tap do |cfg|
20
+ cfg.target = args['TARGET']
21
+ # args['FILES'] is an array containing all surplus arguments
22
+ cfg.sources = args['FILES']
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
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/mini-cli'
4
+
5
+ include MiniCli
6
+
7
+ help <<~HELP, %w[TARGET [SOURCE]]
8
+ -n, --name NAME option requires NAME argument, has shortcut
9
+ --url URL option requires URL argument
10
+ -s, --switch option without any argument, has shortcut
11
+ --opt option without any argument
12
+ HELP
13
+
14
+ main do |args|
15
+ puts("TARGET: #{args['TARGET']}")
16
+ puts("SOURCE: #{args['SOURCE']}") if args.key?('SOURCE')
17
+ puts("NAME: #{args['NAME']}") if args.key?('NAME')
18
+ puts("URL: #{args['URL']}") if args.key?('URL')
19
+ puts("FILES: #{args['FILES']}") unless args['FILES'].empty?
20
+ puts('--switch was given') if args.key?('switch')
21
+ puts('--opt was given') if args.key?('opt')
22
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/mini-cli'
4
+
5
+ include MiniCli
6
+
7
+ help <<~HELP
8
+
9
+ This is a very simple sample without any required parameter.
10
+ HELP
11
+
12
+ main do |args|
13
+ puts("given files: #{args['FILES']}")
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/parallel'
5
+
6
+ require_relative '../lib/mini-cli'
7
+ require_relative '../lib/mini-cli/run'
8
+
9
+ class Test < Minitest::Test
10
+ parallelize_me!
11
+ attr_reader :subject
12
+
13
+ def setup
14
+ @subject = Class.new do
15
+ include MiniCli
16
+ attr_reader :exit_args
17
+
18
+ def exit(*args)
19
+ @exit_args = args
20
+ end
21
+ end.new
22
+ end
23
+
24
+ def assert_stop_with_error(code, text, &block)
25
+ assert_output(nil, "helper: #{text}\n", &block)
26
+ assert_equal([code], subject.exit_args)
27
+ end
28
+
29
+ def as_argv(str)
30
+ str.split(' ')
31
+ end
32
+ end
@@ -0,0 +1,178 @@
1
+ require_relative '../helper'
2
+
3
+ class MainTest < Test
4
+ def test_defaults
5
+ assert_equal('helper', subject.name)
6
+ assert_output("Usage: helper\n"){ subject.show_help }
7
+ end
8
+
9
+ def test_methods
10
+ subject = Class.new{ include MiniCli }.new
11
+
12
+ expected_methods = %i[
13
+ error
14
+ help
15
+ main
16
+ name
17
+ parse_argv
18
+ run
19
+ show_help
20
+ ].sort!
21
+ methods = (subject.methods - Object.new.methods).sort!
22
+ assert_equal(expected_methods, methods)
23
+ end
24
+
25
+ def test_error
26
+ assert_stop_with_error(42, 'some error text') do
27
+ subject.error(42, 'some error text')
28
+ end
29
+
30
+ assert_stop_with_error(21, 'error') do
31
+ subject.error(21, :error)
32
+ end
33
+ end
34
+
35
+ def test_help_simple
36
+ subject.help 'Some helptext'
37
+ expected_text = <<~EXPECTED
38
+ Usage: helper
39
+ Some helptext
40
+ EXPECTED
41
+
42
+ assert_output(expected_text){ subject.show_help }
43
+ end
44
+
45
+ def test_help_with_args
46
+ subject.help <<~HELP, 'ARG1', :ARG2
47
+ Some helptext comes
48
+ here
49
+ HELP
50
+
51
+ expected_text = <<~EXPECTED
52
+ Usage: helper ARG1 ARG2
53
+ Some helptext comes
54
+ here
55
+ EXPECTED
56
+
57
+ assert_output(expected_text){ subject.show_help }
58
+ end
59
+
60
+ def test_argument_required
61
+ subject.help :text, :ARG
62
+
63
+ assert_stop_with_error(1, 'parameter expected - ARG') do
64
+ subject.parse_argv(as_argv(''))
65
+ end
66
+
67
+ expected = {'ARG' => 'arg', 'FILES' => []}
68
+ assert_equal(expected, subject.parse_argv(as_argv('arg')))
69
+
70
+ expected = {'ARG' => 'arg1', 'FILES' => %w[arg2 arg3]}
71
+ assert_equal(expected, subject.parse_argv(as_argv('arg1 arg2 arg3')))
72
+ end
73
+
74
+ def test_name
75
+ subject.name 'test-42'
76
+ assert_equal('test-42', subject.name)
77
+ end
78
+
79
+ def test_argument_optional
80
+ subject.help :text, 'ARG1', '[ARG2]'
81
+
82
+ assert_stop_with_error(1, 'parameter expected - ARG1') do
83
+ subject.parse_argv(as_argv(''))
84
+ end
85
+
86
+ expected = {'ARG1' => 'arg1', 'ARG2' => 'arg2', 'FILES' => []}
87
+ assert_equal(expected, subject.parse_argv(as_argv('arg1 arg2')))
88
+
89
+ expected = {'ARG1' => 'arg', 'FILES' => []}
90
+ assert_equal(expected, subject.parse_argv(as_argv('arg')))
91
+ end
92
+
93
+ def test_options
94
+ subject.help <<~HELP
95
+ -n, --named NAME option NAME with shortcut
96
+ --named-long LNAME option LNAME without shortcut
97
+ -u, --unnamed option unnamed with shortcut
98
+ --un-named option un-named without shortcut
99
+
100
+ Some additional explaination can be here
101
+ HELP
102
+
103
+ expected = {'FILES' => []}
104
+ assert_equal(expected, subject.parse_argv(as_argv('')))
105
+
106
+ expected = {'NAME' => 'name', 'FILES' => []}
107
+ assert_equal(expected, subject.parse_argv(as_argv('--named name')))
108
+ assert_equal(expected, subject.parse_argv(as_argv('-n name')))
109
+
110
+ expected = {'LNAME' => 'long', 'FILES' => []}
111
+ assert_equal(expected, subject.parse_argv(as_argv('--named-long long')))
112
+
113
+ expected = {'unnamed' => true, 'FILES' => []}
114
+ assert_equal(expected, subject.parse_argv(as_argv('--unnamed')))
115
+ assert_equal(expected, subject.parse_argv(as_argv('-u')))
116
+
117
+ expected = {'un-named' => true, 'FILES' => []}
118
+ assert_equal(expected, subject.parse_argv(as_argv('--un-named')))
119
+
120
+ expected = {
121
+ 'NAME' => 'name',
122
+ 'LNAME' => 'long',
123
+ 'unnamed' => true,
124
+ 'un-named' => true,
125
+ 'FILES' => %w[FILE1 FILE2]
126
+ }
127
+
128
+ result = subject.parse_argv(%w[
129
+ --named name
130
+ --named-long long
131
+ --unnamed
132
+ --un-named
133
+ FILE1
134
+ FILE2
135
+ ])
136
+ assert_equal(expected, result)
137
+
138
+ result = subject.parse_argv(%w[
139
+ -nu name
140
+ --named-long long
141
+ --un-named
142
+ FILE1
143
+ FILE2
144
+ ])
145
+ assert_equal(expected, result)
146
+ end
147
+
148
+ def test_complex_options
149
+ subject.help <<~HELP, %w[INFILE OUTFILE [OPTFILE]]
150
+ -n, --named NAME key 'NAME'
151
+ -p, --port PORT key 'PORT'
152
+ -u, --un-named key 'unnamed'
153
+ HELP
154
+
155
+ expected = {
156
+ 'INFILE' => 'in',
157
+ 'OUTFILE' => 'out',
158
+ 'NAME' => 'name',
159
+ 'PORT' => 'port',
160
+ 'un-named' => true,
161
+ 'FILES' => []
162
+ }
163
+ result = subject.parse_argv(as_argv('-nup name port in out'))
164
+ assert_equal(expected, result)
165
+
166
+ expected = {
167
+ 'INFILE' => 'in',
168
+ 'OUTFILE' => 'out',
169
+ 'OPTFILE' => 'opt',
170
+ 'NAME' => 'name',
171
+ 'PORT' => 'port',
172
+ 'un-named' => true,
173
+ 'FILES' => %w[file]
174
+ }
175
+ result = subject.parse_argv(as_argv('-nup name port in out opt file'))
176
+ assert_equal(expected, result)
177
+ end
178
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../helper'
2
+
3
+ class RunTest < Test
4
+ def setup
5
+ super
6
+ @pwd = Dir.pwd + "\n"
7
+ end
8
+
9
+ def test_std_out_only
10
+ out = subject.run('pwd')
11
+ assert_equal(@pwd, out)
12
+
13
+ out = subject.run('pwd', stdout: true)
14
+ assert_equal(@pwd, out)
15
+ end
16
+
17
+ def test_status
18
+ result = subject.run('pwd', stdout: false)
19
+ assert_instance_of(TrueClass, result)
20
+
21
+ status = subject.run('pwd', status: true)
22
+ assert_instance_of(Process::Status, status)
23
+
24
+ out, status = subject.run('pwd', stdout: true, status: true)
25
+ assert_equal(@pwd, out)
26
+ assert_instance_of(Process::Status, status)
27
+ assert(status.success?)
28
+ end
29
+
30
+ def test_std_error
31
+ err = subject.run('ls /no-valid-dir', stderr: true)
32
+ assert_match(/No such file or directory/, err)
33
+
34
+ out, err = subject.run('ls /no-valid-dir', stdout: true, stderr: true)
35
+ assert_empty(out)
36
+ assert_match(/No such file or directory/, err)
37
+
38
+ err, status = subject.run('ls /no-valid-dir', stderr: true, status: true)
39
+ assert_match(/No such file or directory/, err)
40
+ assert_instance_of(Process::Status, status)
41
+ refute(status.success?)
42
+ end
43
+
44
+ def test_failure
45
+ result = subject.run('this-is-not-a-valid-command')
46
+ assert_instance_of(NilClass, result)
47
+ end
48
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mini-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mike Blumtritt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: |
56
+ This gem is a minimalistic, easy to use CLI framework with a very small
57
+ footprint. I provides an easy to use argument parsing, help displaying and
58
+ minimalistic error handling.
59
+ email:
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - README.md
66
+ - gems.rb
67
+ - lib/mini-cli.rb
68
+ - lib/mini-cli/run.rb
69
+ - lib/mini-cli/version.rb
70
+ - mini-cli.gemspec
71
+ - rakefile.rb
72
+ - samples/custom_args.rb
73
+ - samples/demo.rb
74
+ - samples/simple.rb
75
+ - test/helper.rb
76
+ - test/mini-cli/main_test.rb
77
+ - test/mini-cli/run_test.rb
78
+ homepage: https://github.com/mblumtritt/mini-cli
79
+ licenses: []
80
+ metadata:
81
+ source_code_uri: https://github.com/mblumtritt/mini-cli
82
+ bug_tracker_uri: https://github.com/mblumtritt/mini-cli/issues
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 2.5.0
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubygems_version: 3.1.2
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: The minimalistic CLI framework for Ruby
102
+ test_files:
103
+ - test/helper.rb
104
+ - test/mini-cli/main_test.rb
105
+ - test/mini-cli/run_test.rb