mini-cli 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86629e6e4c057eaa03c51483b6931c35517b9753ebdafa2f7b459e494be8b682
4
- data.tar.gz: e16f2d52c65a4a84b7e9f631915b2d161c9e13c2d038695c0a7b764280f862c5
3
+ metadata.gz: 6954edd798ee19570124490d3c139443e54cf9db86da1cbf5e1ecf053f5b4de6
4
+ data.tar.gz: e9c458ab08eb813875df22053ce3c5fd99c651bbe24f60d787a6d0968936d204
5
5
  SHA512:
6
- metadata.gz: ef6755a1c1dfdca0313daac675704265c4b35a9a44cad752ef859435abbc69b71ff0350796b86963b1b1038aa03ee609fe85a3e2063ce4b3d1d2d72efc505aea
7
- data.tar.gz: b5d68657a09c053b5311a4cf5427a779e374a483142df5ca0704ad4121c4138e506ef508be97261d1bc97bf90111a4abd876b457cf0d747e38cf178bc40b4045
6
+ metadata.gz: ad9884fa0f18600b69212a8f3b3c36108838d510879cde3d2a4525009439a3574c8eae1d7d7d4b567647fce04aa5cfaeee3fdceec8529381defc2533c1166559
7
+ data.tar.gz: 287198992331abcd2fee44165775cad3a6905c15eb1fac71bee380d706ba5f2067b3b2d3498f9a7bc4f07fe92c447e417c854313b247f0b81db304f0810a582b
@@ -1,36 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniCli
4
- def self.included(_)
5
- return if const_defined?(:SRC)
6
- const_set(:SRC, caller_locations(1, 1).first.absolute_path)
4
+ def self.included(mod)
5
+ source = caller_locations(1, 1).first.absolute_path
6
+ mod.const_set(:MiniCli__, Instance.new(source))
7
7
  end
8
8
 
9
9
  def name(name = nil)
10
- return name ? @__name = name : @__name if defined?(@__name)
11
- @__name = name || File.basename(MiniCli::SRC, '.*')
10
+ __minicli__.name(name)
12
11
  end
13
12
 
14
13
  def help(helptext, *args)
15
- @__argv_parser = ArgvParser.new(helptext, args)
14
+ __minicli__.help(helptext, args)
16
15
  end
17
16
 
18
17
  def show_help
19
- __argv_parser.show_help(name)
20
- true
18
+ __minicli__.show_help
21
19
  end
22
20
 
23
- def error(code, message)
24
- $stderr.puts("#{name}: #{message}")
21
+ def show_errors?
22
+ __minicli__.show_errors
23
+ end
24
+
25
+ def show_errors=(value)
26
+ __minicli__.show_errors = value ? true : false
27
+ end
28
+
29
+ def error(code, message = nil)
30
+ $stderr.puts("#{name}: #{message}") if message && show_errors?
25
31
  exit(code)
26
32
  end
27
33
 
28
34
  def parse_argv(argv = nil, &argv_converter)
29
- return @__argv_converter = argv_converter if argv_converter
35
+ return __minicli__.converter = argv_converter if argv_converter
30
36
  argv ||= ARGV.dup
31
37
  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
38
+ __minicli__.convert(__minicli__.parse(argv, method(:error).to_proc))
34
39
  end
35
40
 
36
41
  def main(args = nil)
@@ -43,121 +48,159 @@ module MiniCli
43
48
 
44
49
  private
45
50
 
46
- def __argv_parser
47
- @__argv_parser ||= ArgvParser.new(nil, [])
51
+ def __minicli__
52
+ self.class::MiniCli__
48
53
  end
49
54
 
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
+ class Instance
56
+ attr_reader :source
57
+ attr_writer :converter
58
+ attr_accessor :show_errors
59
+
60
+ def initialize(source)
61
+ @source = source
62
+ @name = File.basename(source, '.*')
63
+ @parser = @converter = nil
64
+ @show_errors = true
55
65
  end
56
66
 
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?
67
+ def name(name = nil)
68
+ name ? @name = name.to_s : @name
69
+ end
70
+
71
+ def help(helptext, args)
72
+ @parser = ArgvParser.new(helptext, args)
73
+ end
74
+
75
+ def show_help
76
+ parser.show_help(@name)
77
+ true
65
78
  end
66
79
 
67
80
  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)
81
+ parser.parse(argv, error)
82
+ end
83
+
84
+ def convert(args)
85
+ @converter ? @converter.call(args) || args : args
87
86
  end
88
87
 
89
88
  private
90
89
 
91
- def error(msg)
92
- @error.call(1, msg)
90
+ def parser
91
+ @parser ||= ArgvParser.new(nil, [])
93
92
  end
94
93
 
95
- def process(arguments)
96
- @args.each do |arg|
97
- next if arg.index('..')
98
- value = arguments.shift
94
+ class ArgvParser
95
+ def initialize(helptext, args)
96
+ @helptext = helptext.to_s
97
+ @args = args.flatten.map!(&:to_s).uniq
98
+ @options = nil
99
+ end
100
+
101
+ def show_help(name)
102
+ parse_help! unless @options
103
+ print("Usage: #{name}")
104
+ print(' [OPTIONS]') unless @options.empty?
105
+ print(' ', @args.join(' ')) unless @args.empty?
106
+ puts
107
+ puts(nil, 'Options:') unless @options.empty?
108
+ puts(@helptext) unless @helptext.empty?
109
+ end
110
+
111
+ def parse(argv, error)
112
+ @error, @result = error, {}
113
+ parse_help! unless @options
114
+ process(parse_argv(argv))
115
+ end
99
116
 
117
+ private
118
+
119
+ def parse_argv(argv)
120
+ arguments = []
121
+ while (arg = argv.shift)
122
+ case arg
123
+ when '--'
124
+ arguments += argv
125
+ break
126
+ when /\A--([[[:alnum:]]-]+)\z/
127
+ handle_option(Regexp.last_match[1], argv)
128
+ when /\A-([[:alnum:]]+)\z/
129
+ parse_options(Regexp.last_match[1], argv)
130
+ else
131
+ arguments << arg
132
+ end
133
+ end
134
+ arguments
135
+ end
136
+
137
+ def error(msg)
138
+ @error[1, msg]
139
+ end
140
+
141
+ def process(arguments)
142
+ @args.each do |arg|
143
+ process_arg(arg, arguments.shift) unless arg.index('..')
144
+ end
145
+ arguments.unshift(@result['FILES']) if @result.key?('FILES')
146
+ @result['FILES'] = arguments
147
+ @result
148
+ end
149
+
150
+ def process_arg(arg, value)
100
151
  if arg.start_with?('[')
101
152
  @result[arg[1..-2]] = value if value
102
153
  else
103
154
  @result[arg] = value || error("parameter expected - #{arg}")
104
155
  end
105
156
  end
106
- arguments.unshift(@result['FILES']) if @result.key?('FILES')
107
- @result['FILES'] = arguments
108
- @result
109
- end
110
157
 
111
- def handle_option(option, argv)
112
- key = @options[option] || error("unknown option - #{option}")
113
- return @result[key] = true if option == key
114
- @result[key] = value = argv.shift
115
- return unless value.nil? || value.start_with?('-')
116
- error("parameter #{key} expected - --#{option}")
117
- end
118
-
119
- def parse_options(options, argv)
120
- options.each_char do |opt|
121
- key = @options[opt] || error("unknown option - #{opt}")
122
- next @result[key] = true if key == key.downcase
158
+ def handle_option(option, argv, test = ->(k) { option == k })
159
+ key = @options[option] || error("unknown option - #{option}")
160
+ @result[key] = test[key] and return
123
161
  @result[key] = value = argv.shift
124
- next unless value.nil? || value.start_with?('-')
125
- error("parameter #{key} expected - -#{opt}")
162
+ return unless value.nil? || value.start_with?('-')
163
+ error("parameter #{key} expected - --#{option}")
126
164
  end
127
- end
128
165
 
129
- def parse_help!
130
- @options = {}
131
- @helptext.each_line do |line|
132
- case line
133
- when /-([[:alnum:]]), --([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
134
- named_option(Regexp.last_match)
135
- when /--([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
136
- named_short_option(Regexp.last_match)
137
- when /-([[:alnum:]]), --([[[:alnum:]]-]+)\s+\S+/
138
- option(Regexp.last_match)
139
- when /--([[[:alnum:]]-]+)\s+\S+/
140
- short_option(Regexp.last_match)
166
+ def parse_options(options, argv)
167
+ test = ->(k) { k == k.downcase }
168
+ options.each_char { |opt| handle_option(opt, argv, test) }
169
+ end
170
+
171
+ def parse_help!
172
+ @options = {}
173
+ @helptext.each_line do |line|
174
+ case line
175
+ when /-([[:alnum:]]), --([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
176
+ option_with_argument(Regexp.last_match)
177
+ when /--([[[:alnum:]]-]+) ([[:upper:]]+)\s+\S+/
178
+ short_option_with_argument(Regexp.last_match)
179
+ when /-([[:alnum:]]), --([[[:alnum:]]-]+)\s+\S+/
180
+ option(Regexp.last_match)
181
+ when /--([[[:alnum:]]-]+)\s+\S+/
182
+ short_option(Regexp.last_match)
183
+ end
141
184
  end
142
185
  end
143
- end
144
186
 
145
- def named_option(match)
146
- @options[match[1]] = @options[match[2]] = match[3]
147
- end
187
+ def option_with_argument(match)
188
+ @options[match[1]] = @options[match[2]] = match[3]
189
+ end
148
190
 
149
- def named_short_option(match)
150
- @options[match[1]] = match[2]
151
- end
191
+ def short_option_with_argument(match)
192
+ @options[match[1]] = match[2]
193
+ end
152
194
 
153
- def option(match)
154
- @options[match[1]] = @options[match[2]] = match[2]
155
- end
195
+ def option(match)
196
+ @options[match[1]] = @options[match[2]] = match[2]
197
+ end
156
198
 
157
- def short_option(match)
158
- @options[match[1]] = match[1]
199
+ def short_option(match)
200
+ @options[match[1]] = match[1]
201
+ end
159
202
  end
160
203
  end
161
204
 
162
- private_constant(:ArgvParser)
205
+ private_constant(:Instance)
163
206
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniCli
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -0,0 +1 @@
1
+ require_relative 'mini-cli'
@@ -1,16 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../helper'
2
4
 
3
5
  class MainTest < Test
4
6
  def test_defaults
5
7
  assert_equal('helper', subject.name)
8
+ assert(subject.show_errors?)
6
9
  assert_output("Usage: helper\n") { subject.show_help }
7
10
  end
8
11
 
9
12
  def test_methods
10
13
  subject = Class.new { include MiniCli }.new
11
14
 
12
- expected_methods = %i[error help main name parse_argv run show_help].sort!
13
- methods = (subject.methods - Object.new.methods).sort!
15
+ expected_methods = %i[
16
+ error
17
+ help
18
+ main
19
+ name
20
+ parse_argv
21
+ run
22
+ show_errors=
23
+ show_errors?
24
+ show_help
25
+ ]
26
+ methods = (subject.methods - Object.instance_methods).sort!
14
27
  assert_equal(expected_methods, methods)
15
28
  end
16
29
 
@@ -22,6 +35,13 @@ class MainTest < Test
22
35
  assert_stop_with_error(21, 'error') { subject.error(21, :error) }
23
36
  end
24
37
 
38
+ def test_no_error
39
+ subject.show_errors = false
40
+
41
+ assert_output(nil, nil) { subject.error(666, 'some error text') }
42
+ assert_equal([666], subject.exit_args)
43
+ end
44
+
25
45
  def test_help_simple
26
46
  subject.help 'Some helptext'
27
47
  expected_text = <<~EXPECTED
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../helper'
2
4
 
3
5
  class RunTest < Test
4
6
  def test_simple
5
7
  result = subject.run('pwd')
6
- assert_equal(Dir.pwd + "\n", result)
8
+ assert_equal("#{Dir.pwd}\n", result)
7
9
  end
8
10
 
9
11
  def test_simple_error
@@ -15,14 +17,14 @@ class RunTest < Test
15
17
  home = Dir.home
16
18
  refute(home == Dir.pwd)
17
19
  result = subject.run('pwd', chdir: home)
18
- assert_equal(home + "\n", result)
20
+ assert_equal("#{home}\n", result)
19
21
  end
20
22
 
21
23
  def test_status
22
24
  status, result = subject.run('pwd', status: true)
23
25
  assert_instance_of(Process::Status, status)
24
26
  assert(status.success?)
25
- assert_equal(Dir.pwd + "\n", result)
27
+ assert_equal("#{Dir.pwd}\n", result)
26
28
  end
27
29
 
28
30
  def test_status_error
@@ -39,7 +41,7 @@ class RunTest < Test
39
41
  end
40
42
 
41
43
  def test_stdin_stream
42
- stream = StringIO.new("Hello World")
44
+ stream = StringIO.new('Hello World')
43
45
  result = subject.run('cat', stdin_data: stream)
44
46
  assert_equal(stream.string, result)
45
47
  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.2.0
4
+ version: 0.3.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: 2020-10-25 00:00:00.000000000 Z
11
+ date: 2020-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -68,6 +68,7 @@ files:
68
68
  - lib/mini-cli.rb
69
69
  - lib/mini-cli/run.rb
70
70
  - lib/mini-cli/version.rb
71
+ - lib/mini_cli.rb
71
72
  - mini-cli.gemspec
72
73
  - rakefile.rb
73
74
  - samples/custom_args.rb