acclaim 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +181 -1
- data/lib/acclaim.rb +4 -4
- data/lib/acclaim/command.rb +4 -3
- data/lib/acclaim/command/help.rb +19 -15
- data/lib/acclaim/command/help/template.rb +30 -0
- data/lib/acclaim/command/help/template/command.erb +8 -0
- data/lib/acclaim/command/version.rb +16 -0
- data/lib/acclaim/option.rb +38 -1
- data/lib/acclaim/option/arity.rb +19 -1
- data/lib/acclaim/option/parser.rb +52 -9
- data/lib/acclaim/option/parser/regexp.rb +10 -10
- data/lib/acclaim/option/type.rb +25 -29
- data/lib/acclaim/option/type/date.rb +1 -0
- data/lib/acclaim/option/type/date_time.rb +1 -0
- data/lib/acclaim/option/type/string.rb +1 -0
- data/lib/acclaim/option/type/time.rb +1 -0
- data/lib/acclaim/option/type/uri.rb +1 -0
- data/lib/acclaim/version.rb +20 -1
- metadata +7 -5
data/README.markdown
CHANGED
@@ -2,4 +2,184 @@
|
|
2
2
|
|
3
3
|
Command-line option parsing and command interface.
|
4
4
|
|
5
|
-
|
5
|
+
## Introduction
|
6
|
+
|
7
|
+
Acclaim makes it easy to describe commands and options for a command-line
|
8
|
+
application in a structured manner. Commands are classes that inherit from
|
9
|
+
`Acclaim::Command`:
|
10
|
+
|
11
|
+
require 'acclaim'
|
12
|
+
|
13
|
+
module App
|
14
|
+
class Command < Acclaim::Command
|
15
|
+
option :verbose, '-v', '--verbose'
|
16
|
+
|
17
|
+
when_called do |options, args|
|
18
|
+
puts 'Hello World!'
|
19
|
+
puts args.join ', ' if options.verbose? and args.any?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
$ app --verbose a b c
|
25
|
+
Hello World!
|
26
|
+
a, b, c
|
27
|
+
|
28
|
+
Every command has a set of options and block that is executed when it is called.
|
29
|
+
The options are parsed into an object and passed to the command's block along
|
30
|
+
with the remaining command line arguments. The first argument of the `option`
|
31
|
+
method is the key used to store the value of the option, the other strings are
|
32
|
+
either switches or a description:
|
33
|
+
|
34
|
+
option :verbose, '-v', '--verbose', '--run-verbosely', 'Run verbosely.'
|
35
|
+
|
36
|
+
Acclaim provides especial `help` and `version` commands that may be added to
|
37
|
+
your program. The help command will automatically generate and print a help page
|
38
|
+
for all commands and options. The version command will print your program's
|
39
|
+
version and exit. To use them:
|
40
|
+
|
41
|
+
class App::Command
|
42
|
+
help
|
43
|
+
version '1.2.3'
|
44
|
+
end
|
45
|
+
|
46
|
+
$ app -h
|
47
|
+
$ app --help
|
48
|
+
$ app help
|
49
|
+
|
50
|
+
-v, --verbose, --run-verbosely Run verbosely.
|
51
|
+
-h, --help Show usage information and exit.
|
52
|
+
-v, --version Show version and exit.
|
53
|
+
|
54
|
+
$ app -v
|
55
|
+
$ app --version
|
56
|
+
$ app version
|
57
|
+
1.2.3
|
58
|
+
|
59
|
+
Both methods can take a hash as the last parameter, which accepts the same
|
60
|
+
configurations. If you don't want the options, or if you want to specify a
|
61
|
+
different set of switches or a different description, you can write something
|
62
|
+
like:
|
63
|
+
|
64
|
+
help options: false
|
65
|
+
version '1.2.3', switches: %w(--version),
|
66
|
+
description: "Shows this program's version."
|
67
|
+
|
68
|
+
### Subcommands
|
69
|
+
|
70
|
+
Essentially, a command given to another command. Subcommands benefit from all
|
71
|
+
the option processing done by its parents. To create one, you simply inherit
|
72
|
+
from an existing command:
|
73
|
+
|
74
|
+
class App::Command::Do < App::Command
|
75
|
+
|
76
|
+
# option is aliased as opt
|
77
|
+
opt :what, '--what', 'What to do.', default: 'something', arity: [1, 0]
|
78
|
+
|
79
|
+
# when_called is aliased as action
|
80
|
+
action do |options, args|
|
81
|
+
puts "Doing #{options.what} with #{args.join ', '}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
$ app do x, y, z
|
86
|
+
Doing something with x, y, z
|
87
|
+
|
88
|
+
$ app do --what x, y, z
|
89
|
+
Doing x with y, z
|
90
|
+
|
91
|
+
Options may also take an Hash as the last parameter. Among the things that can
|
92
|
+
be configured is the default value for the option and its arity. The default
|
93
|
+
value is `nil` by default and is used if the option is not given. The arity of
|
94
|
+
the option represents the minimum number of arguments it __must__ take and the
|
95
|
+
number of optional arguments it __may__ take. It is specified as an array in the
|
96
|
+
form `[minimum, optional]`. Options that take zero arguments, which is the
|
97
|
+
default, are flags.
|
98
|
+
|
99
|
+
So, options can take from zero to an unlimited number of arguments, right?
|
100
|
+
|
101
|
+
class App::Command::Do < App::Command
|
102
|
+
|
103
|
+
# Negative number of optional arguments denote unlimited argument count
|
104
|
+
opt :what, '--what', default: 'something', arity: [0, -1]
|
105
|
+
|
106
|
+
action do |options, args|
|
107
|
+
what = (options.what.join ', ' rescue options.what)
|
108
|
+
subjects = args.join ', '
|
109
|
+
puts "Doing #{what} with #{subjects}"
|
110
|
+
end
|
111
|
+
|
112
|
+
$ app do --what x y z
|
113
|
+
Doing x, y, z with
|
114
|
+
|
115
|
+
Now, our option is eating up all the arguments in the command line! Hope is not
|
116
|
+
lost, however. Even though the list of arguments may be unlimited, parsing will
|
117
|
+
still stop if either another switch or an argument separator is encountered. An
|
118
|
+
argument separator is a group of two or more dashes:
|
119
|
+
|
120
|
+
$ app do --what w x -- y z
|
121
|
+
Doing w, x with y, z
|
122
|
+
|
123
|
+
An important thing to understand is that options are not parsed all at once;
|
124
|
+
first, the main command's options are parsed, then the remaining arguments are
|
125
|
+
searched for subcommands. If one is found, its options are parsed, the remaining
|
126
|
+
arguments are searched and so on. If a subcommand can't be found, the most
|
127
|
+
specific command found is executed.
|
128
|
+
|
129
|
+
Options are deleted from the command line as they are parsed, so the following
|
130
|
+
will not work:
|
131
|
+
|
132
|
+
$ app do --what w x --verbose y z
|
133
|
+
Doing w, x, y, z with
|
134
|
+
|
135
|
+
This happens because `--verbose` is an option of the main command. Since it will
|
136
|
+
be parsed and deleted from the argument array, when `do` gets its turn it will
|
137
|
+
be parsing the `%w(--what w x y z)` array.
|
138
|
+
|
139
|
+
### Option Type Handlers
|
140
|
+
|
141
|
+
Arguments given to options are by default strings. To make life easier, you may
|
142
|
+
specify the type of the arguments by passing a class among the arguments:
|
143
|
+
|
144
|
+
class App::Command::Do
|
145
|
+
opt :when, '--when', 'When to do it.', Date,
|
146
|
+
default: Date.today, arity: [1,0]
|
147
|
+
|
148
|
+
action do |options, args|
|
149
|
+
what = (options.what.join ', ' rescue options.what)
|
150
|
+
subjects = args.join ', '
|
151
|
+
date = options.when
|
152
|
+
puts 'Merry Christmas!' if date.month == 12 and date.day == 25
|
153
|
+
date = date.strftime '%m/%d/%Y'
|
154
|
+
puts "Doing #{what} with #{subjects} on #{date}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
$ app do --what w x --when 2011-12-25 y z
|
159
|
+
Merry Christmas!
|
160
|
+
Doing w, x with y, z on 12/25/2011
|
161
|
+
|
162
|
+
There are type handlers included for `Date`s, `Time`s, `DateTime`s, `URI`s and
|
163
|
+
`String`s, but if you need more you can always write your own:
|
164
|
+
|
165
|
+
Acclaim::Option::Type.add_handler_for(Symbol) { |str| str.to_sym }
|
166
|
+
|
167
|
+
class App::Command::Handle < App::Command
|
168
|
+
opt :syms, '--symbol', '--symbols', Symbol, arity: [1,-1], required: true
|
169
|
+
|
170
|
+
when_called do |options, args|
|
171
|
+
options.syms.each { |sym| puts "#{sym.class} => #{sym.inspect}" }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
$ app handle --symbols a s d
|
176
|
+
Symbol => :a
|
177
|
+
Symbol => :s
|
178
|
+
Symbol => :d
|
179
|
+
|
180
|
+
`add_handler_for` takes a class and a block, which will be called for every
|
181
|
+
argument of that class that must be parsed.
|
182
|
+
|
183
|
+
---
|
184
|
+
|
185
|
+
Originally extracted from [Safeguard](https://github.com/matheusmoreira/safeguard).
|
data/lib/acclaim.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
+
# Acclaim is a command line option parsing and command interface for Ruby.
|
2
|
+
module Acclaim
|
3
|
+
end
|
4
|
+
|
1
5
|
%w(
|
2
6
|
|
3
7
|
command
|
4
8
|
option
|
5
|
-
option/arity
|
6
|
-
option/parser
|
7
|
-
option/parser/regexp
|
8
|
-
option/values
|
9
9
|
version
|
10
10
|
|
11
11
|
).each { |file| require file.prepend 'acclaim/' }
|
data/lib/acclaim/command.rb
CHANGED
@@ -81,12 +81,12 @@ module Acclaim
|
|
81
81
|
|
82
82
|
# Adds help subcommand and options to this command.
|
83
83
|
def help(opts = {})
|
84
|
-
|
84
|
+
Help.create(self, opts)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Adds help subcommand and options to this command.
|
88
88
|
def version(version_string, opts = {})
|
89
|
-
|
89
|
+
Version.create(self, version_string, opts)
|
90
90
|
end
|
91
91
|
|
92
92
|
# Parses the argument array using this command's set of options.
|
@@ -113,6 +113,7 @@ module Acclaim
|
|
113
113
|
args.delete subcommand.line
|
114
114
|
subcommand.invoke(opts, args)
|
115
115
|
else
|
116
|
+
args.delete_if { |arg| arg =~ Option::Parser::Regexp::ARGUMENT_SEPARATOR }
|
116
117
|
execute(opts, args)
|
117
118
|
end
|
118
119
|
end
|
@@ -120,7 +121,7 @@ module Acclaim
|
|
120
121
|
# Calls this command's action block with the given option values and
|
121
122
|
# arguments.
|
122
123
|
def execute(opts, args)
|
123
|
-
@action.call opts, args
|
124
|
+
@action.call opts, args if @action
|
124
125
|
end
|
125
126
|
|
126
127
|
alias :call :execute
|
data/lib/acclaim/command/help.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
+
require 'acclaim/command/help/template'
|
2
|
+
|
1
3
|
module Acclaim
|
2
4
|
class Command
|
3
5
|
|
4
6
|
# Module which adds help support to a command.
|
5
7
|
module Help
|
6
8
|
|
9
|
+
# Adds a special help option to the given +command+.
|
10
|
+
#
|
11
|
+
# The last argument is an option +Hash+, which accepts the following
|
12
|
+
# options:
|
13
|
+
#
|
14
|
+
# [:switches] The switches used when creating the help option.
|
7
15
|
def self.add_options_to!(command, opts = {})
|
8
16
|
switches = opts.fetch :switches, %w(-h --help)
|
9
17
|
description = opts.fetch :description, 'Show usage information and exit.'
|
@@ -12,6 +20,16 @@ module Acclaim
|
|
12
20
|
|
13
21
|
private_class_method :add_options_to!
|
14
22
|
|
23
|
+
# Creates a help subcommand that inherits from the given +base+ command
|
24
|
+
# and stores the class in the +Help+ constant of +base+. When called, the
|
25
|
+
# command displays a help screen including information for all commands
|
26
|
+
# and then exits.
|
27
|
+
#
|
28
|
+
# The last argument is an option +Hash+, which accepts the following
|
29
|
+
# options:
|
30
|
+
#
|
31
|
+
# [:options] If +true+, will add a help option to the +base+ command.
|
32
|
+
# [:switches] The switches used when creating the help option.
|
15
33
|
def self.create(base, opts = {})
|
16
34
|
if opts.fetch :options, true
|
17
35
|
add_options_to! base, opts
|
@@ -27,21 +45,7 @@ module Acclaim
|
|
27
45
|
# Displays a very simple help screen for the given command and all its
|
28
46
|
# subcommands.
|
29
47
|
def self.display_help_for(command)
|
30
|
-
|
31
|
-
# Look into how to code a text formatter later.
|
32
|
-
help_string = ''
|
33
|
-
command.options.tap do |options|
|
34
|
-
if options.any?
|
35
|
-
help_string << "\nCommand '#{command.line}':\n\n" unless command.root?
|
36
|
-
max = options.map { |option| option.names.join(', ').length }.max
|
37
|
-
options.each do |option|
|
38
|
-
switches = option.names.join ', '
|
39
|
-
help_string << ' ' * 4 << switches << ' ' * (4 + max - switches.length)
|
40
|
-
help_string << option.description << "\n"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
puts help_string unless help_string.empty?
|
48
|
+
puts Template.for(command) if command.options.any?
|
45
49
|
command.subcommands.each { |subcommand| display_help_for subcommand }
|
46
50
|
end
|
47
51
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Acclaim
|
4
|
+
class Command
|
5
|
+
module Help
|
6
|
+
|
7
|
+
# Manages help templates.
|
8
|
+
module Template
|
9
|
+
|
10
|
+
# Loads an ERB template file from the
|
11
|
+
# +lib/acclaim/command/help/template+ folder and instantiates a new ERB
|
12
|
+
# instance with its contents.
|
13
|
+
def self.load(template)
|
14
|
+
filename = File.join File.dirname(__FILE__), 'template', template
|
15
|
+
ERB.new File.read(filename), nil, '%<>'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Computes the result of the template +file+ using the +command+'s
|
19
|
+
# binding.
|
20
|
+
def self.for(command, file = 'command.erb')
|
21
|
+
template = self.load file
|
22
|
+
b = command.instance_eval { binding }
|
23
|
+
template.result b
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,6 +4,12 @@ module Acclaim
|
|
4
4
|
# Module which adds version query support to a command.
|
5
5
|
module Version
|
6
6
|
|
7
|
+
# Adds a special version option to the given +command+.
|
8
|
+
#
|
9
|
+
# The last argument is an option +Hash+, which accepts the following
|
10
|
+
# options:
|
11
|
+
#
|
12
|
+
# [:switches] The switches used when creating the version option.
|
7
13
|
def self.add_options_to!(command, opts = {})
|
8
14
|
switches = opts.fetch :switches, %w(-v --version)
|
9
15
|
description = opts.fetch :description, 'Show version and exit.'
|
@@ -12,6 +18,16 @@ module Acclaim
|
|
12
18
|
|
13
19
|
private_class_method :add_options_to!
|
14
20
|
|
21
|
+
# Creates a <tt>version</tt> subcommand that inherits from the given
|
22
|
+
# +base+ command and stores the class in the +Version+ constant of +base+.
|
23
|
+
# When called, the command displays the +version_string+ of the program
|
24
|
+
# and then exits.
|
25
|
+
#
|
26
|
+
# The last argument is an option +Hash+, which accepts the following
|
27
|
+
# options:
|
28
|
+
#
|
29
|
+
# [:options] If +true+, will add a version option to the +base+ command.
|
30
|
+
# [:switches] The switches used when creating the version option.
|
15
31
|
def self.create(base, version_string, opts = {})
|
16
32
|
if opts.fetch :options, true
|
17
33
|
add_options_to! base, opts
|
data/lib/acclaim/option.rb
CHANGED
@@ -9,6 +9,33 @@ module Acclaim
|
|
9
9
|
|
10
10
|
attr_accessor :key, :names, :description, :type, :default, :handler
|
11
11
|
|
12
|
+
# Initializes a command line option. The +key+ is the object used to
|
13
|
+
# associate this option with a value. The other arguments may be:
|
14
|
+
#
|
15
|
+
# [short switches] Strings starting with <tt>'-'</tt>, like:
|
16
|
+
# <tt>'-h'</tt>; <tt>'-v'</tt>
|
17
|
+
# [long switches] Strings starting with <tt>'--'</tt>, like:
|
18
|
+
# <tt>'--help'</tt>; <tt>'--version'</tt>
|
19
|
+
# [description] Strings that don't start with either <tt>'-'</tt>
|
20
|
+
# nor <tt>'--'</tt>, like:
|
21
|
+
# <tt>'Display this help text and exit.'</tt>;
|
22
|
+
# <tt>'Display version and exit.'</tt>
|
23
|
+
# [class] The <tt>Class</tt> which will be used in parameter
|
24
|
+
# conversion. The default is <tt>String</tt>.
|
25
|
+
#
|
26
|
+
# The last argument can be a hash of options, which may specify:
|
27
|
+
#
|
28
|
+
# [:arity] The number of required and optional arguments. See Arity for
|
29
|
+
# defails.
|
30
|
+
# [:default] The default value for this option.
|
31
|
+
# [:required] Whether or not the option must be present on the command
|
32
|
+
# line.
|
33
|
+
#
|
34
|
+
# Additionally, if a block is given, it will be called when the option is
|
35
|
+
# parsed with a Values instance and the parameters given to the option. The
|
36
|
+
# parameters will already be converted to this option's specified type; if
|
37
|
+
# this is not desirable consider not specifying a class to the option or
|
38
|
+
# registering a custom type handler.
|
12
39
|
def initialize(key, *args, &block)
|
13
40
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
14
41
|
matches = args.select { |arg| arg.is_a? String }.group_by do |arg|
|
@@ -25,18 +52,24 @@ module Acclaim
|
|
25
52
|
self.handler = block
|
26
53
|
end
|
27
54
|
|
55
|
+
# Converts all given arguments using the type handler for this option's
|
56
|
+
# type.
|
28
57
|
def convert_parameters(*args)
|
29
58
|
args.map { |arg| Type[type].call arg }
|
30
59
|
end
|
31
60
|
|
61
|
+
# Returns true if the given string is equal to any of this option's names.
|
32
62
|
def =~(str)
|
33
63
|
names.include? str.strip
|
34
64
|
end
|
35
65
|
|
66
|
+
# Returns this option's arity. See Arity for details.
|
36
67
|
def arity
|
37
68
|
@arity ||= Arity.new
|
38
69
|
end
|
39
70
|
|
71
|
+
# Sets this option's arity. The value given may be an Arity, or an array in
|
72
|
+
# the form of <tt>[ required_parameters, optional_parameters ]</tt>.
|
40
73
|
def arity=(arity_or_array)
|
41
74
|
@arity = if arity.nil? or arity_or_array.is_a? Arity
|
42
75
|
arity_or_array
|
@@ -45,18 +78,22 @@ module Acclaim
|
|
45
78
|
end
|
46
79
|
end
|
47
80
|
|
81
|
+
# Whether or not this option is required on the command line.
|
48
82
|
def required?
|
49
83
|
@required
|
50
84
|
end
|
51
85
|
|
86
|
+
# Sets whether or not this option is required.
|
52
87
|
def required=(value)
|
53
|
-
@required = value
|
88
|
+
@required = (value ? true : false)
|
54
89
|
end
|
55
90
|
|
91
|
+
# Require that this option be given on the command line.
|
56
92
|
def require
|
57
93
|
self.required = true
|
58
94
|
end
|
59
95
|
|
96
|
+
# Returns true if this option takes no arguments.
|
60
97
|
def flag?
|
61
98
|
not arity or arity == [0, 0]
|
62
99
|
end
|
data/lib/acclaim/option/arity.rb
CHANGED
@@ -39,6 +39,8 @@ module Acclaim
|
|
39
39
|
bound? ? minimum + optional : nil
|
40
40
|
end
|
41
41
|
|
42
|
+
# Converts this arity to an array in the form of
|
43
|
+
# <tt>[ required, optional ]</tt>.
|
42
44
|
def to_a
|
43
45
|
[ minimum, optional ]
|
44
46
|
end
|
@@ -46,10 +48,16 @@ module Acclaim
|
|
46
48
|
alias :to_ary :to_a
|
47
49
|
alias :to_array :to_a
|
48
50
|
|
51
|
+
# Equivalent to <tt>to_a.hash</tt>.
|
49
52
|
def hash
|
50
53
|
to_a.hash
|
51
54
|
end
|
52
55
|
|
56
|
+
# Converts both +self+ and +arity+ to an array and compares them. This is
|
57
|
+
# so that comparing directly with an array is possible:
|
58
|
+
#
|
59
|
+
# Arity.new(1, 3) == [1, 3]
|
60
|
+
# => true
|
53
61
|
def ==(arity)
|
54
62
|
to_a == arity.to_a
|
55
63
|
end
|
@@ -57,11 +65,21 @@ module Acclaim
|
|
57
65
|
alias :eql? :==
|
58
66
|
alias :=== :==
|
59
67
|
|
68
|
+
# Returns a string in the following format:
|
69
|
+
#
|
70
|
+
# Arity: minimum +optional
|
71
|
+
#
|
72
|
+
# The value of +optional+ will be <tt>'infinite'</tt> if #unlimited? is
|
73
|
+
# +true+.
|
60
74
|
def to_s
|
61
75
|
"Arity: #{minimum} +#{unlimited? ? 'infinite' : optional}"
|
62
76
|
end
|
63
77
|
|
64
|
-
|
78
|
+
# Returns the output of #to_s, enclosed in angle brackets (<tt>'<'</tt>
|
79
|
+
# and <tt>'>'</tt>).
|
80
|
+
def inspect
|
81
|
+
"<#{to_s}>"
|
82
|
+
end
|
65
83
|
|
66
84
|
end
|
67
85
|
|
@@ -9,12 +9,19 @@ module Acclaim
|
|
9
9
|
|
10
10
|
include Parser::Regexp
|
11
11
|
|
12
|
+
# Errors raised by the parser.
|
12
13
|
class Error < StandardError
|
13
14
|
|
15
|
+
# Raises an Error with the following error message:
|
16
|
+
#
|
17
|
+
# Wrong number of arguments (actual for minimum)
|
14
18
|
def self.raise_wrong_arg_number(actual, minimum, optional)
|
15
19
|
raise self, "Wrong number of arguments (#{actual} for #{minimum})"
|
16
20
|
end
|
17
21
|
|
22
|
+
# Raises an Error with the following error message:
|
23
|
+
#
|
24
|
+
# Missing required argument (arg)
|
18
25
|
def self.raise_missing_arg(arg)
|
19
26
|
raise self, "Missing required argument (#{arg})"
|
20
27
|
end
|
@@ -32,9 +39,22 @@ module Acclaim
|
|
32
39
|
end
|
33
40
|
|
34
41
|
# Parses the meaning of the options given to this parser. If none were
|
35
|
-
# given, the argument array will
|
42
|
+
# given, the argument array will be preprocessed only. Any parsed options
|
36
43
|
# and arguments will be removed from the argument array, so pass in a
|
37
44
|
# duplicate if you need the original.
|
45
|
+
#
|
46
|
+
# include Acclaim
|
47
|
+
#
|
48
|
+
# args = %w(-F log.txt --verbose arg1 arg2)
|
49
|
+
# options = []
|
50
|
+
# options << Option.new(:file, '-F', arity: [1,0], required: true)
|
51
|
+
# options << Option.new(:verbose, '--verbose')
|
52
|
+
#
|
53
|
+
# Option::Parser.new(args, options).parse!
|
54
|
+
# => #<Acclaim::Option::Values:0x00000002a2fee8 @options={:file=>"log.txt", :verbose=>true}>
|
55
|
+
#
|
56
|
+
# args
|
57
|
+
# => ["arg1", "arg2"]
|
38
58
|
def parse!
|
39
59
|
preprocess_argv!
|
40
60
|
parse_values! unless options.nil?
|
@@ -42,15 +62,16 @@ module Acclaim
|
|
42
62
|
|
43
63
|
private
|
44
64
|
|
45
|
-
#
|
65
|
+
# Preprocesses the argument array.
|
46
66
|
def preprocess_argv!
|
47
67
|
split_multiple_short_options!
|
48
68
|
normalize_parameters!
|
49
|
-
# TODO: normalize parameter formats?
|
50
|
-
# -sPARAM1[,PARAM2,PARAM3...] - possibly incompatible with split_multiple_short_options!
|
51
69
|
argv.compact!
|
52
70
|
end
|
53
71
|
|
72
|
+
# Splits multiple short options.
|
73
|
+
#
|
74
|
+
# %w(-abcdef PARAM1 PARAM2) => %w(-a -b -c -d -e -f PARAM1 PARAM2)
|
54
75
|
def split_multiple_short_options!
|
55
76
|
argv.find_all { |arg| arg =~ MULTIPLE_SHORT_SWITCHES }.each do |multiples|
|
56
77
|
multiples_index = argv.index multiples
|
@@ -60,6 +81,12 @@ module Acclaim
|
|
60
81
|
end
|
61
82
|
end
|
62
83
|
|
84
|
+
# Splits switches that are connected to a comma-separated parameter list.
|
85
|
+
#
|
86
|
+
# %w(--switch=) => %w(--switch)
|
87
|
+
# %w(--switch=PARAM1,PARAM2) => %w(--switch PARAM1 PARAM2)
|
88
|
+
# %w(--switch=PARAM1,) => %w(--switch PARAM1)
|
89
|
+
# %w(--switch=,PARAM2) => [ '--switch', '', 'PARAM2' ]
|
63
90
|
def normalize_parameters!
|
64
91
|
argv.find_all { |arg| arg =~ SWITCH_PARAM_EQUALS }.each do |switch|
|
65
92
|
switch_index = argv.index switch
|
@@ -70,20 +97,22 @@ module Acclaim
|
|
70
97
|
end
|
71
98
|
end
|
72
99
|
|
100
|
+
# Parses the options and their arguments, associating that information
|
101
|
+
# with a Values instance.
|
73
102
|
def parse_values!
|
74
|
-
Values.new.tap do |
|
103
|
+
Values.new.tap do |values|
|
75
104
|
options.each do |option|
|
76
105
|
key = option.key
|
77
|
-
|
106
|
+
values[key] = option.default unless values[key]
|
78
107
|
switches = argv.find_all { |switch| option =~ switch }
|
79
108
|
if switches.any?
|
80
109
|
if option.flag?
|
81
|
-
set_option_value option,
|
110
|
+
set_option_value option, values
|
111
|
+
argv.delete *switches
|
82
112
|
else
|
83
113
|
switches.each do |switch|
|
84
114
|
params = extract_parameters_of! option, switch
|
85
|
-
|
86
|
-
set_option_value option, options_instance, params
|
115
|
+
set_option_value option, values, params
|
87
116
|
end
|
88
117
|
end
|
89
118
|
else
|
@@ -93,6 +122,14 @@ module Acclaim
|
|
93
122
|
end
|
94
123
|
end
|
95
124
|
|
125
|
+
# Finds the +switch+ in #argv and scans the next +option.arity.total+
|
126
|
+
# elements if +option.arity.bound?+ is +true+, or all parameters
|
127
|
+
# otherwise. In either case, the algorithm will stop if it finds +nil+,
|
128
|
+
# another switch or an argument separator among the parameters.
|
129
|
+
#
|
130
|
+
# Deletes the switch and every value that was extracted from #argv. Raises
|
131
|
+
# an Error if the number of parameters found is less than
|
132
|
+
# +option.arity.required+.
|
96
133
|
def extract_parameters_of!(option, switch)
|
97
134
|
arity = option.arity
|
98
135
|
switch_index = argv.index switch
|
@@ -113,9 +150,15 @@ module Acclaim
|
|
113
150
|
end
|
114
151
|
count = values.count
|
115
152
|
Error.raise_wrong_arg_number count, *arity if count < arity.required
|
153
|
+
argv.delete switch
|
116
154
|
values.each { |value| argv.delete value }
|
117
155
|
end
|
118
156
|
|
157
|
+
# If the option has an custom handler associated, call it with the
|
158
|
+
# parameters. Otherwise, if the option is a flag, the value corresponding
|
159
|
+
# to the option's key will be set to +true+, if it is not, the value will
|
160
|
+
# be set to params.first+ if +params+ contains only one element or to
|
161
|
+
# +params+ if it contains more.
|
119
162
|
def set_option_value(option, values, params = [])
|
120
163
|
params = option.convert_parameters *params
|
121
164
|
if handler = option.handler
|
@@ -7,13 +7,13 @@ module Acclaim
|
|
7
7
|
|
8
8
|
# Regular expression for a short option switch.
|
9
9
|
#
|
10
|
-
# Matches strings that begin with a single dash and
|
11
|
-
#
|
10
|
+
# Matches strings that begin with a single dash and contains only one
|
11
|
+
# word character or digit before the end of the string.
|
12
12
|
#
|
13
|
-
# Examples: <tt>-s; -
|
13
|
+
# Examples: <tt>-s; -5; -_</tt>
|
14
14
|
#
|
15
15
|
# <tt>'-mult'</tt> will be split into <tt>%w(-m -u -l -t)</tt>.
|
16
|
-
SHORT_SWITCH = /\A-[\w\d]
|
16
|
+
SHORT_SWITCH = /\A-[\w\d]\Z/
|
17
17
|
|
18
18
|
# Regular expression for a long option switch.
|
19
19
|
#
|
@@ -26,12 +26,6 @@ module Acclaim
|
|
26
26
|
# --_private-option; --1-1</tt>
|
27
27
|
LONG_SWITCH = /\A--[\w\d]+(-[\w\d]+)*\Z/
|
28
28
|
|
29
|
-
# Regular expression for any kind of option switch.
|
30
|
-
#
|
31
|
-
# Matches either a SHORT_SWITCH or a LONG_SWITCH. See their descriptions
|
32
|
-
# for details.
|
33
|
-
SWITCH = /(#{SHORT_SWITCH})|(#{LONG_SWITCH})/
|
34
|
-
|
35
29
|
# Regular expression for multiple short options in a single "short"
|
36
30
|
# switch.
|
37
31
|
#
|
@@ -66,6 +60,12 @@ module Acclaim
|
|
66
60
|
# of those isn't a decision for a preprocessor.
|
67
61
|
SWITCH_PARAM_EQUALS = /\A--[\w\d]+(-?[\w\d]+)*=(,*[\w\d]*)*\Z/
|
68
62
|
|
63
|
+
# Regular expression for any kind of option switch.
|
64
|
+
#
|
65
|
+
# Matches anything that matches any of the other switch regular
|
66
|
+
# expressions.
|
67
|
+
SWITCH = /(#{SHORT_SWITCH})|(#{LONG_SWITCH})|(#{MULTIPLE_SHORT_SWITCHES})|(#{SWITCH_PARAM_EQUALS})/
|
68
|
+
|
69
69
|
# Regular expression for the string that separates options and their
|
70
70
|
# parameters from arguments like filenames.
|
71
71
|
#
|
data/lib/acclaim/option/type.rb
CHANGED
@@ -4,45 +4,41 @@ module Acclaim
|
|
4
4
|
# Associates a class with a handler block.
|
5
5
|
module Type
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
table.each &block
|
13
|
-
end
|
7
|
+
# Yields class, proc pairs if a block was given. Returns an enumerator
|
8
|
+
# otherwise.
|
9
|
+
def self.each(&block)
|
10
|
+
table.each &block
|
11
|
+
end
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
# Returns all registered classes.
|
14
|
+
def self.all
|
15
|
+
table.keys
|
16
|
+
end
|
19
17
|
|
20
|
-
|
18
|
+
# Registers a handler for a class.
|
19
|
+
def self.register(klass, &block)
|
20
|
+
table[klass] = block
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
# Returns the handler for the given class.
|
24
|
+
def self.handler_for(klass)
|
25
|
+
table[klass]
|
26
|
+
end
|
26
27
|
|
28
|
+
class << self
|
29
|
+
alias registered all
|
27
30
|
alias add_handler_for register
|
28
31
|
alias accept register
|
29
|
-
|
30
|
-
# Returns the handler for the given class.
|
31
|
-
def handler_for(klass)
|
32
|
-
table[klass]
|
33
|
-
end
|
34
|
-
|
35
32
|
alias [] handler_for
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def table
|
41
|
-
@table ||= {}
|
42
|
-
end
|
43
|
-
|
35
|
+
# The hash used to associate classes with their handlers.
|
36
|
+
def self.table
|
37
|
+
@table ||= {}
|
44
38
|
end
|
45
39
|
|
40
|
+
private_class_method :table
|
41
|
+
|
46
42
|
end
|
47
43
|
|
48
44
|
end
|
data/lib/acclaim/version.rb
CHANGED
@@ -1,11 +1,30 @@
|
|
1
1
|
module Acclaim
|
2
|
+
|
3
|
+
# Acclaim's version.
|
2
4
|
module Version
|
3
5
|
|
6
|
+
# Major version.
|
7
|
+
#
|
8
|
+
# Increments denote backward-incompatible changes and additions.
|
4
9
|
MAJOR = 0
|
10
|
+
|
11
|
+
# Minor version.
|
12
|
+
#
|
13
|
+
# Increments denote backward-compatible changes and additions.
|
5
14
|
MINOR = 0
|
6
|
-
|
15
|
+
|
16
|
+
# Patch version.
|
17
|
+
#
|
18
|
+
# Increments denote changes in implementation.
|
19
|
+
PATCH = 5
|
20
|
+
|
21
|
+
# Build version.
|
22
|
+
#
|
23
|
+
# Used for pre-release versions.
|
7
24
|
BUILD = nil
|
8
25
|
|
26
|
+
# Complete version string, which is every individual version number joined
|
27
|
+
# by a dot (<tt>'.'</tt>), in descending order of prescedence.
|
9
28
|
STRING = [ MAJOR, MINOR, PATCH, BUILD ].compact.join '.'
|
10
29
|
|
11
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acclaim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-12-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &8505620 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *8505620
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rookie
|
27
|
-
requirement: &
|
27
|
+
requirement: &8505100 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *8505100
|
36
36
|
description: Command-line option parser and command interface.
|
37
37
|
email: matheus.a.m.moreira@gmail.com
|
38
38
|
executables: []
|
@@ -49,6 +49,8 @@ files:
|
|
49
49
|
- lib/acclaim.rb
|
50
50
|
- lib/acclaim/command.rb
|
51
51
|
- lib/acclaim/command/help.rb
|
52
|
+
- lib/acclaim/command/help/template.rb
|
53
|
+
- lib/acclaim/command/help/template/command.erb
|
52
54
|
- lib/acclaim/command/version.rb
|
53
55
|
- lib/acclaim/option.rb
|
54
56
|
- lib/acclaim/option/arity.rb
|