optparsegen 0.1.0
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 +7 -0
- data/bin/optparsegen +27 -0
- data/lib/optparsegen/scopt.rb +109 -0
- data/lib/optparsegen.rb +13 -0
- data/test/test_scopt.rb +40 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c224a84b9f8bc19e937d687806e1171f2b8d9c00
|
4
|
+
data.tar.gz: aed0a9eda0f3e95194a4f0e4320dee8d263fe4eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 58d646498865d522f5eb80e81c52005cd77cb26469e153b4acebfb690ff4a4f0d3af6ff6a50f6b6c78313ff720794791c67dccd8c5e04172ffb6c0459d09c5b0
|
7
|
+
data.tar.gz: fdc547b174c848784af0c117d4310142c48ef8991b375295273a927c519857b2020377b84f2e9f571ff40286df5064d5cf8ef8e7edc7cf0bb1b8bfea00e0dc24
|
data/bin/optparsegen
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'optparsegen'
|
4
|
+
|
5
|
+
options = Struct.new(:format).new(:scopt)
|
6
|
+
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = %Q(Usage: #{File.basename($0)} [options] <file>
|
9
|
+
|
10
|
+
optparsegen converts program usage text into equivalent ruby 'optparse'
|
11
|
+
code. It reads the text from the filename passed as the only argument
|
12
|
+
on the command line or from standard input.
|
13
|
+
|
14
|
+
Options:
|
15
|
+
)
|
16
|
+
|
17
|
+
opts.on('-f', '--format', '=[FORMAT]', [:scopt], 'Input usage text format. Default: scopt') do |v|
|
18
|
+
options.format = v
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on_tail('-h', '--help', 'Show this message.') do
|
22
|
+
puts opts
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
end.parse!
|
26
|
+
|
27
|
+
OptParseGen.generate(ARGF.read, options.format)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class OptParseGen::ScoptParser
|
2
|
+
def initialize(input)
|
3
|
+
@tape = input
|
4
|
+
@options = []
|
5
|
+
@current = OptParseGen::Option.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse
|
9
|
+
state = :parse_any
|
10
|
+
|
11
|
+
while state != nil
|
12
|
+
lchomp_until!(is_not_space)
|
13
|
+
state = send(state)
|
14
|
+
end
|
15
|
+
|
16
|
+
@options
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def is_not_space
|
21
|
+
/[^\s]/
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_space
|
25
|
+
/\s/
|
26
|
+
end
|
27
|
+
|
28
|
+
def lchomp_until!(matches)
|
29
|
+
p = @tape.index(matches)
|
30
|
+
if p == nil
|
31
|
+
@tape.slice!(-1)
|
32
|
+
else
|
33
|
+
@tape.slice!(0, p)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_any
|
38
|
+
case
|
39
|
+
when @tape.start_with?('-') then
|
40
|
+
@tape.slice!(0, 1)
|
41
|
+
:parse_opt
|
42
|
+
when (p = @tape.index("\n")) != nil then
|
43
|
+
@tape.slice!(0, p)
|
44
|
+
:parse_any
|
45
|
+
else
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_opt
|
51
|
+
if @tape[0] == '-'
|
52
|
+
@tape.slice!(0)
|
53
|
+
:parse_opt_name
|
54
|
+
else
|
55
|
+
:parse_opt_short
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_opt_short
|
60
|
+
short = lchomp_until!(is_space).chop!
|
61
|
+
if short
|
62
|
+
@current.short = short
|
63
|
+
:parse_any
|
64
|
+
else
|
65
|
+
raise 'expected short option name'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_opt_name
|
70
|
+
name = lchomp_until!(is_space)
|
71
|
+
if name
|
72
|
+
@current.name = name
|
73
|
+
:parse_opt_value_or_desc
|
74
|
+
else
|
75
|
+
raise 'expected option name'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_opt_value_or_desc
|
80
|
+
if @tape.start_with?('<')
|
81
|
+
:parse_opt_value
|
82
|
+
else
|
83
|
+
:parse_opt_desc
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_opt_value
|
88
|
+
value = lchomp_until!(is_space)
|
89
|
+
if value
|
90
|
+
# TODO: Handle value examples.
|
91
|
+
# @current.value = value
|
92
|
+
:parse_opt_desc
|
93
|
+
else
|
94
|
+
raise 'expected value'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse_opt_desc
|
99
|
+
desc = lchomp_until!("\n")
|
100
|
+
if desc
|
101
|
+
@current.description = desc
|
102
|
+
@options.push(@current)
|
103
|
+
@current = OptParseGen::Option.new
|
104
|
+
:parse_any
|
105
|
+
else
|
106
|
+
raise 'expected description'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/optparsegen.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# The main entry point for OptParseGen.
|
2
|
+
class OptParseGen
|
3
|
+
# Represents a single option.
|
4
|
+
Option = Struct.new(:name, :short, :description)
|
5
|
+
|
6
|
+
# Generates 'optparse' code from the given input and format.
|
7
|
+
def self.generate(input, format)
|
8
|
+
require "optparsegen/#{format}"
|
9
|
+
parser = OptParseGen.const_get("#{format.capitalize}Parser").new(input)
|
10
|
+
options = parser.parse
|
11
|
+
puts options
|
12
|
+
end
|
13
|
+
end
|
data/test/test_scopt.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'optparsegen'
|
3
|
+
require 'optparsegen/scopt'
|
4
|
+
|
5
|
+
class ScoptParserTest < Minitest::Test
|
6
|
+
def test_basic_parse
|
7
|
+
input = 'Usage: myprogram [options]
|
8
|
+
|
9
|
+
--help Shows this usage text.
|
10
|
+
-d, --work-date <value> Generate data for this date. Default: 2017-01-02
|
11
|
+
-i, --input-dir <value> Load input data from this directory. Default: hdfs:///path/to/input
|
12
|
+
-o, --output-dir <value>
|
13
|
+
Output generated data to this directory. Default: hdfs:///path/to/output
|
14
|
+
-x, --extra-jars <jar1>,<jar2>...
|
15
|
+
Extra jars to include.
|
16
|
+
'
|
17
|
+
|
18
|
+
options = parse(input)
|
19
|
+
|
20
|
+
assert_equal(5, options.size)
|
21
|
+
assert_equal('extra-jars help input-dir output-dir work-date', options.map { |o| o.name }.sort.join(' '))
|
22
|
+
assert_equal('Extra jars to include.', options.find { |o| o.name == 'extra-jars' }.description)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_parse_error
|
26
|
+
input = 'Usage: myprogram [options]
|
27
|
+
|
28
|
+
--help
|
29
|
+
'
|
30
|
+
err = assert_raises RuntimeError do
|
31
|
+
parse(input)
|
32
|
+
end
|
33
|
+
assert_equal('expected description', err.message)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def parse(input)
|
38
|
+
OptParseGen::ScoptParser.new(input).parse
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: optparsegen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tyler Sommer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
executables:
|
16
|
+
- optparsegen
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/optparsegen
|
21
|
+
- lib/optparsegen.rb
|
22
|
+
- lib/optparsegen/scopt.rb
|
23
|
+
- test/test_scopt.rb
|
24
|
+
homepage:
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.4.5.1
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: Generate ruby optparse code from usage text.
|
48
|
+
test_files:
|
49
|
+
- test/test_scopt.rb
|