opt_parse_builder 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/.gitignore +2 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +35 -0
- data/LICENSE +23 -0
- data/README.md +434 -0
- data/Rakefile +13 -0
- data/examples/hello_world.rb +20 -0
- data/lib/opt_parse_builder.rb +156 -0
- data/lib/opt_parse_builder/argument.rb +62 -0
- data/lib/opt_parse_builder/argument_builder.rb +193 -0
- data/lib/opt_parse_builder/argument_bundle.rb +30 -0
- data/lib/opt_parse_builder/argument_bundle_builder.rb +34 -0
- data/lib/opt_parse_builder/argument_values.rb +60 -0
- data/lib/opt_parse_builder/banner_argument.rb +11 -0
- data/lib/opt_parse_builder/constant_argument.rb +16 -0
- data/lib/opt_parse_builder/errors.rb +10 -0
- data/lib/opt_parse_builder/formats_operand_name.rb +9 -0
- data/lib/opt_parse_builder/has_value.rb +21 -0
- data/lib/opt_parse_builder/null_argument.rb +4 -0
- data/lib/opt_parse_builder/option_argument.rb +33 -0
- data/lib/opt_parse_builder/optional_operand_argument.rb +29 -0
- data/lib/opt_parse_builder/parser.rb +345 -0
- data/lib/opt_parse_builder/parser_builder.rb +17 -0
- data/lib/opt_parse_builder/required_operand_argument.rb +32 -0
- data/lib/opt_parse_builder/separator_argument.rb +11 -0
- data/lib/opt_parse_builder/splat_operand_argument.rb +22 -0
- data/lib/opt_parse_builder/stable_sort.rb +13 -0
- data/lib/opt_parse_builder/version.rb +6 -0
- data/opt_parse_builder.gemspec +35 -0
- data/rake/bundler.rake +1 -0
- data/rake/default.rake +1 -0
- data/rake/rdoc.rake +7 -0
- data/rake/spec.rake +3 -0
- data/rake/test.rake +2 -0
- metadata +126 -0
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
|
4
|
+
begin
|
5
|
+
Bundler.setup(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
exit e.status_code
|
10
|
+
end
|
11
|
+
|
12
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
13
|
+
Dir["rake/**/*.rake"].sort.each { |path| load path }
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "opt_parse_builder"
|
4
|
+
|
5
|
+
ARG_PARSER = OptParseBuilder.build_parser do |args|
|
6
|
+
args.banner "A simple example"
|
7
|
+
args.add do |arg|
|
8
|
+
arg.key :path
|
9
|
+
arg.required_operand
|
10
|
+
end
|
11
|
+
args.add do |arg|
|
12
|
+
arg.key :verbose
|
13
|
+
arg.on "-v", "--verbose", "Be verbose"
|
14
|
+
end
|
15
|
+
args.separator "Some explanatory text at the bottom"
|
16
|
+
end
|
17
|
+
|
18
|
+
arg_values = ARG_PARSER.parse!
|
19
|
+
p arg_values.verbose
|
20
|
+
p arg_values.path
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require_relative "opt_parse_builder/argument"
|
4
|
+
require_relative "opt_parse_builder/argument_builder"
|
5
|
+
require_relative "opt_parse_builder/argument_bundle"
|
6
|
+
require_relative "opt_parse_builder/argument_bundle_builder"
|
7
|
+
require_relative "opt_parse_builder/argument_values"
|
8
|
+
require_relative "opt_parse_builder/banner_argument"
|
9
|
+
require_relative "opt_parse_builder/constant_argument"
|
10
|
+
require_relative "opt_parse_builder/errors"
|
11
|
+
require_relative "opt_parse_builder/formats_operand_name"
|
12
|
+
require_relative "opt_parse_builder/has_value"
|
13
|
+
require_relative "opt_parse_builder/null_argument"
|
14
|
+
require_relative "opt_parse_builder/option_argument"
|
15
|
+
require_relative "opt_parse_builder/optional_operand_argument"
|
16
|
+
require_relative "opt_parse_builder/parser"
|
17
|
+
require_relative "opt_parse_builder/parser_builder"
|
18
|
+
require_relative "opt_parse_builder/required_operand_argument"
|
19
|
+
require_relative "opt_parse_builder/separator_argument"
|
20
|
+
require_relative "opt_parse_builder/splat_operand_argument"
|
21
|
+
require_relative "opt_parse_builder/stable_sort"
|
22
|
+
|
23
|
+
# The namespace of this library, and the sole entry point. You never
|
24
|
+
# have to (and never should) explicitly refer to any other class or
|
25
|
+
# module of this library than this one. There are a few other classes
|
26
|
+
# you will use, but they will be created for you by methods of this
|
27
|
+
# module.
|
28
|
+
#
|
29
|
+
# Minimal example:
|
30
|
+
#
|
31
|
+
# arg_parser = OptParseBuilder.build_parser
|
32
|
+
# arg_parser.parse!
|
33
|
+
#
|
34
|
+
# An example with a little bit of everything
|
35
|
+
#
|
36
|
+
# arg_parser = OptParseBuilder.build_parser do |p|
|
37
|
+
# parser.banner "A short description of the program"
|
38
|
+
# parser.add do |arg|
|
39
|
+
# arg.key :output_path
|
40
|
+
# arg.required_operand
|
41
|
+
# end
|
42
|
+
# parser.add do |arg|
|
43
|
+
# arg.key :input_paths
|
44
|
+
# arg.splat_operand
|
45
|
+
# end
|
46
|
+
# parser.add do |arg|
|
47
|
+
# arg.key :quiet
|
48
|
+
# arg.on "-q", "--quiet", "Be quiet"
|
49
|
+
# end
|
50
|
+
# parser.add do |arg|
|
51
|
+
# arg.key :size
|
52
|
+
# arg.default 1024
|
53
|
+
# arg.on "--size=N", Integer
|
54
|
+
# arg.on "Size in bytes (default _DEFAULT_)"
|
55
|
+
# end
|
56
|
+
# parser.separator "Explanatory text at the bottom"
|
57
|
+
# end
|
58
|
+
# arg_values = arg_parser.parse!
|
59
|
+
# p arg_values.quiet # nil or true
|
60
|
+
# p arg_values.size # An Integer
|
61
|
+
# p arg_values.output_path # A string
|
62
|
+
# p arg_values.input_paths # An array of strings
|
63
|
+
module OptParseBuilder
|
64
|
+
|
65
|
+
# Create a new parser. If called without a block, returns a parser
|
66
|
+
# than you can then add arguments to:
|
67
|
+
#
|
68
|
+
# arg_parser = OptParseBuilder.build_parser
|
69
|
+
# arg_parser.add do |arg|
|
70
|
+
# arg.key :force
|
71
|
+
# arg.on "--force", "Force dangerous operation"
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# If called with a block, yields itself to the block:
|
75
|
+
#
|
76
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
77
|
+
# args.add do |arg|
|
78
|
+
# arg.key :force
|
79
|
+
# arg.on "--force", "Force dangerous operation"
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Note that the parser constructed using the block form can still
|
84
|
+
# be added onto:
|
85
|
+
#
|
86
|
+
# arg_parser.add do |arg|
|
87
|
+
# arg.key :size
|
88
|
+
# arg.on "--size=N", Integer, "File size in bytes"
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
def self.build_parser
|
92
|
+
parser_builder = ParserBuilder.new
|
93
|
+
yield parser_builder if block_given?
|
94
|
+
parser_builder.parser
|
95
|
+
end
|
96
|
+
|
97
|
+
# Build an argument that can be added to a parser. Yields an
|
98
|
+
# ArgumentBuilder. Returns the argument created by the builder.
|
99
|
+
#
|
100
|
+
# VERBOSE = OptParseBuilder.build_argument do |arg|
|
101
|
+
# arg.key :verbose
|
102
|
+
# arg.on "-v", "--verbose", "Print extra output"
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
106
|
+
# args.add VERBOSE
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# See the README for argument examples.
|
110
|
+
#
|
111
|
+
# Raises BuildError if the argument cannot be built or added.
|
112
|
+
#
|
113
|
+
# This is most useful when you are building a related suite of
|
114
|
+
# programs that share some command-line arguments in common. Most
|
115
|
+
# of the time you will just add the argument using the block form of
|
116
|
+
# OptParseBuilder#add.
|
117
|
+
def self.build_argument
|
118
|
+
builder = ArgumentBuilder.new
|
119
|
+
yield builder
|
120
|
+
builder.argument
|
121
|
+
end
|
122
|
+
|
123
|
+
# Build a bundle of arguments that can be added to a parser
|
124
|
+
# together. Yields an ArgumentBundleBuilder.
|
125
|
+
#
|
126
|
+
# This is useful when you have a group of arguments that go
|
127
|
+
# together:
|
128
|
+
#
|
129
|
+
# bundle = OptParseBuilder.build_bundle do |args|
|
130
|
+
# args.add do |arg|
|
131
|
+
# arg.key :x
|
132
|
+
# op.on "-x", Integer, "X coordinate"
|
133
|
+
# end
|
134
|
+
# args.add do |arg|
|
135
|
+
# arg.key :y
|
136
|
+
# op.on "-y", Integer, "Y coordinate"
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
141
|
+
# args.add bundle
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# Raises BuildError if the argument cannot be built or added.
|
145
|
+
#
|
146
|
+
# This is most useful when you are building a related suite of
|
147
|
+
# programs that share some command-line arguments in common. Most
|
148
|
+
# of the time you will just add the arguments using the block form
|
149
|
+
# of OptParseBuilder#add.
|
150
|
+
def self.build_bundle
|
151
|
+
bundler = ArgumentBundleBuilder.new
|
152
|
+
yield bundler
|
153
|
+
bundler.argument
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
|
3
|
+
# The base class for all arguments. You don't create arguments
|
4
|
+
# explicitly; they are created by for you when you use the builder
|
5
|
+
# API.
|
6
|
+
class Argument
|
7
|
+
|
8
|
+
def key # :nodoc:
|
9
|
+
end
|
10
|
+
|
11
|
+
# Get an argument's value. Returns nil if the argument has no
|
12
|
+
# value. This is made public for the use of a handler proc (See
|
13
|
+
# ArgumentBuilder#handler).
|
14
|
+
def value
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set the argument's value. Does nothing if the argument has no
|
18
|
+
# value. This is made public for the use of a handler proc (See
|
19
|
+
# ArgumentBuilder#handler).
|
20
|
+
def value=(_v)
|
21
|
+
end
|
22
|
+
|
23
|
+
def banner_lines # :nodoc:
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def operand_notation # :nodoc:
|
28
|
+
end
|
29
|
+
|
30
|
+
def separator_lines # :nodoc:
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
def apply_option(_op) # :nodoc:
|
35
|
+
end
|
36
|
+
|
37
|
+
def shift_operand(_argv) # :nodoc:
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset # :nodoc:
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_a # :nodoc:
|
44
|
+
[self]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Convert from a required operand to an optional one, returning a
|
48
|
+
# new argument. Raises an error if that isn't possible.
|
49
|
+
def optional
|
50
|
+
raise BuildError,
|
51
|
+
"cannot convert #{self.class.name} to an optional operand"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Convert from a required operand to an optional one, returning a
|
55
|
+
# new argument. Raises an error if that isn't possible.
|
56
|
+
def required
|
57
|
+
raise BuildError,
|
58
|
+
"cannot convert #{self.class.name} to a required operand"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
|
3
|
+
# Builds arguments using a builder style DSL. You never create an
|
4
|
+
# instance of this class yourself. Instead, an instance is yielded
|
5
|
+
# to you by OptParseBuilder.
|
6
|
+
#
|
7
|
+
# See the README for examples.
|
8
|
+
class ArgumentBuilder
|
9
|
+
|
10
|
+
def initialize # :nodoc:
|
11
|
+
@key = nil
|
12
|
+
@default = nil
|
13
|
+
@on = []
|
14
|
+
@handler = nil
|
15
|
+
@operand_class = nil
|
16
|
+
@operand_help_name = nil
|
17
|
+
@banner_lines = []
|
18
|
+
@separator_lines = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set the argument's key. Accepts either a string or a symbol.
|
22
|
+
def key(v)
|
23
|
+
@key = v.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set the argument's default value. This it the value an argument
|
27
|
+
# has before parsing, or if parsing does not set the value.
|
28
|
+
#
|
29
|
+
# If an argument's default value is not explicitly set, then the
|
30
|
+
# default value is `nil`.
|
31
|
+
def default(v)
|
32
|
+
@default = v
|
33
|
+
end
|
34
|
+
|
35
|
+
# Declares the argument to be an option that is handled by
|
36
|
+
# OptParse. The arguments are passed to OptParse exactly as you
|
37
|
+
# give them, except that the string _DEFAULT_ is replaced with the
|
38
|
+
# argument's default value.
|
39
|
+
#
|
40
|
+
# Simple example:
|
41
|
+
#
|
42
|
+
# arg = OptParseBuilder.build_argument do |arg|
|
43
|
+
# arg.key :quiet
|
44
|
+
# arg.on "-q", "Be very veru quiet", "We're hunting rabbit!"
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# You may split up a long argument list by calling this method
|
48
|
+
# more than once. This is equivalent to the above:
|
49
|
+
#
|
50
|
+
# arg = OptParseBuilder.build_argument do |arg|
|
51
|
+
# arg.key :quiet
|
52
|
+
# arg.on "-q", "Be very veru quiet",
|
53
|
+
# arg.on "We're hunting rabbit!"
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# So that the option's help may print the default without having
|
57
|
+
# to duplicate it, the string _DEFAULT_ is replaced with the
|
58
|
+
# argument's default value:
|
59
|
+
#
|
60
|
+
# arg = OptParseBuilder.build_argument do |arg|
|
61
|
+
# arg.key :size
|
62
|
+
# arg.default 1024
|
63
|
+
# arg.on "--size=N", Integer,
|
64
|
+
# arg.on "Size in bytes (default _DEFAULT_)"
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# When the `--help` text for this argument is printed, it will
|
68
|
+
# read:
|
69
|
+
#
|
70
|
+
# --size-N Size in bytes (default 1024)
|
71
|
+
def on(*option_args)
|
72
|
+
@on.concat(option_args)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set a handler, a proc that will will process the argument's
|
76
|
+
# value. The proc takes two arguments:
|
77
|
+
#
|
78
|
+
# * The Argument
|
79
|
+
# * The value
|
80
|
+
#
|
81
|
+
# If no handler is set, it defaults to
|
82
|
+
#
|
83
|
+
# `->(argument, value) { argument.value = value }
|
84
|
+
#
|
85
|
+
# Applies to these argument types:
|
86
|
+
#
|
87
|
+
# * Simple option
|
88
|
+
# * Option with value
|
89
|
+
#
|
90
|
+
# Example:
|
91
|
+
#
|
92
|
+
# arg = OptParseBuilder.build_argument do |arg|
|
93
|
+
# arg.key :square
|
94
|
+
# arg.on "-v", "Increase verbosity (can give more than once)"
|
95
|
+
# arg.handler do |argument, _value|
|
96
|
+
# argument.value += 1
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
def handler(&block)
|
100
|
+
@handler = block
|
101
|
+
end
|
102
|
+
|
103
|
+
# Add to the banner text shown first in the --help output. You
|
104
|
+
# may call this more than once; each call adds another line of
|
105
|
+
# text to the banner.
|
106
|
+
#
|
107
|
+
# Any type of argument may have banner text.
|
108
|
+
#
|
109
|
+
# See also OptParseBuilder#banner
|
110
|
+
def banner(line)
|
111
|
+
@banner_lines << line
|
112
|
+
end
|
113
|
+
|
114
|
+
# Add to the separator text shown last in the --help output. You
|
115
|
+
# may call this more than once; each call adds another line of
|
116
|
+
# text to the separator.
|
117
|
+
#
|
118
|
+
# Any type of argument may have separator text.
|
119
|
+
#
|
120
|
+
# See also OptParseBuilder#separator
|
121
|
+
def separator(line)
|
122
|
+
@separator_lines << line
|
123
|
+
end
|
124
|
+
|
125
|
+
# Declare the operand to be an optional operand. An optional
|
126
|
+
# operand consumes one argument. If the argument is not present,
|
127
|
+
# value is either the default (if provided), or nil (if no default
|
128
|
+
# was provided).
|
129
|
+
def optional_operand(help_name: nil)
|
130
|
+
check_operand_class_not_set
|
131
|
+
@operand_class = OptionalOperandArgument
|
132
|
+
@operand_help_name = help_name
|
133
|
+
end
|
134
|
+
|
135
|
+
# Declare the operand to be a required operand. A required
|
136
|
+
# operand consumes one argument, generating an error if there is
|
137
|
+
# not one.
|
138
|
+
def required_operand(help_name: nil)
|
139
|
+
check_operand_class_not_set
|
140
|
+
@operand_class = RequiredOperandArgument
|
141
|
+
@operand_help_name = help_name
|
142
|
+
end
|
143
|
+
|
144
|
+
# Declare the argument to be a "splat" operand. A splat operand
|
145
|
+
# consumes all remaining arguments.
|
146
|
+
def splat_operand(help_name: nil)
|
147
|
+
check_operand_class_not_set
|
148
|
+
@operand_class = SplatOperandArgument
|
149
|
+
@operand_help_name = help_name
|
150
|
+
end
|
151
|
+
|
152
|
+
def argument # :nodoc:
|
153
|
+
check_for_build_errors
|
154
|
+
bundle = ArgumentBundle.new
|
155
|
+
unless @banner_lines.empty?
|
156
|
+
bundle << BannerArgument.new(@banner_lines)
|
157
|
+
end
|
158
|
+
unless @separator_lines.empty?
|
159
|
+
bundle << SeparatorArgument.new(@separator_lines)
|
160
|
+
end
|
161
|
+
if !@on.empty?
|
162
|
+
bundle << OptionArgument.new(@key, @default, @on, @handler)
|
163
|
+
elsif @operand_class
|
164
|
+
bundle << @operand_class.new(
|
165
|
+
@key,
|
166
|
+
@default,
|
167
|
+
@operand_help_name,
|
168
|
+
)
|
169
|
+
else
|
170
|
+
if @key || @default
|
171
|
+
bundle << ConstantArgument.new(@key, @default)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
bundle.simplify
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def check_operand_class_not_set
|
180
|
+
if @operand_class
|
181
|
+
raise BuildError, "Argument is already an operand"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def check_for_build_errors
|
186
|
+
if !@on.empty? && @operand_class
|
187
|
+
raise BuildError,
|
188
|
+
"Argument cannot be both an option and an operand"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
class ArgumentBundle < Argument # :nodoc:
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@arguments = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def <<(argument)
|
9
|
+
@arguments << argument
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
@arguments.reduce([]) do |a, arg|
|
14
|
+
a + arg.to_a
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def simplify
|
19
|
+
case @arguments.count
|
20
|
+
when 0
|
21
|
+
NullArgument.new
|
22
|
+
when 1
|
23
|
+
@arguments.first
|
24
|
+
else
|
25
|
+
self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|