help_parser 7.0.200907 → 8.1.221206
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -32
- data/lib/help_parser/completion.rb +22 -10
- data/lib/help_parser/constants.rb +17 -3
- data/lib/help_parser/k2t2r.rb +7 -2
- data/lib/help_parser/macros.rb +12 -28
- data/lib/help_parser/options.rb +18 -10
- data/lib/help_parser/parseh.rb +15 -12
- data/lib/help_parser/parseu.rb +4 -0
- data/lib/help_parser/{validations.rb → validate.rb} +21 -18
- data/lib/help_parser.rb +12 -22
- metadata +9 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 157ae793a16a5b92ca1633306080465fcd2e9671aaed67dc01fb47cb318f0824
|
4
|
+
data.tar.gz: cc72ed9f03c94ef2f5455897807a49ba69e79786ceae5daa3d158d3265e9a931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aea35622e25f8fd0cf84cc3115ce15b524440e698f516ebbd89188fa56d30c098dcc8711d61cee4b07aa7b77f935091222c2b0ff71465480d0e9cf76530810f5
|
7
|
+
data.tar.gz: 88a2613d9487be0b11e0da90bef805abc5fc1a7ca0012a97b32d5aa62540f382cc91e38b6714e4279bdba319475b323126625b4cf092e037742f30ba1c4ee22a
|
data/README.md
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
-
# Help Parser
|
1
|
+
# Help Parser VIII: Helpland
|
2
2
|
|
3
|
-
* [VERSION
|
4
|
-
* [github](https://www.github.com/carlosjhr64/
|
3
|
+
* [VERSION 8.1.221206](https://github.com/carlosjhr64/help_parser/releases)
|
4
|
+
* [github](https://www.github.com/carlosjhr64/help_parser)
|
5
5
|
* [rubygems](https://rubygems.org/gems/help_parser)
|
6
6
|
|
7
7
|
## DESCRIPTION:
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
Welcome to Help Parser!
|
10
|
+
Do you have your help text?
|
11
|
+
Let's parse!
|
11
12
|
|
12
|
-
|
13
|
+
## INSTALL:
|
14
|
+
|
15
|
+
```console
|
16
|
+
$ gem install help_parser
|
17
|
+
```
|
13
18
|
|
14
19
|
## SYNOPSIS:
|
15
20
|
<!-- The following PREVIEW has been approved for ALL PROGRAMMERS by CarlosJHR64.
|
16
21
|
For the README validator that checks against me lying....
|
17
22
|
```ruby
|
18
|
-
unless File.basename($PROGRAM_NAME) == '
|
23
|
+
unless File.basename($PROGRAM_NAME) == 'party'
|
19
24
|
# For example's sake say
|
20
|
-
$PROGRAM_NAME = '
|
25
|
+
$PROGRAM_NAME = 'party'
|
21
26
|
# and ARGV is
|
22
|
-
ARGV.concat ["-\-age", "-\-date=2020-09-07", '
|
27
|
+
ARGV.concat ["-\-age", "-\-date=2020-09-07", 'touch', 'that']
|
23
28
|
# and proceed as if run as:
|
24
29
|
# awesome -\-name=Doe -\-value a b c
|
25
30
|
end
|
@@ -28,34 +33,35 @@ The following gem has been rated
|
|
28
33
|
| M | Mature |
|
29
34
|
-->
|
30
35
|
|
31
|
-
> Who ever you are, you were meant to find me today...
|
32
|
-
> there is no turning back!
|
33
|
-
> Above all, don't invoke the command!
|
34
|
-
|
35
36
|
```ruby
|
36
37
|
require "help_parser"
|
37
38
|
|
38
39
|
HELP = <<-HELP
|
39
40
|
# <= Hash here, parser skips
|
40
|
-
# HelpParser:
|
41
|
+
# HelpParser: Party command example #
|
41
42
|
Usage:
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
party :options+ [<args>+]
|
44
|
+
party [:alternate] <arg=FLOAT>
|
45
|
+
party literal <arg1=WORD> <arg2=WORD>
|
45
46
|
Options:
|
46
47
|
-v --version \t Give version and quit
|
47
48
|
-h --help \t Give help and quit
|
48
49
|
-s --long \t Short long synonyms
|
49
|
-
--
|
50
|
+
--touch that \t Defaulted
|
50
51
|
--date=DATE \t Typed
|
51
52
|
--age=INTEGER 80 \t Typed and Defaulted
|
52
53
|
-a --all=YN y \t Short, long, typed, and defaulted
|
53
54
|
--to_be
|
54
55
|
--not_to_be
|
56
|
+
--rain
|
57
|
+
--water
|
58
|
+
--wet
|
55
59
|
Exclusive:
|
56
60
|
to_be not_to_be \t Tells parser these are mutually exclusive keys
|
57
61
|
Inclusive:
|
58
62
|
date age \t Tells parser any of these must include all of these
|
63
|
+
Conditional:
|
64
|
+
rain water wet \t Tells parser if first then all
|
59
65
|
Alternate:
|
60
66
|
--invoke
|
61
67
|
--wut
|
@@ -67,7 +73,7 @@ Types:
|
|
67
73
|
YN /^[YNyn]$/
|
68
74
|
# <= Hash here, parser breaks out
|
69
75
|
# Notes #
|
70
|
-
|
76
|
+
I wouldn't touch that!
|
71
77
|
HELP
|
72
78
|
|
73
79
|
VERSION = "1.2.3"
|
@@ -82,30 +88,27 @@ HelpParser.string(:arg1, :arg2, :arg3) # for OPTIONS.arg1, etc : String
|
|
82
88
|
#=> [:arg1, :arg2, :arg3]
|
83
89
|
|
84
90
|
## If run as:
|
85
|
-
##
|
86
|
-
OPTIONS.age
|
87
|
-
OPTIONS.
|
91
|
+
## party --age --date=2020-09-07 touch that
|
92
|
+
OPTIONS.age? #=> 80
|
93
|
+
OPTIONS.age?.class #=> Integer
|
94
|
+
OPTIONS.args? #=> ["touch", "that"]
|
95
|
+
OPTIONS.args?.class #=> Array
|
88
96
|
OPTIONS.arg? and OPTIONS.arg #=> false
|
97
|
+
OPTIONS.arg?.class #=> FalseClass
|
89
98
|
```
|
90
99
|
|
91
|
-
YOU HAVE INVOKED THE COMMAND...
|
92
|
-
YOUR HELP BELONGS TO ME!!!
|
93
|
-
|
94
100
|
## Features
|
95
101
|
|
96
|
-
*
|
97
|
-
*
|
102
|
+
* `$DEBUG=true` on --debug
|
103
|
+
* `$VERBOSE=true` on --verbose
|
98
104
|
* -h and --help simultaneously will check help string for errors
|
99
|
-
|
100
|
-
## INSTALL:
|
101
|
-
|
102
|
-
$ sudo gem install help_parser
|
105
|
+
* `HelpParser::REDTTY[msg]` will red color output `msg` to `$stderr`.
|
103
106
|
|
104
107
|
## LICENSE:
|
105
108
|
|
106
109
|
(The MIT License)
|
107
110
|
|
108
|
-
Copyright (c)
|
111
|
+
Copyright (c) 2022 CarlosJHR64
|
109
112
|
|
110
113
|
Permission is hereby granted, free of charge, to any person obtaining
|
111
114
|
a copy of this software and associated documentation files (the
|
@@ -28,9 +28,14 @@ module HelpParser
|
|
28
28
|
# Diagnose user's usage.
|
29
29
|
def diagnose
|
30
30
|
dict = {}
|
31
|
-
@specs.each do |
|
32
|
-
next if RESERVED
|
33
|
-
|
31
|
+
@specs.each do |section,list|
|
32
|
+
next if RESERVED.include? section
|
33
|
+
list.flatten.select{_1[0]=='-'}.each do |key_type|
|
34
|
+
key_type.scan(/\w+/) do |key|
|
35
|
+
dict[key]=true
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
34
39
|
end
|
35
40
|
typos = @hash.keys.select{|k|k.is_a? String and not dict[k]}
|
36
41
|
raise UsageError, MSG[UNRECOGNIZED, typos] unless typos.empty?
|
@@ -46,10 +51,15 @@ module HelpParser
|
|
46
51
|
regex = t2r[type]
|
47
52
|
case value
|
48
53
|
when String
|
49
|
-
|
54
|
+
unless value=~regex
|
55
|
+
raise UsageError, "--#{key}=#{value} !~ #{type}=#{regex.inspect}"
|
56
|
+
end
|
50
57
|
when Array
|
51
58
|
value.each do |string|
|
52
|
-
|
59
|
+
unless string=~regex
|
60
|
+
raise UsageError,
|
61
|
+
"--#{key}=#{string} !~ #{type}=#{regex.inspect}"
|
62
|
+
end
|
53
63
|
end
|
54
64
|
else
|
55
65
|
raise UsageError, "--#{key} !~ #{type}=#{regex.inspect}"
|
@@ -61,7 +71,7 @@ module HelpParser
|
|
61
71
|
def pad
|
62
72
|
# Synonyms and defaults:
|
63
73
|
@specs.each do |section,options|
|
64
|
-
next if section==
|
74
|
+
next if RESERVED.any?{section==_1}
|
65
75
|
options.each do |words|
|
66
76
|
next unless words.size>1
|
67
77
|
first,second,default = words[0],words[1],words[2]
|
@@ -90,6 +100,8 @@ module HelpParser
|
|
90
100
|
@hash[long] = default
|
91
101
|
end
|
92
102
|
end
|
103
|
+
else
|
104
|
+
raise SoftwareError, MSG[UNEXPECTED, words]
|
93
105
|
end
|
94
106
|
end
|
95
107
|
end
|
@@ -106,22 +118,22 @@ module HelpParser
|
|
106
118
|
end
|
107
119
|
next
|
108
120
|
elsif m=FLAG_GROUP.match(token)
|
109
|
-
group,plus = m[
|
121
|
+
group,plus = m[:k],m[:p]
|
110
122
|
key = keys[i]
|
111
|
-
raise NoMatch
|
123
|
+
raise NoMatch unless key.is_a? String
|
112
124
|
list = @specs[group].flatten.select{|f|f[0]=='-'}.map{|f| F2K[f]}
|
113
125
|
raise NoMatch unless list.include?(key)
|
114
126
|
unless plus.nil?
|
115
127
|
loop do
|
116
128
|
key = keys[i+1]
|
117
|
-
break
|
129
|
+
break unless key.is_a?(String) and list.include?(key)
|
118
130
|
i+=1
|
119
131
|
end
|
120
132
|
end
|
121
133
|
elsif m=VARIABLE.match(token)
|
122
134
|
key = keys[i]
|
123
135
|
raise NoMatch unless key.is_a?(Integer)
|
124
|
-
variable,plus = m[
|
136
|
+
variable,plus = m[:k],m[:p]
|
125
137
|
if plus.nil?
|
126
138
|
@cache[variable] = @hash[key]
|
127
139
|
else
|
@@ -1,8 +1,19 @@
|
|
1
1
|
module HelpParser
|
2
|
+
VSN = ['v','version']
|
3
|
+
HLP = ['h','help']
|
4
|
+
VRBS,DBG = 'verbose','debug'
|
5
|
+
|
6
|
+
# reserved name
|
2
7
|
USAGE = 'usage'
|
3
8
|
TYPES = 'types'
|
4
9
|
EXCLUSIVE = 'exclusive'
|
5
10
|
INCLUSIVE = 'inclusive'
|
11
|
+
CONDITIONAL = 'conditional'
|
12
|
+
FLAG_CLUMPS = [EXCLUSIVE,INCLUSIVE,CONDITIONAL]
|
13
|
+
RESERVED = [USAGE,TYPES,EXCLUSIVE,INCLUSIVE,CONDITIONAL]
|
14
|
+
|
15
|
+
# sections
|
16
|
+
SECTION_NAME = /^(?<name>[A-Z]\w+):$/
|
6
17
|
|
7
18
|
# usage
|
8
19
|
FLAG = /^[-][-]?(?<k>\w+)$/
|
@@ -16,7 +27,8 @@ module HelpParser
|
|
16
27
|
|
17
28
|
# spec -w,? --w+
|
18
29
|
SHORT_LONG = /^[-](?<s>\w),?\s+[-][-](?<k>\w+)$/
|
19
|
-
SHORT_LONG_DEFAULT =
|
30
|
+
SHORT_LONG_DEFAULT =
|
31
|
+
/^[-](?<s>\w),?\s+[-][-](?<k>\w+)(=(?<t>[A-Z]+))?,?\s+(?<d>\S*)$/
|
20
32
|
|
21
33
|
# spec W+ /~/
|
22
34
|
TYPE_DEF = /^(?<t>[A-Z]+),?\s+\/(?<r>\S+)\/$/
|
@@ -43,6 +55,7 @@ module HelpParser
|
|
43
55
|
REDUNDANT = 'Redundant'
|
44
56
|
EXCLUSIVE_KEYS = 'Exclusive keys'
|
45
57
|
INCLUSIVE_KEYS = 'Inclusive keys'
|
58
|
+
CONDITIONAL_KEYS = 'Conditional keys'
|
46
59
|
UNBALANCED = 'Unbalanced brackets'
|
47
60
|
UNRECOGNIZED_TOKEN = 'Unrecognized usage token'
|
48
61
|
UNRECOGNIZED_TYPE = 'Unrecognized type spec'
|
@@ -68,6 +81,7 @@ module HelpParser
|
|
68
81
|
# lambda utilities
|
69
82
|
MSG = lambda{|msg,*keys| "#{msg}: #{keys.join(' ')}"}
|
70
83
|
F2K = lambda{|f| f[1]=='-' ? f[2..((f.index('=')||0)-1)] : f[1]}
|
71
|
-
|
72
|
-
|
84
|
+
REDTTY = lambda{|msg,out=$stderr|
|
85
|
+
out.tty? ? out.puts("\033[0;31m#{msg}\033[0m"): out.puts(msg)
|
86
|
+
}
|
73
87
|
end
|
data/lib/help_parser/k2t2r.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
module HelpParser
|
2
|
+
# k2t is an acronym for the "key to type" mapping
|
2
3
|
def self.k2t(specs)
|
3
4
|
k2t = NoDupHash.new
|
4
|
-
|
5
|
+
# If specs section is not a RESERVED section, it's an options list.
|
6
|
+
tokens = specs.select{|k,v| k==USAGE or not RESERVED.include?(k)}
|
7
|
+
# Tokens associating a key to a type.
|
8
|
+
.values.flatten.select{|v|v.include?('=')}
|
5
9
|
tokens.each do |token|
|
6
10
|
if match = VARIABLE.match(token) || LONG.match(token)
|
7
|
-
name, type = match[
|
11
|
+
name, type = match[:k], match[:t]
|
8
12
|
if _=k2t[name]
|
9
13
|
raise HelpError, MSG[INCONSISTENT,name,type,_] unless type==_
|
10
14
|
else
|
@@ -18,6 +22,7 @@ module HelpParser
|
|
18
22
|
return k2t
|
19
23
|
end
|
20
24
|
|
25
|
+
# t2r is an acronym for "type to regexp"
|
21
26
|
def self.t2r(specs)
|
22
27
|
if types = specs[TYPES]
|
23
28
|
t2r = NoDupHash.new
|
data/lib/help_parser/macros.rb
CHANGED
@@ -20,7 +20,8 @@ module HelpParser
|
|
20
20
|
class Options
|
21
21
|
def #{name}?
|
22
22
|
s = @hash['#{name}']
|
23
|
-
raise UsageError, MSG[NOT_STRING,'#{name}'] unless s.nil? ||
|
23
|
+
raise UsageError, MSG[NOT_STRING,'#{name}'] unless s.nil? ||
|
24
|
+
s.is_a?(String)
|
24
25
|
return s
|
25
26
|
end
|
26
27
|
end
|
@@ -50,7 +51,8 @@ module HelpParser
|
|
50
51
|
class Options
|
51
52
|
def #{name}?
|
52
53
|
a = @hash['#{name}']
|
53
|
-
raise UsageError, MSG[NOT_STRINGS,'#{name}'] unless a.nil? ||
|
54
|
+
raise UsageError, MSG[NOT_STRINGS,'#{name}'] unless a.nil? ||
|
55
|
+
a.is_a?(Array)
|
54
56
|
return a
|
55
57
|
end
|
56
58
|
end
|
@@ -64,9 +66,7 @@ module HelpParser
|
|
64
66
|
code = <<-CODE
|
65
67
|
class Options
|
66
68
|
def #{name}
|
67
|
-
|
68
|
-
raise if f.nil?
|
69
|
-
f.to_f
|
69
|
+
@hash['#{name}']&.to_f or raise
|
70
70
|
rescue
|
71
71
|
raise UsageError, MSG[NOT_FLOAT,'#{name}']
|
72
72
|
end
|
@@ -81,9 +81,7 @@ module HelpParser
|
|
81
81
|
code = <<-CODE
|
82
82
|
class Options
|
83
83
|
def #{name}?
|
84
|
-
|
85
|
-
f = f.to_f if f
|
86
|
-
return f
|
84
|
+
@hash['#{name}']&.to_f
|
87
85
|
rescue
|
88
86
|
raise UsageError, MSG[NOT_FLOAT,'#{name}']
|
89
87
|
end
|
@@ -98,9 +96,7 @@ module HelpParser
|
|
98
96
|
code = <<-CODE
|
99
97
|
class Options
|
100
98
|
def #{name}
|
101
|
-
|
102
|
-
raise unless f.is_a?(Array)
|
103
|
-
f.map{|_|_.to_f}
|
99
|
+
@hash['#{name}'].map{_1.to_f}
|
104
100
|
rescue
|
105
101
|
raise UsageError, MSG[#{NOT_FLOATS},'#{name}']
|
106
102
|
end
|
@@ -115,10 +111,7 @@ module HelpParser
|
|
115
111
|
code = <<-CODE
|
116
112
|
class Options
|
117
113
|
def #{name}?
|
118
|
-
|
119
|
-
return nil unless f
|
120
|
-
raise unless f.is_a?(Array)
|
121
|
-
f.map{|_|_.to_f}
|
114
|
+
@hash['#{name}']&.map{_1.to_f}
|
122
115
|
rescue
|
123
116
|
raise UsageError, MSG[NOT_FLOATS,'#{name}']
|
124
117
|
end
|
@@ -133,9 +126,7 @@ module HelpParser
|
|
133
126
|
code = <<-CODE
|
134
127
|
class Options
|
135
128
|
def #{name}
|
136
|
-
|
137
|
-
raise if f.nil?
|
138
|
-
f.to_i
|
129
|
+
@hash['#{name}']&.to_i or raise
|
139
130
|
rescue
|
140
131
|
raise UsageError, MSG[NOT_INTEGER,'#{name}']
|
141
132
|
end
|
@@ -150,9 +141,7 @@ module HelpParser
|
|
150
141
|
code = <<-CODE
|
151
142
|
class Options
|
152
143
|
def #{name}?
|
153
|
-
|
154
|
-
f = f.to_i if f
|
155
|
-
return f
|
144
|
+
@hash['#{name}']&.to_i
|
156
145
|
rescue
|
157
146
|
raise UsageError, MSG[NOT_INTEGER,'#{name}']
|
158
147
|
end
|
@@ -167,9 +156,7 @@ module HelpParser
|
|
167
156
|
code = <<-CODE
|
168
157
|
class Options
|
169
158
|
def #{name}
|
170
|
-
|
171
|
-
raise unless f.is_a?(Array)
|
172
|
-
f.map{|_|_.to_i}
|
159
|
+
@hash['#{name}'].map{_1.to_i}
|
173
160
|
rescue
|
174
161
|
raise UsageError, MSG[NOT_INTEGERS,'#{name}']
|
175
162
|
end
|
@@ -184,10 +171,7 @@ module HelpParser
|
|
184
171
|
code = <<-CODE
|
185
172
|
class Options
|
186
173
|
def #{name}?
|
187
|
-
|
188
|
-
return nil unless f
|
189
|
-
raise unless f.is_a?(Array)
|
190
|
-
f.map{|_|_.to_i}
|
174
|
+
@hash['#{name}']&.map{_1.to_i}
|
191
175
|
rescue
|
192
176
|
raise UsageError, MSG[NOT_INTEGERS,'#{name}']
|
193
177
|
end
|
data/lib/help_parser/options.rb
CHANGED
@@ -2,36 +2,44 @@ module HelpParser
|
|
2
2
|
class Options
|
3
3
|
def initialize(version, help, argv)
|
4
4
|
@hash = HelpParser.parsea(argv)
|
5
|
-
if version &&
|
5
|
+
if version && VSN.any?{@hash.has_key? _1}
|
6
6
|
# -v or --version
|
7
7
|
raise VersionException, version
|
8
8
|
end
|
9
9
|
if help
|
10
|
-
|
11
|
-
|
12
|
-
HelpParser.parseh(help, validate: true) if h.all?{|_|@hash.key?_}
|
10
|
+
if HLP.any?{@hash.key? _1}
|
11
|
+
HelpParser.parseh(help, validate: true) if HLP.all?{@hash.key? _1}
|
13
12
|
raise HelpException, help
|
14
13
|
end
|
15
14
|
specs = HelpParser.parseh(help)
|
16
15
|
Completion.new(@hash, specs)
|
17
16
|
if exclusive=specs[EXCLUSIVE]
|
18
17
|
exclusive.each do |x|
|
19
|
-
count =
|
18
|
+
count = x.count{@hash.key? _1}
|
20
19
|
raise HelpParser::UsageError, MSG[EXCLUSIVE_KEYS,*x] if count > 1
|
21
20
|
end
|
22
21
|
end
|
23
22
|
if inclusive=specs[INCLUSIVE]
|
24
23
|
inclusive.each do |i|
|
25
|
-
count =
|
26
|
-
|
24
|
+
count = i.count{@hash.key? _1}
|
25
|
+
unless count==0 or count==i.length
|
26
|
+
raise HelpParser::UsageError, MSG[INCLUSIVE_KEYS,*i]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
if conditional=specs[CONDITIONAL]
|
31
|
+
conditional.each do |c|
|
32
|
+
if @hash.key? c[0] and not c.all?{@hash.key? _1}
|
33
|
+
raise HelpParser::UsageError, MSG[CONDITIONAL_KEYS,*c]
|
34
|
+
end
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
30
|
-
$VERBOSE = true if @hash[
|
31
|
-
$DEBUG = true if @hash[
|
38
|
+
$VERBOSE = true if @hash[VRBS]==true
|
39
|
+
$DEBUG = true if @hash[DBG]==true
|
32
40
|
end
|
33
41
|
|
34
|
-
def
|
42
|
+
def to_h
|
35
43
|
@hash
|
36
44
|
end
|
37
45
|
|
data/lib/help_parser/parseh.rb
CHANGED
@@ -4,8 +4,8 @@ module HelpParser
|
|
4
4
|
help.each_line do |line|
|
5
5
|
line.chomp!
|
6
6
|
next if line==''
|
7
|
-
if line
|
8
|
-
name =
|
7
|
+
if md = SECTION_NAME.match(line)
|
8
|
+
name = md[:name].downcase
|
9
9
|
specs[name] = []
|
10
10
|
else
|
11
11
|
next if name==''
|
@@ -15,29 +15,32 @@ module HelpParser
|
|
15
15
|
raise HelpError, EXTRANEOUS_SPACES if validate and spec==''
|
16
16
|
case name
|
17
17
|
when USAGE
|
18
|
-
|
18
|
+
Validate.balanced_brackets(spec.chars) if validate
|
19
19
|
tokens = HelpParser.parseu(spec.chars)
|
20
|
-
|
20
|
+
Validate.usage_tokens(tokens) if validate
|
21
21
|
specs[USAGE].push tokens
|
22
22
|
when TYPES
|
23
|
-
|
23
|
+
if validate and not spec=~TYPE_DEF
|
24
|
+
raise HelpError, MSG[UNRECOGNIZED_TYPE,spec]
|
25
|
+
end
|
24
26
|
specs[TYPES].push spec.split(CSV)
|
25
|
-
when EXCLUSIVE,INCLUSIVE
|
26
|
-
|
27
|
+
when *FLAG_CLUMPS # EXCLUSIVE,INCLUSIVE,CONDITIONAL,...
|
28
|
+
if validate and not spec=~X_DEF
|
29
|
+
raise HelpError, MSG[UNRECOGNIZED_X,spec]
|
30
|
+
end
|
27
31
|
specs[name].push spec.split(CSV)
|
28
32
|
else
|
29
|
-
|
30
|
-
|
31
|
-
end
|
33
|
+
raise HelpError, MSG[UNRECOGNIZED_OPTION,spec] if validate and
|
34
|
+
not [SHORT, LONG, SHORT_LONG, SHORT_LONG_DEFAULT].any?{_1=~spec}
|
32
35
|
specs[name].push spec.split(CSV)
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
36
39
|
if validate
|
37
|
-
|
40
|
+
Validate.usage_specs(specs)
|
38
41
|
if t2r = HelpParser.t2r(specs)
|
39
42
|
k2t = HelpParser.k2t(specs)
|
40
|
-
|
43
|
+
Validate.k2t2r(specs, k2t, t2r)
|
41
44
|
end
|
42
45
|
end
|
43
46
|
return specs
|
data/lib/help_parser/parseu.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module HelpParser
|
2
|
-
|
2
|
+
module Validate
|
3
|
+
def self.balanced_brackets(chars)
|
3
4
|
count = 0
|
4
5
|
chars.each do |c|
|
5
6
|
if c=='['
|
@@ -12,30 +13,29 @@ module HelpParser
|
|
12
13
|
raise HelpError, MSG[UNBALANCED,chars.join] unless count==0
|
13
14
|
end
|
14
15
|
|
15
|
-
def self.
|
16
|
+
def self.usage_tokens(tokens)
|
16
17
|
words = []
|
17
18
|
tokens.flatten.each do |token|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
token.match(FLAG_GROUP)
|
22
|
-
raise HelpError, MSG[UNRECOGNIZED_TOKEN,token] unless match
|
23
|
-
words.push match['k'] # key
|
19
|
+
raise HelpError, MSG[UNRECOGNIZED_TOKEN,token] unless
|
20
|
+
[FLAG,LITERAL,VARIABLE,FLAG_GROUP]
|
21
|
+
.detect{_=token.match(_1) and words.push(_[:k])}
|
24
22
|
end
|
25
23
|
words.each_with_index do |word,i|
|
26
24
|
raise HelpError, MSG[DUP_WORD,word] unless i==words.rindex(word)
|
27
25
|
end
|
28
26
|
end
|
29
27
|
|
30
|
-
def self.
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
def self.usage_specs(specs)
|
29
|
+
flags = specs.select{|a,b| not RESERVED.include? a}.values.flatten
|
30
|
+
.select{|f|f[0]=='-'}.map{|f| F2K[f]}
|
31
|
+
FLAG_CLUMPS.each do |k|
|
34
32
|
if a=specs[k]
|
35
33
|
seen = {}
|
36
34
|
a.each do |xs|
|
37
35
|
k = xs.sort.join(' ').to_sym
|
38
|
-
|
36
|
+
if seen[k] or not xs.length==xs.uniq.length
|
37
|
+
raise HelpError, MSG[DUP_X,k]
|
38
|
+
end
|
39
39
|
seen[k] = true
|
40
40
|
xs.each do |x|
|
41
41
|
raise HelpError, MSG[UNSEEN_FLAG, x] unless flags.include?(x)
|
@@ -51,7 +51,7 @@ module HelpParser
|
|
51
51
|
unless specs_usage.nil?
|
52
52
|
specs_usage.flatten.each do |token|
|
53
53
|
if match = token.match(FLAG_GROUP)
|
54
|
-
key = match[
|
54
|
+
key = match[:k]
|
55
55
|
raise HelpError, MSG[UNDEFINED_SECTION,key] unless specs[key]
|
56
56
|
group.push(key)
|
57
57
|
end
|
@@ -59,19 +59,19 @@ module HelpParser
|
|
59
59
|
end
|
60
60
|
specs.each do |key,tokens|
|
61
61
|
raise HelpError, MSG[MISSING_CASES,key] unless tokens.size>0
|
62
|
-
next if specs_usage.nil? or RESERVED
|
62
|
+
next if specs_usage.nil? or RESERVED.include? key
|
63
63
|
raise HelpError, MSG[MISSING_USAGE,key] unless group.include?(key)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def self.
|
67
|
+
def self.k2t2r(specs, k2t, t2r)
|
68
68
|
a,b = k2t.values.uniq.sort,t2r.keys.sort
|
69
69
|
unless a==b
|
70
70
|
c = (a+b).uniq.select{|x|!(a.include?(x) && b.include?(x))}
|
71
71
|
raise HelpError, MSG[UNCOMPLETED_TYPES,c.join(',')]
|
72
72
|
end
|
73
73
|
specs.each do |section,tokens|
|
74
|
-
next if
|
74
|
+
next if RESERVED.include? section
|
75
75
|
tokens.each do |words|
|
76
76
|
next if words.size<2
|
77
77
|
default = words[-1]
|
@@ -82,8 +82,11 @@ module HelpParser
|
|
82
82
|
long = long_type[2..(i-1)]
|
83
83
|
type = long_type[(i+1)..-1]
|
84
84
|
regex = t2r[type]
|
85
|
-
|
85
|
+
unless regex=~default
|
86
|
+
raise HelpError, MSG[BAD_DEFAULT,long,default,type,regex.inspect]
|
87
|
+
end
|
86
88
|
end
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
92
|
+
end
|
data/lib/help_parser.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
10
|
-
require_relative '
|
11
|
-
require_relative './help_parser/macros'
|
1
|
+
require_relative 'help_parser/constants'
|
2
|
+
require_relative 'help_parser/exceptions'
|
3
|
+
require_relative 'help_parser/aliases'
|
4
|
+
require_relative 'help_parser/parsea'
|
5
|
+
require_relative 'help_parser/parseu'
|
6
|
+
require_relative 'help_parser/parseh'
|
7
|
+
require_relative 'help_parser/k2t2r'
|
8
|
+
require_relative 'help_parser/completion'
|
9
|
+
require_relative 'help_parser/options'
|
10
|
+
require_relative 'help_parser/macros'
|
12
11
|
|
13
12
|
module HelpParser
|
14
|
-
VERSION = '
|
13
|
+
VERSION = '8.1.221206'
|
14
|
+
autoload :Validate, 'help_parser/validate'
|
15
15
|
|
16
16
|
def self.[](
|
17
17
|
version = nil,
|
@@ -21,16 +21,6 @@ module HelpParser
|
|
21
21
|
rescue HelpParserException => exception
|
22
22
|
exception.exit
|
23
23
|
end
|
24
|
-
|
25
|
-
def self.run(
|
26
|
-
version = nil,
|
27
|
-
help = nil,
|
28
|
-
argv = [File.basename($0)]+ARGV)
|
29
|
-
options = Options.new(version, help, argv)
|
30
|
-
yield options
|
31
|
-
rescue HelpParserException => exception
|
32
|
-
exception.exit
|
33
|
-
end
|
34
24
|
end
|
35
25
|
|
36
26
|
# Requires:
|
metadata
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: help_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.1.221206
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- CarlosJHR64
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
14
|
-
Can't help YOU???
|
15
|
-
You're not the first to say that...
|
16
|
-
|
17
|
-
I will parse your help!
|
13
|
+
description: "Welcome to Help Parser! \nDo you have your help text? \nLet's parse!\n"
|
18
14
|
email: carlosjhr64@gmail.com
|
19
15
|
executables: []
|
20
16
|
extensions: []
|
@@ -33,8 +29,8 @@ files:
|
|
33
29
|
- lib/help_parser/parsea.rb
|
34
30
|
- lib/help_parser/parseh.rb
|
35
31
|
- lib/help_parser/parseu.rb
|
36
|
-
- lib/help_parser/
|
37
|
-
homepage: https://github.com/carlosjhr64/
|
32
|
+
- lib/help_parser/validate.rb
|
33
|
+
homepage: https://github.com/carlosjhr64/help_parser
|
38
34
|
licenses:
|
39
35
|
- MIT
|
40
36
|
metadata: {}
|
@@ -53,9 +49,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
49
|
- !ruby/object:Gem::Version
|
54
50
|
version: '0'
|
55
51
|
requirements:
|
56
|
-
- 'ruby: ruby
|
57
|
-
rubygems_version: 3.
|
52
|
+
- 'ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]'
|
53
|
+
rubygems_version: 3.3.7
|
58
54
|
signing_key:
|
59
55
|
specification_version: 4
|
60
|
-
summary:
|
56
|
+
summary: Welcome to Help Parser! Do you have your help text? Let's parse!
|
61
57
|
test_files: []
|