mini-cli 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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