acclaim 0.0.4 → 0.0.5
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.
- 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
|