module HelpParser
Constants
- BAD_DEFAULT
- BAD_REGEX
- CONDITIONAL
- CONDITIONAL_KEYS
- CSV
- DBG
- DUP_FLAG
- DUP_KEY
error messages, partials:
- DUP_WORD
- DUP_X
- EXCLUSIVE
- EXCLUSIVE_KEYS
- EXTRANEOUS_SPACES
- EX_CONFIG
- EX_SOFTWARE
- EX_USAGE
exit codes
- F2K
- FLAG
usage
- FLAG_CLUMPS
- FLAG_GROUP
- HLP
- INCLUSIVE
- INCLUSIVE_KEYS
- INCONSISTENT
- LITERAL
- LONG
- MATCH_USAGE
- MISSING_CASES
- MISSING_USAGE
- MSG
lambda utilities
- NOT_EXIST
- NOT_FLOAT
- NOT_FLOATS
- NOT_INTEGER
- NOT_INTEGERS
- NOT_STRING
- NOT_STRINGS
- NO_MATCH
error messages, full:
- REDTTY
- REDUNDANT
- RESERVED
- SECTION_NAME
sections
- SHORT
spec –?w+
- SHORT_LONG
spec -w,? –w+
- SHORT_LONG_DEFAULT
- TYPES
- TYPE_DEF
spec W+ /~/
- UNBALANCED
- UNCOMPLETED_TYPES
- UNDEFINED_SECTION
- UNEXPECTED
- UNRECOGNIZED
- UNRECOGNIZED_OPTION
- UNRECOGNIZED_TOKEN
- UNRECOGNIZED_TYPE
- UNRECOGNIZED_X
- UNSEEN_FLAG
- USAGE
reserved name
- VARIABLE
- VERSION
- VSN
- X_DEF
spec w+( w+)+
Public Class Methods
[]( version = nil, help = nil, argv = [File.basename($0)]+ARGV)
click to toggle source
# 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)
click to toggle source
# File lib/help_parser/macros.rb, line 28 def self.csv(*names) = HelpParser.split(*names, sep: ',', map: :strip) end
float(*names)
click to toggle source
# File lib/help_parser/macros.rb, line 14 def self.float(*names) = HelpParser.map(*names, map: :to_f) def self.rational(*names) = HelpParser.map(*names, map: :to_r) 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 def self.csv(*names) = HelpParser.split(*names, sep: ',', map:
integer(*names)
click to toggle source
# File lib/help_parser/macros.rb, line 13 def self.integer(*names) = HelpParser.map(*names, map: :to_i) def self.float(*names) = HelpParser.map(*names, map: :to_f) def self.rational(*names) = HelpParser.map(*names, map: :to_r) 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 def self.csv(*names) = HelpParser.split(*names, sep: ',',
k2t(specs)
click to toggle source
k2t is an acronym for the “key to type” mapping
# 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:)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
Chars := String.split(/t/,2).first.strip.chars Token := String=~/^[^ []]$/ Note that emergent Token is String=~/^[^s]$/ Tokens := Array(Token|Tokens)
# 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)
click to toggle source
# File lib/help_parser/macros.rb, line 15 def self.rational(*names) = HelpParser.map(*names, map: :to_r) 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 def self.csv(*names) = HelpParser.split(*names, sep: ',', map: :strip)
split(*names, sep:, map:)
click to toggle source
# 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)
click to toggle source
t2r is an acronym for “type to regexp”
# 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