Module: HelpParser
- Defined in:
- lib/help_parser.rb,
lib/help_parser/k2t2r.rb,
lib/help_parser/macros.rb,
lib/help_parser/parsea.rb,
lib/help_parser/parseh.rb,
lib/help_parser/parseu.rb,
lib/help_parser/aliases.rb,
lib/help_parser/options.rb,
lib/help_parser/validate.rb,
lib/help_parser/constants.rb,
lib/help_parser/completion.rb,
lib/help_parser/exceptions.rb
Defined Under Namespace
Modules: Validate Classes: ArgvHash, Completion, HelpError, HelpException, HelpParserException, NoDupHash, NoMatch, Options, SoftwareError, UsageError, VersionException
Constant Summary collapse
- VERSION =
'9.0.240926'
- VSN =
%w[v version]
- HLP =
%w[h help]
- USAGE =
reserved name
'usage'
- TYPES =
'types'
- EXCLUSIVE =
'exclusive'
- INCLUSIVE =
'inclusive'
- CONDITIONAL =
'conditional'
- FLAG_CLUMPS =
[EXCLUSIVE,INCLUSIVE,CONDITIONAL]
- RESERVED =
[USAGE,TYPES,EXCLUSIVE,INCLUSIVE,CONDITIONAL]
- SECTION_NAME =
sections
/^(?<name>[A-Z]\w+):$/
- FLAG =
usage
/^--?(?<k>\w+)$/
- LITERAL =
/^(?<k>\w[\w.-]*:?)$/
- VARIABLE =
/^<(?<k>\w+)(=(?<t>[A-Z]+))?>(?<p>[+])?$/
- FLAG_GROUP =
/^:(?<k>\w+)(?<p>[+])?$/
- SHORT =
spec –?w+
/^-(?<s>\w)$/
- LONG =
/^--(?<k>\w+)(=(?<t>[A-Z]+))?(,?\s+(?<d>[^-\s]\S*))?$/
- SHORT_LONG =
spec -w,? –w+
/^-(?<s>\w),?\s+--(?<k>\w+)$/
- SHORT_LONG_DEFAULT =
/^-(?<s>\w),?\s+--(?<k>\w+)(=(?<t>[A-Z]+))?,?\s+(?<d>\S*)$/
- TYPE_DEF =
spec W+ /~/
/^(?<t>[A-Z]+),?\s+\/(?<r>\S+)\/$/
- X_DEF =
spec w+( w+)+
/^\w+( +\w+)+$/
- CSV =
/,?\s+/
- EX_USAGE =
exit codes
64
- EX_SOFTWARE =
70
- EX_CONFIG =
78
- DUP_KEY =
error messages, partials:
'Duplicate key'
- DUP_WORD =
'Duplicate word'
- DUP_FLAG =
'Duplicate flag'
- DUP_X =
'Duplicate exclusive/inclusive spec'
- UNSEEN_FLAG =
'Undefined flag'
- INCONSISTENT =
'Inconsistent use of variable'
- UNEXPECTED =
'Unexpected string in help text'
- BAD_REGEX =
'Bad regex'
- REDUNDANT =
'Redundant'
- EXCLUSIVE_KEYS =
'Exclusive keys'
- INCLUSIVE_KEYS =
'Inclusive keys'
- CONDITIONAL_KEYS =
'Conditional keys'
- UNBALANCED =
'Unbalanced brackets'
- UNRECOGNIZED_TOKEN =
'Unrecognized usage token'
- UNRECOGNIZED_TYPE =
'Unrecognized type spec'
- UNRECOGNIZED_X =
'Unrecognized exclusive/inclusive spec'
- UNRECOGNIZED_OPTION =
'Unrecognized option spec'
- UNRECOGNIZED =
'Unrecognized'
- UNDEFINED_SECTION =
'Section not defined'
- MISSING_CASES =
'Missing cases'
- MISSING_USAGE =
'Missing usage'
- UNCOMPLETED_TYPES =
'Uncompleted types definition'
- BAD_DEFAULT =
'Default does not match type'
- NOT_STRING =
'Not a String'
- NOT_STRINGS =
'Not all Strings'
- NOT_FLOAT =
'Not a Float'
- NOT_FLOATS =
'Not all Floats'
- NOT_INTEGER =
'Not an Integer'
- NOT_INTEGERS =
'Not all Integers'
- NOT_EXIST =
'Does not exist'
- NO_MATCH =
error messages, full:
'Software Error: NoMatch was not caught by HelpParser.'
- MATCH_USAGE =
'Please match usage.'
- EXTRANEOUS_SPACES =
'Extraneous spaces in help.'
- MSG =
lambda utilities
->(msg,*keys){"#{msg}: #{keys.join(' ')}"}
- F2K =
->(f){f[1]=='-' ? f[2..((f.index('=')||0)-1)] : f[1]}
- REDTTY =
lambda do |msg,out=$stderr| out.tty? ? out.puts("\033[0;31m#{msg}\033[0m"): out.puts(msg) end
Class Method Summary collapse
- .[](version = nil, help = nil, argv = [File.basename($0)]+ARGV) ⇒ Object
- .csv(*names) ⇒ Object
- .float(*names) ⇒ Object
- .integer(*names) ⇒ Object
-
.k2t(specs) ⇒ Object
k2t is an acronym for the “key to type” mapping.
- .map(*names, map:) ⇒ Object
- .parsea(argv) ⇒ Object
- .parseh(help, validate: false) ⇒ Object
-
.parseu(chars) ⇒ Object
Chars := String.split(/t/,2).first.strip.chars Token := String=~/^[^ []]$/ Note that emergent Token is String=~/^[^s]$/ Tokens := Array(Token|Tokens).
- .rational(*names) ⇒ Object
- .split(*names, sep:, map:) ⇒ Object
-
.t2r(specs) ⇒ Object
t2r is an acronym for “type to regexp”.
Class Method Details
.[](version = nil, help = nil, argv = [File.basename($0)]+ARGV) ⇒ Object
16 17 18 19 20 21 22 23 |
# File 'lib/help_parser.rb', line 16 def self.[]( version = nil, help = nil, argv = [File.basename($0)]+ARGV) Options.new(version, help, argv) rescue HelpParserException => e e.exit end |
.csv(*names) ⇒ Object
28 |
# File 'lib/help_parser/macros.rb', line 28 def self.csv(*names) = HelpParser.split(*names, sep: ',', map: :strip) |
.float(*names) ⇒ Object
14 |
# File 'lib/help_parser/macros.rb', line 14 def self.float(*names) = HelpParser.map(*names, map: :to_f) |
.integer(*names) ⇒ Object
13 |
# File 'lib/help_parser/macros.rb', line 13 def self.integer(*names) = HelpParser.map(*names, map: :to_i) |
.k2t(specs) ⇒ Object
k2t is an acronym for the “key to type” mapping
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/help_parser/k2t2r.rb', line 3 def self.k2t(specs) k2t = NoDupHash.new # If specs section is not a RESERVED section, it's an options list. tokens = specs.select{|k,_| k==USAGE or !RESERVED.include?(k)} # Tokens associating a key to a type. .values.flatten.select{|v|v.include?('=')} tokens.each do |token| if (match = VARIABLE.match(token) || LONG.match(token)) name, type = match[:k], match[:t] if (_=k2t[name]) raise HelpError, MSG[INCONSISTENT,name,type,_] unless type==_ else k2t[name] = type end else # Expected these to be caught earlier... raise SoftwareError, MSG[UNEXPECTED,token] end end k2t end |
.map(*names, map:) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 |
# File 'lib/help_parser/macros.rb', line 2 def self.map(*names, map:) names.each do |name| Options.instance_eval do define_method(name) do v = @hash[name.to_s] and (v.is_a?(Array) ? v.map(&map) : v.method(map).call) end end end end |
.parsea(argv) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/help_parser/parsea.rb', line 2 def self.parsea(argv) hsh = ArgvHash.new n = 0 argv.each do |a| if a[0]=='-' break if a.size==1 # '-' quits argv processing if a[1]=='-' break if a.size==2 # '--' also quits argv processing s = a[2..] if s.include?('=') k,v = s.split('=',2) hsh[k] = v else hsh[s] = true end else a.chars[1..].each do |c| hsh[c] = true end end else hsh[n] = a n += 1 end end hsh end |
.parseh(help, validate: false) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/help_parser/parseh.rb', line 2 def self.parseh(help, validate: false) specs,name = NoDupHash.new,'' help.each_line do |line| line.chomp! next if line=='' if (md=SECTION_NAME.match(line)) name = md[:name].downcase specs[name] = [] else next if name=='' break if line[0]=='#' next unless line[0]==' ' spec,comment = line.split("\t", 2).map(&:strip) if spec.empty? raise HelpError, EXTRANEOUS_SPACES if validate && comment.to_s.empty? next end case name when USAGE Validate.balanced_brackets(spec.chars) if validate tokens = HelpParser.parseu(spec.chars) Validate.usage_tokens(tokens) if validate specs[USAGE].push tokens when TYPES if validate && !TYPE_DEF.match?(spec) raise HelpError, MSG[UNRECOGNIZED_TYPE,spec] end specs[TYPES].push spec.split(CSV) when *FLAG_CLUMPS # EXCLUSIVE,INCLUSIVE,CONDITIONAL,... if validate && !X_DEF.match?(spec) raise HelpError, MSG[UNRECOGNIZED_X,spec] end specs[name].push spec.split(CSV) else if validate && [SHORT, LONG, SHORT_LONG, SHORT_LONG_DEFAULT].none?{_1=~spec} raise HelpError, MSG[UNRECOGNIZED_OPTION,spec] end specs[name].push spec.split(CSV) end end end if validate Validate.usage_specs(specs) if (t2r=HelpParser.t2r(specs)) k2t = HelpParser.k2t(specs) Validate.k2t2r(specs, k2t, t2r) end end specs end |
.parseu(chars) ⇒ Object
Chars := String.split(/t/,2).first.strip.chars Token := String=~/^[^ []]$/ Note that emergent Token is String=~/^[^s]$/ Tokens := Array(Token|Tokens)
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/help_parser/parseu.rb', line 6 def self.parseu(chars) tokens,token = [],'' while (c=chars.shift) case c when ' ','[',']' unless token=='' tokens.push(token) token = '' end tokens.push HelpParser.parseu(chars) if c=='[' return tokens if c==']' else token += c end end tokens.push(token) unless token=='' tokens end |
.rational(*names) ⇒ Object
15 |
# File 'lib/help_parser/macros.rb', line 15 def self.rational(*names) = HelpParser.map(*names, map: :to_r) |
.split(*names, sep:, map:) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/help_parser/macros.rb', line 17 def self.split(*names, sep:, map:) names.each do |name| Options.instance_eval do define_method(name) do v = @hash[name.to_s] and (v.is_a?(Array) ? v.map{_1.split(sep).map(&map)} : v.split(sep).map(&map)) end end end end |
.t2r(specs) ⇒ Object
t2r is an acronym for “type to regexp”
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/help_parser/k2t2r.rb', line 26 def self.t2r(specs) if (types=specs[TYPES]) t2r = NoDupHash.new types.each do |pair| type, pattern = *pair begin t2r[type] = Regexp.new(pattern[1..-2]) rescue raise HelpError, MSG[BAD_REGEX,type,pattern] end end return t2r end nil end |