help_parser 6.5.0 → 7.0.200907

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []