help_parser 6.5.0 → 7.0.200907

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: f4db6d5181c02bb903bbbf763859492f86a97f6d332e4e6759ad75aa5c8af158
4
- data.tar.gz: 2395a8527b6ddc0e002ca4b07443f97e2933f96d75fcd4f41592bc2fcd10e113
3
+ metadata.gz: 7df1feedeed249286efe5cd5f1e2cc187a91d348eab654d5a6f110292d0c3476
4
+ data.tar.gz: a3f142a3d2cf4c6bf038b25e3552dfc3f56bfbb3469749386994b0763ccaea4c
5
5
  SHA512:
6
- metadata.gz: bab28a22dbf528db7220d98aef0b85daaa9289bf1b536691581bf0465b4a1ed72fc517ddb4b3d6e7836eceaca4db7fe5467720287a612eeb5d73a864e7a34f9d
7
- data.tar.gz: d44ba0ee9546f540c19b329d1d29e3dc07945d311d2ca7f4b54f6477e7d8d1bc945536598516f47abff0ca10bebfdbd38b758f70846b55cf0d92b4d9b2e91591
6
+ metadata.gz: c3df75b2ae4640bc268e86774facbc7f60e74fda4d58c3262022e3a571cb3d716af2be92e7d1652e2ffa5469a1852da4a412e582141f155fe849f37e62d4e4dc
7
+ data.tar.gz: 447dfb4939662fec618c4c315f104785e1923a6a625b82ed028981a9ff98c35c9049b23586501c8bd06e244f21de8da4cec2c491bf815a17d3c2d38f93495e4e
data/README.md CHANGED
@@ -1,83 +1,127 @@
1
- # Help Parser VI: Tweeker
1
+ # Help Parser VII: Deader
2
2
 
3
+ * [VERSION 7.0.200907](https://github.com/carlosjhr64/Ruby-HelpParser/releases)
3
4
  * [github](https://www.github.com/carlosjhr64/Ruby-HelpParser)
4
5
  * [rubygems](https://rubygems.org/gems/help_parser)
5
6
 
6
7
  ## DESCRIPTION:
7
- Welcome to the best Help Parser of all!
8
- Tweeker!
9
- Which do you find most helpful?
10
- Hard?
11
- I prefer easy.
12
8
 
13
- ## SYNOPSIS:
9
+ Can't help YOU???
10
+ You're not the first to say that...
11
+
12
+ I will parse your help!
14
13
 
15
- require "help_parser"
16
-
17
- HELP = <<-HELP
18
- # <= Hash here, parser skips
19
- # The Awesome Command #
20
- Usage:
21
- awesome [:options+] <args>+
22
- awesome :alternate+ <arg=NAME>
23
- Options:
24
- -v --version \t Give version and quit
25
- -h --help \t Give help and quit
26
- -s --long \t Short long synonyms
27
- --name=NAME \t Typed
28
- --number 5 \t Defaulted
29
- --value=FLOAT 1.23 \t Typed and Defaulted
30
- -a --all=YN y \t Short, long, typed, and defaulted
31
- Alternate:
32
- -V \t Just short
33
- --to_be
34
- --not_to_be
35
- Types:
36
- NAME /^[A-Z][a-z]+$/
37
- FLOAT /^\\d+\\.\\d+$/
38
- YN /^[YNyn]$/
39
- Exclusive:
40
- to_be not_to_be \t Tells parser these are mutually exclusive keys
41
- # <= Hash here, parser breaks out
42
- # Notes #
43
- Blah blah blah
44
- HELP
45
-
46
- VERSION = "6.5.0"
47
-
48
- # Macros:
49
- HelpParser.string(name) # for options.name : String
50
- HelpParser.strings(args) # for options.args : Array(String)
51
- HelpParser.float(value) # for options.value : Float
52
- HelpParser.int?(number) # for options.number? : Int32 | Nil
53
-
54
- HelpParser.run(VERSION, HELP) do |options|
55
- hash = options._hash
56
- pp hash # to inspect the hash
57
-
58
- pp options.name if hash["name"]?
59
- pp options.args if hash["args"]?
60
- pp options.value if hash["value"]?
61
- pp options.number?
62
- end
63
-
64
- Well, what do you think?
65
- PERFECT!
66
-
67
- ## New for 6.4.2:
68
-
69
- * Automates $DEBUG=true on --debug
70
-
71
- ## New for 6.4.0:
72
-
73
- * Automates $VERBOSE=true on --verbose
74
- * Reports typos you may have on options usage
75
-
76
- ## New for 6.1.0:
77
-
78
- Running your `awesome` command with the `--help` flag will also check your help text for errors,
79
- on top of giving the help text. Otherwise, the parser no longer checks for help text errors.
14
+ ## SYNOPSIS:
15
+ <!-- The following PREVIEW has been approved for ALL PROGRAMMERS by CarlosJHR64.
16
+ For the README validator that checks against me lying....
17
+ ```ruby
18
+ unless File.basename($PROGRAM_NAME) == 'deader'
19
+ # For example's sake say
20
+ $PROGRAM_NAME = 'deader'
21
+ # and ARGV is
22
+ ARGV.concat ["-\-age", "-\-date=2020-09-07", 'invoke', 'the', 'command']
23
+ # and proceed as if run as:
24
+ # awesome -\-name=Doe -\-value a b c
25
+ end
26
+ ```
27
+ The following gem has been rated
28
+ | M | Mature |
29
+ -->
30
+
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
+ ```ruby
36
+ require "help_parser"
37
+
38
+ HELP = <<-HELP
39
+ # <= Hash here, parser skips
40
+ # HelpParser: Deader command example #
41
+ Usage:
42
+ deader :options+ [<args>+]
43
+ deader [:alternate] <arg=FLOAT>
44
+ deader literal <arg1=WORD> <arg2=WORD> <arg3=WORD>
45
+ Options:
46
+ -v --version \t Give version and quit
47
+ -h --help \t Give help and quit
48
+ -s --long \t Short long synonyms
49
+ --command invoke \t Defaulted
50
+ --date=DATE \t Typed
51
+ --age=INTEGER 80 \t Typed and Defaulted
52
+ -a --all=YN y \t Short, long, typed, and defaulted
53
+ --to_be
54
+ --not_to_be
55
+ Exclusive:
56
+ to_be not_to_be \t Tells parser these are mutually exclusive keys
57
+ Inclusive:
58
+ date age \t Tells parser any of these must include all of these
59
+ Alternate:
60
+ --invoke
61
+ --wut
62
+ Types:
63
+ WORD /^[A-Za-z]+$/
64
+ DATE /^\\d\\d\\d\\d-\\d\\d-\\d\\d$/
65
+ INTEGER /^\\d+$/
66
+ FLOAT /^\\d+\\.\\d+$/
67
+ YN /^[YNyn]$/
68
+ # <= Hash here, parser breaks out
69
+ # Notes #
70
+ Don't invoke the command.
71
+ HELP
72
+
73
+ VERSION = "1.2.3"
74
+
75
+ OPTIONS = HelpParser[VERSION, HELP] #~> HelpParser
76
+
77
+ # Macros:
78
+ HelpParser.strings?(:args) # for OPTIONS.args : Array(String) | Nil
79
+ HelpParser.int?(:age) # for OPTIONS.age? : Integer | Nil
80
+ HelpParser.float(:arg) # for options.arg : Float
81
+ HelpParser.string(:arg1, :arg2, :arg3) # for OPTIONS.arg1, etc : String
82
+ #=> [:arg1, :arg2, :arg3]
83
+
84
+ ## If run as:
85
+ ## deader --age --date=2020-09-07 invoke the command
86
+ OPTIONS.age #=> 80
87
+ OPTIONS.args #=> ["invoke", "the", "command"]
88
+ OPTIONS.arg? and OPTIONS.arg #=> false
89
+ ```
90
+
91
+ YOU HAVE INVOKED THE COMMAND...
92
+ YOUR HELP BELONGS TO ME!!!
93
+
94
+ ## Features
95
+
96
+ * $DEBUG=true on --debug
97
+ * $VERBOSE=true on --verbose
98
+ * -h and --help simultaneously will check help string for errors
80
99
 
81
100
  ## INSTALL:
82
101
 
83
102
  $ sudo gem install help_parser
103
+
104
+ ## LICENSE:
105
+
106
+ (The MIT License)
107
+
108
+ Copyright (c) 2020 CarlosJHR64
109
+
110
+ Permission is hereby granted, free of charge, to any person obtaining
111
+ a copy of this software and associated documentation files (the
112
+ 'Software'), to deal in the Software without restriction, including
113
+ without limitation the rights to use, copy, modify, merge, publish,
114
+ distribute, sublicense, and/or sell copies of the Software, and to
115
+ permit persons to whom the Software is furnished to do so, subject to
116
+ the following conditions:
117
+
118
+ The above copyright notice and this permission notice shall be
119
+ included in all copies or substantial portions of the Software.
120
+
121
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
122
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
123
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
124
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
125
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
126
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
127
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -11,7 +11,7 @@ require_relative './help_parser/options'
11
11
  require_relative './help_parser/macros'
12
12
 
13
13
  module HelpParser
14
- VERSION = '6.5.0'
14
+ VERSION = '7.0.200907'
15
15
 
16
16
  def self.[](
17
17
  version = nil,
@@ -3,28 +3,33 @@ module HelpParser
3
3
  def initialize(hash, specs)
4
4
  @hash,@specs = hash,specs
5
5
  @cache = NoDupHash.new
6
- usage if @specs.has_key?(USAGE)
6
+ usage or diagnose if @specs.has_key?(USAGE)
7
7
  pad
8
- types
8
+ types if @specs.has_key?(TYPES)
9
9
  end
10
10
 
11
+ # Which usage does the user's command options match?
11
12
  def usage
12
13
  @specs[USAGE].each do |cmd|
13
14
  begin
14
15
  i = matches(cmd)
15
16
  raise NoMatch unless @hash.size==i
16
17
  @cache.each{|k,v|@hash[k]=v} # Variables
17
- return
18
+ return true # Good! Found matching usage.
18
19
  rescue NoMatch
19
20
  next
20
21
  ensure
21
22
  @cache.clear
22
23
  end
23
24
  end
25
+ return false # Bad! Did not match any of the expected usage.
26
+ end
24
27
 
28
+ # Diagnose user's usage.
29
+ def diagnose
25
30
  dict = {}
26
31
  @specs.each do |k,v|
27
- next if [USAGE,TYPES,EXCLUSIVE].include? k
32
+ next if RESERVED[k]
28
33
  v.flatten.map{|_|_.scan(/\w+/).first}.each{|_|dict[_]=true}
29
34
  end
30
35
  typos = @hash.keys.select{|k|k.is_a? String and not dict[k]}
@@ -34,22 +39,20 @@ module HelpParser
34
39
  end
35
40
 
36
41
  def types
37
- if t2r = HelpParser.t2r(@specs)
38
- k2t = HelpParser.k2t(@specs)
39
- @hash.each do |key,value|
40
- next unless key.is_a?(String)
41
- if type = k2t[key]
42
- regex = t2r[type]
43
- case value
44
- when String
45
- raise UsageError, "--#{key}=#{value} !~ #{type}=#{regex.inspect}" unless value=~regex
46
- when Array
47
- value.each do |string|
48
- raise UsageError, "--#{key}=#{string} !~ #{type}=#{regex.inspect}" unless string=~regex
49
- end
50
- else
51
- raise UsageError, "--#{key} !~ #{type}=#{regex.inspect}"
42
+ t2r,k2t = HelpParser.t2r(@specs),HelpParser.k2t(@specs)
43
+ @hash.each do |key,value|
44
+ next unless key.is_a?(String)
45
+ if type = k2t[key]
46
+ regex = t2r[type]
47
+ case value
48
+ when String
49
+ raise UsageError, "--#{key}=#{value} !~ #{type}=#{regex.inspect}" unless value=~regex
50
+ when Array
51
+ value.each do |string|
52
+ raise UsageError, "--#{key}=#{string} !~ #{type}=#{regex.inspect}" unless string=~regex
52
53
  end
54
+ else
55
+ raise UsageError, "--#{key} !~ #{type}=#{regex.inspect}"
53
56
  end
54
57
  end
55
58
  end
@@ -74,7 +77,7 @@ module HelpParser
74
77
  elsif value = @hash[long]
75
78
  @hash[short] = true
76
79
  if value==true && !default.nil?
77
- @hash.delete(long)
80
+ @hash.delete(long) # ArgvHash reset
78
81
  @hash[long]=default
79
82
  end
80
83
  end
@@ -83,7 +86,7 @@ module HelpParser
83
86
  long,default = first[2..(i-1)],second
84
87
  value = @hash[long]
85
88
  if value==true
86
- @hash.delete(long)
89
+ @hash.delete(long) # ArgvHash reset
87
90
  @hash[long] = default
88
91
  end
89
92
  end
@@ -1,15 +1,8 @@
1
1
  module HelpParser
2
- @@validate = false
3
- def self.validate!
4
- @@validate = true
5
- end
6
- def self.validate?
7
- @@validate
8
- end
9
-
10
2
  USAGE = 'usage'
11
3
  TYPES = 'types'
12
4
  EXCLUSIVE = 'exclusive'
5
+ INCLUSIVE = 'inclusive'
13
6
 
14
7
  # usage
15
8
  FLAG = /^[-][-]?(?<k>\w+)$/
@@ -29,7 +22,7 @@ module HelpParser
29
22
  TYPE_DEF = /^(?<t>[A-Z]+),?\s+\/(?<r>\S+)\/$/
30
23
 
31
24
  # spec w+( w+)+
32
- X_DEF = /^\w+( +\w+)+$/
25
+ X_DEF = /^\w+( +\w+)+$/ # for both exclusive and inclusive specs
33
26
 
34
27
  CSV = /,?\s+/
35
28
 
@@ -42,17 +35,18 @@ module HelpParser
42
35
  DUP_KEY = 'Duplicate key'
43
36
  DUP_WORD = 'Duplicate word'
44
37
  DUP_FLAG = 'Duplicate flag'
45
- DUP_X = 'Duplicate exclusive spec'
38
+ DUP_X = 'Duplicate exclusive/inclusive spec'
46
39
  UNSEEN_FLAG = 'Undefined flag'
47
40
  INCONSISTENT = 'Inconsistent use of variable'
48
41
  UNEXPECTED = 'Unexpected string in help text'
49
42
  BAD_REGEX = 'Bad regex'
50
43
  REDUNDANT = 'Redundant'
51
44
  EXCLUSIVE_KEYS = 'Exclusive keys'
45
+ INCLUSIVE_KEYS = 'Inclusive keys'
52
46
  UNBALANCED = 'Unbalanced brackets'
53
47
  UNRECOGNIZED_TOKEN = 'Unrecognized usage token'
54
48
  UNRECOGNIZED_TYPE = 'Unrecognized type spec'
55
- UNRECOGNIZED_X = 'Unrecognized exclusive spec'
49
+ UNRECOGNIZED_X = 'Unrecognized exclusive/inclusive spec'
56
50
  UNRECOGNIZED_OPTION = 'Unrecognized option spec'
57
51
  UNRECOGNIZED = 'Unrecognized'
58
52
  UNDEFINED_SECTION = 'Section not defined'
@@ -74,5 +68,6 @@ module HelpParser
74
68
  # lambda utilities
75
69
  MSG = lambda{|msg,*keys| "#{msg}: #{keys.join(' ')}"}
76
70
  F2K = lambda{|f| f[1]=='-' ? f[2..((f.index('=')||0)-1)] : f[1]}
77
- RESERVED = lambda{|k| [USAGE,TYPES,EXCLUSIVE].include?(k)} # reserved
71
+ RESERVED = lambda{|k| [USAGE,TYPES,EXCLUSIVE,INCLUSIVE].include?(k)} # reserved
72
+ REDTTY = lambda{|msg,out=$stderr| out.tty? ? out.puts("\033[0;31m#{msg}\033[0m"): out.puts(msg)}
78
73
  end
@@ -10,9 +10,9 @@ module HelpParser
10
10
 
11
11
  def exit
12
12
  if @code > 0
13
- STDERR.puts "\033[0;31m#{self.message}\033[0m"
13
+ REDTTY[self.message]
14
14
  else
15
- puts self.message
15
+ $stdout.puts self.message
16
16
  end
17
17
  Kernel.exit @code
18
18
  end
@@ -36,10 +36,10 @@ module HelpParser
36
36
  end
37
37
 
38
38
  class NoMatch < HelpParserException
39
- # used to shortcircuit out
39
+ # used to short-circuit out
40
40
  def _init; @code = EX_SOFTWARE; end
41
41
 
42
- # Forces it's owm message
42
+ # Forces it's own message
43
43
  def initialize
44
44
  super(NO_MATCH)
45
45
  end
@@ -5,8 +5,11 @@ module HelpParser
5
5
  tokens.each do |token|
6
6
  if match = VARIABLE.match(token) || LONG.match(token)
7
7
  name, type = match['k'], match['t']
8
- k2t[name] = type if !k2t.has_key?(name)
9
- raise HelpError, MSG[INCONSISTENT,name,type,k2t[name]] if !(type==k2t[name])
8
+ if _=k2t[name]
9
+ raise HelpError, MSG[INCONSISTENT,name,type,_] unless type==_
10
+ else
11
+ k2t[name] = type
12
+ end
10
13
  else
11
14
  # Expected these to be caught earlier...
12
15
  raise SoftwareError, MSG[UNEXPECTED,token]
@@ -7,20 +7,24 @@ module HelpParser
7
7
  raise VersionException, version
8
8
  end
9
9
  if help
10
- # -h or --help
11
- if @hash.has_key?('h') || _=@hash.has_key?('help')
12
- begin
13
- # validates help
14
- HelpParser.parseh(help, true)
15
- rescue HelpError
16
- $stderr.puts $!
17
- end if _
10
+ h = ['h', 'help']
11
+ if h.any?{|_|@hash.key?_}
12
+ HelpParser.parseh(help, validate: true) if h.all?{|_|@hash.key?_}
18
13
  raise HelpException, help
19
14
  end
20
- specs = HelpParser.parseh(help, HelpParser.validate?)
15
+ specs = HelpParser.parseh(help)
21
16
  Completion.new(@hash, specs)
22
17
  if exclusive=specs[EXCLUSIVE]
23
- exclusive.each{|xs| raise HelpParser::UsageError, MSG[EXCLUSIVE_KEYS,*xs] if @hash.keys.count{|k|xs.include?(k)}>1}
18
+ exclusive.each do |x|
19
+ count = @hash.keys.count{|k|x.include?(k)}
20
+ raise HelpParser::UsageError, MSG[EXCLUSIVE_KEYS,*x] if count > 1
21
+ end
22
+ end
23
+ if inclusive=specs[INCLUSIVE]
24
+ inclusive.each do |i|
25
+ count = @hash.keys.count{|k|i.include?(k)}
26
+ raise HelpParser::UsageError, MSG[INCLUSIVE_KEYS,*i] unless count==0 or count==i.length
27
+ end
24
28
  end
25
29
  end
26
30
  $VERBOSE = true if @hash['verbose']==true
@@ -1,5 +1,5 @@
1
1
  module HelpParser
2
- def self.parseh(help, validate=true)
2
+ def self.parseh(help, validate: false)
3
3
  specs,name = NoDupHash.new,''
4
4
  help.each_line do |line|
5
5
  line.chomp!
@@ -18,11 +18,11 @@ module HelpParser
18
18
  HelpParser.validate_line_chars(spec.chars) if validate
19
19
  tokens = HelpParser.parseu(spec.chars)
20
20
  HelpParser.validate_usage_tokens(tokens) if validate
21
- specs[name].push tokens
21
+ specs[USAGE].push tokens
22
22
  when TYPES
23
23
  raise HelpError, MSG[UNRECOGNIZED_TYPE,spec] if validate and not spec=~TYPE_DEF
24
- specs[name].push spec.split(CSV)
25
- when EXCLUSIVE
24
+ specs[TYPES].push spec.split(CSV)
25
+ when EXCLUSIVE,INCLUSIVE
26
26
  raise HelpError, MSG[UNRECOGNIZED_X,spec] if validate and not spec=~X_DEF
27
27
  specs[name].push spec.split(CSV)
28
28
  else
@@ -30,14 +30,16 @@ module HelpParser
30
30
  def self.validate_usage_specs(specs)
31
31
  option_specs = specs.select{|a,b| !RESERVED[a]}
32
32
  flags = option_specs.values.flatten.select{|f|f[0]=='-'}.map{|f| F2K[f]}
33
- if exclusive=specs[EXCLUSIVE]
34
- seen = {}
35
- exclusive.each do |xs|
36
- k = xs.sort.join(' ').to_sym
37
- raise HelpError, MSG[DUP_X,k] if seen[k]
38
- seen[k] = true
39
- xs.each do |x|
40
- raise HelpError, MSG[UNSEEN_FLAG, x] unless flags.include?(x)
33
+ [EXCLUSIVE,INCLUSIVE].each do |k|
34
+ if a=specs[k]
35
+ seen = {}
36
+ a.each do |xs|
37
+ k = xs.sort.join(' ').to_sym
38
+ raise HelpError, MSG[DUP_X,k] if seen[k] or not xs.length==xs.uniq.length
39
+ seen[k] = true
40
+ xs.each do |x|
41
+ raise HelpError, MSG[UNSEEN_FLAG, x] unless flags.include?(x)
42
+ end
41
43
  end
42
44
  end
43
45
  end
metadata CHANGED
@@ -1,21 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: help_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.0
4
+ version: 7.0.200907
5
5
  platform: ruby
6
6
  authors:
7
7
  - carlosjhr64
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-20 00:00:00.000000000 Z
11
+ date: 2020-09-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
- Welcome to the best Help Parser of all!
15
- Tweeker!
16
- Which do you find most helpful?
17
- Hard?
18
- I prefer easy.
14
+ Can't help YOU???
15
+ You're not the first to say that...
16
+
17
+ I will parse your help!
19
18
  email: carlosjhr64@gmail.com
20
19
  executables: []
21
20
  extensions: []
@@ -54,11 +53,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
53
  - !ruby/object:Gem::Version
55
54
  version: '0'
56
55
  requirements:
57
- - 'ruby: ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]'
58
- rubyforge_project:
59
- rubygems_version: 2.7.7
56
+ - 'ruby: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]'
57
+ rubygems_version: 3.1.2
60
58
  signing_key:
61
59
  specification_version: 4
62
- summary: Welcome to the best Help Parser of all! Tweeker! Which do you find most helpful?
63
- Hard? I prefer easy.
60
+ summary: Can't help YOU??? You're not the first to say that...
64
61
  test_files: []