opt_parse_builder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|