clasp-ruby 0.20.1 → 0.22.0.1
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 +5 -5
- data/README.md +43 -21
- data/examples/cr-example.rb +2 -11
- data/examples/flag_and_option_specifications.md +15 -0
- data/lib/clasp/arguments.rb +70 -21
- data/lib/clasp/clasp.rb +9 -0
- data/lib/clasp/cli.rb +29 -25
- data/lib/clasp/specifications.rb +108 -16
- data/lib/clasp/util/exceptions.rb +82 -0
- data/lib/clasp/util/value_parser.rb +222 -0
- data/lib/clasp/version.rb +4 -2
- data/test/unit/tc_cli.rb +4 -0
- data/test/unit/tc_default_value.rb +21 -3
- data/test/unit/tc_option_required.rb +3 -3
- data/test/unit/tc_typed_options.rb +310 -0
- data/test/unit/tc_with_action.rb +50 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bdf2add70e2d8e134e6759718fabde89ecb5c158
|
4
|
+
data.tar.gz: dcf9e41a17a28f53406daef64bdba1f614f2a080
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d329ce03d0057446f877425faec12da111253f0bb51dbcd0d1e619d0f3e7f5dcc781b20b18ffbb65eb796011b3021d208e1d391881754ec3ecd61e6efad49186
|
7
|
+
data.tar.gz: 63873b0a897f4d854d6f4c80e5605cd68ebecdb4591361662cfa075292ac9c4a69ae8aa8f09ab97446db675fe5611cca41bc7ea83f01853bafb55722b5093fee
|
data/README.md
CHANGED
@@ -1,9 +1,27 @@
|
|
1
1
|
# CLASP.Ruby
|
2
|
-
Command-Line Argument Sorting and Parsing for Ruby
|
2
|
+
Command-Line Argument Sorting and Parsing, for Ruby
|
3
3
|
|
4
4
|
[](https://badge.fury.io/rb/clasp-ruby)
|
5
5
|
|
6
|
-
##
|
6
|
+
## Table of Contents
|
7
|
+
|
8
|
+
1. [Introduction](#introduction)
|
9
|
+
2. [Installation](#installation)
|
10
|
+
3. [Components](#components)
|
11
|
+
4. [Examples](#examples)
|
12
|
+
5. [Project Information](#project-information)
|
13
|
+
|
14
|
+
## Introduction
|
15
|
+
|
16
|
+
**CLASP** stands for Command-Line Argument Sorting and
|
17
|
+
Parsing. The first CLASP library was a C library with a C++ wrapper. There
|
18
|
+
have been several implementations in other languages. **CLASP.Ruby** is the
|
19
|
+
Ruby version.
|
20
|
+
|
21
|
+
All CLASP libraries provide the facilities to **C**ommand **L**ine
|
22
|
+
**I**nterface (**CLI**) programs as described in detail below.
|
23
|
+
|
24
|
+
## Installation
|
7
25
|
|
8
26
|
Install via **gem** as in:
|
9
27
|
|
@@ -19,19 +37,7 @@ Use via **require**, as in:
|
|
19
37
|
require 'clasp'
|
20
38
|
```
|
21
39
|
|
22
|
-
##
|
23
|
-
|
24
|
-
Examples are provided in the ```examples``` directory, along with a markdown description for each. A detailed list TOC of them is provided in [EXAMPLES.md](./EXAMPLES.md).
|
25
|
-
|
26
|
-
## Description
|
27
|
-
|
28
|
-
**CLASP** stands for **C**ommand-**L**ine **A**rgument **S**orting and
|
29
|
-
**P**arsing. The first CLASP library was a C library with a C++ wrapper. There
|
30
|
-
have been several implementations in other languages. **CLASP.Ruby** is the
|
31
|
-
Ruby version.
|
32
|
-
|
33
|
-
All CLASP libraries provide the following facilities to **C**ommand **L**ine
|
34
|
-
**I**nterface (**CLI**) programs:
|
40
|
+
## Components
|
35
41
|
|
36
42
|
### Command-line parsing
|
37
43
|
|
@@ -101,7 +107,7 @@ Specifications = [
|
|
101
107
|
CLASP.Flag('--all', alias: '-a', help: 'processes all item types'),
|
102
108
|
CLASP.Flag('-c', help: 'count the processed items'),
|
103
109
|
CLASP.Option('--opt1', alias: '-o', help: 'an option of some kind', values_range: %w{ val1, val2 }),
|
104
|
-
CLASP.
|
110
|
+
CLASP.Flag('--opt1=val1', alias: '-v'),
|
105
111
|
|
106
112
|
# see next section for why these two are here
|
107
113
|
CLASP::Flag.Help,
|
@@ -195,15 +201,21 @@ then the program will output the following
|
|
195
201
|
cr-example.rb 0.1.2
|
196
202
|
```
|
197
203
|
|
198
|
-
##
|
204
|
+
## Examples
|
205
|
+
|
206
|
+
Examples are provided in the ```examples``` directory, along with a markdown description for each. A detailed list TOC of them is provided in [EXAMPLES.md](./EXAMPLES.md).
|
207
|
+
|
208
|
+
## Project Information
|
209
|
+
|
210
|
+
### Where to get help
|
199
211
|
|
200
212
|
[GitHub Page](https://github.com/synesissoftware/CLASP.Ruby "GitHub Page")
|
201
213
|
|
202
|
-
|
214
|
+
### Contribution guidelines
|
203
215
|
|
204
216
|
Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/CLASP.Ruby.
|
205
217
|
|
206
|
-
|
218
|
+
### Related projects
|
207
219
|
|
208
220
|
**CLASP.Ruby** is inspired by the [C/C++ CLASP library](https://github.com/synesissoftware/CLASP), which is documented in the articles:
|
209
221
|
|
@@ -211,9 +223,19 @@ Defect reports, feature requests, and pull requests are welcome on https://githu
|
|
211
223
|
* _[Anatomy of a CLI Program written in C](http://synesis.com.au/publishing/software-anatomies/anatomy-of-a-cli-program-written-in-c.html)_, Matthew Wilson, [CVu](http://accu.org/index.php/journals/c77/), September 2012; and
|
212
224
|
* _[Anatomy of a CLI Program written in C++](http://synesis.com.au/publishing/software-anatomies/anatomy-of-a-cli-program-written-in-c++.html)_, Matthew Wilson, [CVu](http://accu.org/index.php/journals/c77/), September 2015.
|
213
225
|
|
214
|
-
|
226
|
+
Other CLASP libraries include:
|
227
|
+
|
228
|
+
* [**CLASP**](https://github.com/synesissoftware/CLASP/)
|
229
|
+
* [**CLASP.Go**](https://github.com/synesissoftware/CLASP.Go/)
|
230
|
+
* [**CLASP.js**](https://github.com/synesissoftware/CLASP.js/)
|
231
|
+
* [**CLASP.NET**](https://github.com/synesissoftware/CLASP.NET/)
|
232
|
+
* [**CLASP.Python**](https://github.com/synesissoftware/CLASP.Python/)
|
233
|
+
|
234
|
+
Projects in which **CLASP.Ruby** is used include:
|
235
|
+
|
236
|
+
* [**libCLImate.Ruby**](https://github.com/synesissoftware/libCLImate.Ruby)
|
215
237
|
|
216
|
-
|
238
|
+
### License
|
217
239
|
|
218
240
|
**CLASP.Ruby** is released under the 3-clause BSD license. See LICENSE for details.
|
219
241
|
|
data/examples/cr-example.rb
CHANGED
@@ -1,16 +1,7 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
|
-
|
4
|
-
# File: examples/cr-example.rb
|
3
|
+
# examples/cr-example.rb
|
5
4
|
#
|
6
|
-
# Purpose: COMPLETE_ME
|
7
|
-
#
|
8
|
-
# Created: 11 06 2016
|
9
|
-
# Updated: 11 06 2016
|
10
|
-
#
|
11
|
-
# Author: Matthew Wilson
|
12
|
-
#
|
13
|
-
#############################################################################
|
14
5
|
|
15
6
|
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
16
7
|
|
@@ -23,7 +14,7 @@ Specifications = [
|
|
23
14
|
CLASP.Flag('--all', alias: '-a', help: 'processes all item types'),
|
24
15
|
CLASP.Flag('-c', help: 'count the processed items'),
|
25
16
|
CLASP.Option('--opt1', alias: '-o', help: 'an option of some kind', values_range: %w{ val1, val2 }),
|
26
|
-
CLASP.
|
17
|
+
CLASP.Flag('--opt1=val1', alias: '-v'),
|
27
18
|
|
28
19
|
# see next section for why these two are here
|
29
20
|
CLASP::Flag.Help,
|
@@ -201,4 +201,19 @@ verbosity is specified as: chatty
|
|
201
201
|
Debug mode is specified
|
202
202
|
```
|
203
203
|
|
204
|
+
### Utilise the default value for verbosity
|
205
|
+
|
206
|
+
If executed with the arguments
|
207
|
+
|
208
|
+
```
|
209
|
+
ruby examples/flag_and_option_specifications.rb -d --verbosity=
|
210
|
+
```
|
211
|
+
|
212
|
+
it gives the output:
|
213
|
+
|
214
|
+
```
|
215
|
+
verbosity is specified as: terse
|
216
|
+
Debug mode is specified
|
217
|
+
```
|
218
|
+
|
204
219
|
|
data/lib/clasp/arguments.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# CLASP.Ruby
|
7
7
|
#
|
8
8
|
# Created: 14th February 2014
|
9
|
-
# Updated:
|
9
|
+
# Updated: 20th April 2019
|
10
10
|
#
|
11
11
|
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
12
12
|
#
|
@@ -46,7 +46,8 @@
|
|
46
46
|
|
47
47
|
|
48
48
|
|
49
|
-
require File.join(File.dirname(__FILE__), 'specifications
|
49
|
+
require File.join(File.dirname(__FILE__), 'specifications')
|
50
|
+
require File.join(File.dirname(__FILE__), 'util', 'value_parser')
|
50
51
|
|
51
52
|
require 'yaml'
|
52
53
|
|
@@ -104,6 +105,7 @@ class Arguments
|
|
104
105
|
@name
|
105
106
|
end
|
106
107
|
|
108
|
+
# @!visibility private
|
107
109
|
def eql?(rhs) # :nodoc:
|
108
110
|
|
109
111
|
return false if rhs.nil?
|
@@ -114,6 +116,7 @@ class Arguments
|
|
114
116
|
false
|
115
117
|
end
|
116
118
|
|
119
|
+
# @!visibility private
|
117
120
|
def ==(rhs) # :nodoc:
|
118
121
|
|
119
122
|
return false if rhs.nil?
|
@@ -134,17 +137,40 @@ class Arguments
|
|
134
137
|
# Class that represents a parsed option
|
135
138
|
class OptionArgument
|
136
139
|
|
140
|
+
include ::CLASP::Util::ValueParser
|
141
|
+
|
137
142
|
# @!visibility private
|
138
143
|
#
|
139
144
|
# [PRIVATE] This method is subject to changed between versions and
|
140
145
|
# should not be called directly from application code
|
141
146
|
def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, value, extras) # :nodoc:
|
142
147
|
|
143
|
-
|
148
|
+
resolved_value = nil
|
149
|
+
|
150
|
+
if argument_spec
|
151
|
+
|
152
|
+
case constraint = (argument_spec.constraint || {})
|
153
|
+
=begin
|
154
|
+
when Proc
|
155
|
+
|
156
|
+
resolved_value = value_from_Proc(constraint, value, arg, given_index, given_name, argument_spec, extras)
|
157
|
+
=end
|
158
|
+
when Hash
|
159
|
+
|
160
|
+
if constraint.empty?
|
161
|
+
|
162
|
+
resolved_value = (value || '').empty? ? argument_spec.default_value : value
|
163
|
+
else
|
164
|
+
|
165
|
+
resolved_value = value_from_Hash(constraint, value, arg, given_index, given_name, argument_spec, extras)
|
166
|
+
end
|
167
|
+
else
|
144
168
|
|
145
|
-
|
169
|
+
warn "unexpected constraint on argument specification #{argument_spec} when parsing argument '#{arg}'"
|
170
|
+
end
|
171
|
+
else
|
146
172
|
|
147
|
-
|
173
|
+
resolved_value = value
|
148
174
|
end
|
149
175
|
|
150
176
|
@arg = arg
|
@@ -153,7 +179,8 @@ class Arguments
|
|
153
179
|
@argument_specification = argument_spec
|
154
180
|
@given_hyphens = given_hyphens
|
155
181
|
@given_label = given_label
|
156
|
-
@
|
182
|
+
@given_value = value
|
183
|
+
@value = resolved_value
|
157
184
|
@name = resolved_name || given_name
|
158
185
|
@extras = extras.nil? ? {} : extras
|
159
186
|
end
|
@@ -170,7 +197,9 @@ class Arguments
|
|
170
197
|
attr_reader :given_label
|
171
198
|
# (String) The resolved name of the argument
|
172
199
|
attr_reader :name
|
173
|
-
# (String) The value of the option
|
200
|
+
# (String) The given value of the option
|
201
|
+
attr_reader :given_value
|
202
|
+
# (????) The value of the option, which may be of a type other than string subject to the option specification's constraint
|
174
203
|
attr_reader :value
|
175
204
|
# (Object, Hash) The extras associated with the argument
|
176
205
|
attr_reader :extras
|
@@ -178,6 +207,7 @@ class Arguments
|
|
178
207
|
# [DEPRECATED] Use +argument_specification+
|
179
208
|
def argument_alias; @argument_specification; end
|
180
209
|
|
210
|
+
# @!visibility private
|
181
211
|
def eql?(rhs) # :nodoc:
|
182
212
|
|
183
213
|
return false if rhs.nil?
|
@@ -188,6 +218,7 @@ class Arguments
|
|
188
218
|
false
|
189
219
|
end
|
190
220
|
|
221
|
+
# @!visibility private
|
191
222
|
def ==(rhs) # :nodoc:
|
192
223
|
|
193
224
|
return false if rhs.nil?
|
@@ -454,7 +485,7 @@ class Arguments
|
|
454
485
|
values = []
|
455
486
|
|
456
487
|
forced_value = false
|
457
|
-
|
488
|
+
pending_option = nil
|
458
489
|
|
459
490
|
argv.each_with_index do |arg, index|
|
460
491
|
|
@@ -559,15 +590,22 @@ class Arguments
|
|
559
590
|
|
560
591
|
if argument_spec and argument_spec.is_a? CLASP::OptionSpecification and not value
|
561
592
|
|
562
|
-
|
563
|
-
|
593
|
+
pending_option = {
|
594
|
+
|
595
|
+
arg: arg,
|
596
|
+
index: index,
|
597
|
+
given_name: given_name,
|
598
|
+
resolved_name: resolved_name,
|
599
|
+
argument_spec: argument_spec,
|
600
|
+
hyphens_size: hyphens.size,
|
601
|
+
given_label: given_label,
|
602
|
+
extras: argument_spec ? argument_spec.extras : nil,
|
603
|
+
}
|
564
604
|
elsif value
|
565
605
|
|
566
|
-
want_option_value = false
|
567
606
|
options << OptionArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, value, argument_spec ? argument_spec.extras : nil)
|
568
607
|
else
|
569
608
|
|
570
|
-
want_option_value = false
|
571
609
|
flags << FlagArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil)
|
572
610
|
end
|
573
611
|
|
@@ -575,20 +613,31 @@ class Arguments
|
|
575
613
|
end
|
576
614
|
end
|
577
615
|
|
578
|
-
if
|
616
|
+
if pending_option
|
579
617
|
|
580
|
-
|
581
|
-
option.instance_eval("@value='#{arg}'")
|
582
|
-
want_option_value = false
|
583
|
-
else
|
618
|
+
value = forced_value ? nil : arg
|
584
619
|
|
585
|
-
arg
|
586
|
-
arg_ix = ::Integer === index ? index : index.dup
|
620
|
+
options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
|
587
621
|
|
588
|
-
|
622
|
+
pending_option = nil
|
589
623
|
|
590
|
-
|
624
|
+
next unless forced_value
|
591
625
|
end
|
626
|
+
|
627
|
+
arg = arg.dup
|
628
|
+
arg_ix = ::Integer === index ? index : index.dup
|
629
|
+
|
630
|
+
arg.define_singleton_method(:given_index) { arg_ix }
|
631
|
+
|
632
|
+
values << arg
|
633
|
+
end
|
634
|
+
|
635
|
+
if pending_option
|
636
|
+
|
637
|
+
value = nil
|
638
|
+
|
639
|
+
options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
|
640
|
+
|
592
641
|
end
|
593
642
|
|
594
643
|
return flags, options, values
|
data/lib/clasp/clasp.rb
CHANGED
@@ -50,6 +50,15 @@ require 'clasp/specifications'
|
|
50
50
|
require 'clasp/cli'
|
51
51
|
require 'clasp/version'
|
52
52
|
|
53
|
+
module CLASP
|
54
|
+
|
55
|
+
# TBC (but is a shorthand for calling +Arguments.new()+
|
56
|
+
def self.parse(argv = ARGV, specifications = nil, options = {})
|
57
|
+
|
58
|
+
return Arguments.new(argv, specifications, options)
|
59
|
+
end
|
60
|
+
end # module CLASP
|
61
|
+
|
53
62
|
# ############################## end of file ############################# #
|
54
63
|
|
55
64
|
|
data/lib/clasp/cli.rb
CHANGED
@@ -60,45 +60,49 @@ module CLASP
|
|
60
60
|
=end
|
61
61
|
|
62
62
|
# :stopdoc:
|
63
|
-
module CLI_helpers_
|
64
63
|
|
65
|
-
|
64
|
+
# @!visibility private
|
65
|
+
module CLI_helpers_ # :nodoc: all
|
66
66
|
|
67
|
+
# @!visibility private
|
68
|
+
module Constants # :nodoc: all
|
69
|
+
|
70
|
+
# @!visibility private
|
67
71
|
VALID_ALIAS_TYPES = [ FlagSpecification, OptionSpecification, AliasSpecification ]
|
72
|
+
# @!visibility private
|
68
73
|
VALID_ALIAS_TYPES_STRING = VALID_ALIAS_TYPES[0...-1].join(', ') + ', or ' + VALID_ALIAS_TYPES[-1].to_s
|
69
74
|
end # module Constants
|
70
75
|
|
71
|
-
#
|
72
|
-
def self.generate_version_string_ options
|
76
|
+
# @!visibility private
|
77
|
+
def self.generate_version_string_ options # :nodoc:
|
73
78
|
|
74
|
-
|
79
|
+
program_name = options[:program_name] || File.basename($0)
|
75
80
|
|
76
|
-
|
81
|
+
version_prefix = options[:version_prefix]
|
77
82
|
|
78
|
-
|
83
|
+
if options[:version]
|
79
84
|
|
80
|
-
|
81
|
-
|
82
|
-
|
85
|
+
case options[:version]
|
86
|
+
when ::Array
|
87
|
+
version = options[:version].join('.')
|
88
|
+
else
|
89
|
+
version = options[:version]
|
90
|
+
end
|
83
91
|
else
|
84
|
-
version = options[:version]
|
85
|
-
end
|
86
|
-
else
|
87
92
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
version_major = options[:version_major] or raise ArgumentError, "options must specify :version or :version_major [ + :version_minor [ + :version_revision [ + :version_build ]]]"
|
94
|
+
version_minor = options[:version_minor]
|
95
|
+
version_rev = options[:version_revision]
|
96
|
+
version_build = options[:version_build]
|
92
97
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
"#{program_name} #{version_prefix}#{version}"
|
100
|
-
end
|
98
|
+
version = version_major.to_s
|
99
|
+
version += ".#{version_minor}" if version_minor
|
100
|
+
version += ".#{version_rev}" if version_rev
|
101
|
+
version += ".#{version_build}" if version_build
|
102
|
+
end
|
101
103
|
|
104
|
+
"#{program_name} #{version_prefix}#{version}"
|
105
|
+
end
|
102
106
|
end # module CLI_helpers_
|
103
107
|
|
104
108
|
# ######################################################################## #
|
data/lib/clasp/specifications.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: Argument specification classes
|
6
6
|
#
|
7
7
|
# Created: 25th October 2014
|
8
|
-
# Updated:
|
8
|
+
# Updated: 29th April 2019
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
11
11
|
#
|
@@ -57,8 +57,40 @@ module CLASP
|
|
57
57
|
# ######################################################################## #
|
58
58
|
# classes
|
59
59
|
|
60
|
+
# @!visibility private
|
61
|
+
class SpecificationBase # :nodoc: all
|
62
|
+
|
63
|
+
private
|
64
|
+
# @!visibility private
|
65
|
+
def check_arity_(blk, range, label) # :nodoc:
|
66
|
+
|
67
|
+
raise ArgumentError, "block must be a #{Proc}; #{blk.class} given" unless blk.nil? || Proc === blk
|
68
|
+
|
69
|
+
if blk
|
70
|
+
|
71
|
+
case blk.arity
|
72
|
+
when range
|
73
|
+
|
74
|
+
;
|
75
|
+
else
|
76
|
+
|
77
|
+
msg = "wrong arity for #{label}"
|
78
|
+
|
79
|
+
if $DEBUG
|
80
|
+
|
81
|
+
raise ArgumentError, msg
|
82
|
+
else
|
83
|
+
|
84
|
+
warn msg
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
public
|
90
|
+
end
|
91
|
+
|
60
92
|
# A class that represents the specification for a command-line flag
|
61
|
-
class FlagSpecification
|
93
|
+
class FlagSpecification < SpecificationBase
|
62
94
|
|
63
95
|
# Creates a FlagSpecification instance from the given name, aliases, and help
|
64
96
|
#
|
@@ -69,12 +101,19 @@ class FlagSpecification
|
|
69
101
|
# - +aliases+ (+Array+) 0 or more strings specifying short-form or option-value aliases
|
70
102
|
# - +help+ (+String+) The help string, which may be +nil+
|
71
103
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+
|
72
|
-
|
104
|
+
#
|
105
|
+
# * *Block* An optional block that is called when a matching flag argument is found
|
106
|
+
#
|
107
|
+
# *NOTE:* Users should prefer the +CLASP::Flag()+ method
|
108
|
+
def initialize(name, aliases, help, extras = nil, &blk)
|
109
|
+
|
110
|
+
check_arity_(blk, 0..3, "flag")
|
73
111
|
|
74
112
|
@name = name
|
75
113
|
@aliases = (aliases || []).select { |a| a and not a.empty? }
|
76
114
|
@help = help
|
77
115
|
@extras = extras || {}
|
116
|
+
@action = blk
|
78
117
|
end
|
79
118
|
|
80
119
|
# The flag's name string
|
@@ -86,12 +125,24 @@ class FlagSpecification
|
|
86
125
|
# The flag's extras
|
87
126
|
attr_reader :extras
|
88
127
|
|
128
|
+
# (Proc) The procedure
|
129
|
+
attr_reader :action
|
130
|
+
|
131
|
+
# @!visibility private
|
132
|
+
def action=(blk) # :nodoc: all
|
133
|
+
|
134
|
+
check_arity_(blk, 0..3, "flag")
|
135
|
+
|
136
|
+
@action = blk
|
137
|
+
end
|
138
|
+
|
89
139
|
# String form of the flag
|
90
140
|
def to_s
|
91
141
|
|
92
142
|
"{#{name}; aliases=#{aliases.join(', ')}; help='#{help}'; extras=#{extras}}"
|
93
143
|
end
|
94
144
|
|
145
|
+
# @!visibility private
|
95
146
|
def eql? rhs # :nodoc:
|
96
147
|
|
97
148
|
case rhs
|
@@ -132,28 +183,38 @@ class FlagSpecification
|
|
132
183
|
@@Version_ = self.new('--version', [], 'shows version and terminates')
|
133
184
|
public
|
134
185
|
# An instance of FlagSpecification that provides default '--help' information
|
135
|
-
|
186
|
+
#
|
187
|
+
# If you wish to specify +extras+ or attach a block, you may do so
|
188
|
+
def self.Help(extras = nil, &blk)
|
136
189
|
|
137
190
|
h = @@Help_
|
138
191
|
|
139
|
-
|
192
|
+
if extras || blk
|
193
|
+
|
194
|
+
return self.new(h.name, h.aliases, h.help, extras, &blk)
|
195
|
+
end
|
140
196
|
|
141
197
|
h
|
142
198
|
end
|
143
199
|
|
144
200
|
# An instance of FlagSpecification that provides default '--version' information
|
145
|
-
|
201
|
+
#
|
202
|
+
# If you wish to specify +extras+ or attach a block, you may do so
|
203
|
+
def self.Version(extras = nil, &blk)
|
146
204
|
|
147
205
|
h = @@Version_
|
148
206
|
|
149
|
-
|
207
|
+
if extras || blk
|
208
|
+
|
209
|
+
return self.new(h.name, h.aliases, h.help, extras, &blk)
|
210
|
+
end
|
150
211
|
|
151
212
|
h
|
152
213
|
end
|
153
214
|
end
|
154
215
|
|
155
216
|
# A class that represents the specification for a command-line option
|
156
|
-
class OptionSpecification
|
217
|
+
class OptionSpecification < SpecificationBase
|
157
218
|
|
158
219
|
# Creates an OptionSpecification instance from the given name, aliases, help,
|
159
220
|
# values_range, and default_value
|
@@ -168,8 +229,15 @@ class OptionSpecification
|
|
168
229
|
# - +default_value+ (+String+) The default value of the option, which will be used in the case where an option is specified without a value. May be +nil+
|
169
230
|
# - +required+ (boolean) Whether the option is required. May be +nil+
|
170
231
|
# - +required_message+ (::String) Message to be used when reporting that a required option is missing. May be +nil+ in which case a message of the form "<option-name> not specified; use --help for usage". If begins with the nul character ("\0"), then is used in the place of the <option-name> and placed into the rest of the standard form message
|
232
|
+
# - +constraint+ (Hash) Constraint to be applied to the parsed values of options matching this specification. NOTE: only integer constraints are supported in the current version
|
171
233
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+
|
172
|
-
|
234
|
+
#
|
235
|
+
# * *Block* An optional block that is called when a matching option argument is found
|
236
|
+
#
|
237
|
+
# *NOTE:* Users should prefer the +CLASP::Option()+ method
|
238
|
+
def initialize(name, aliases, help, values_range, default_value, required, required_message, constraint, extras = nil, &blk)
|
239
|
+
|
240
|
+
check_arity_(blk, 0..3, "option")
|
173
241
|
|
174
242
|
@name = name
|
175
243
|
@aliases = (aliases || []).select { |a| a and not a.empty? }
|
@@ -178,7 +246,9 @@ class OptionSpecification
|
|
178
246
|
@default_value = default_value
|
179
247
|
@required = required
|
180
248
|
@required_message = nil
|
249
|
+
@constraint = constraint || {}
|
181
250
|
@extras = extras || {}
|
251
|
+
@action = blk
|
182
252
|
|
183
253
|
rm_name = nil
|
184
254
|
|
@@ -213,18 +283,31 @@ class OptionSpecification
|
|
213
283
|
attr_reader :default_value
|
214
284
|
# Indicates whether the option is required
|
215
285
|
def required?; @required; end
|
216
|
-
# The message to be used when reporting that a required option is
|
217
|
-
# missing
|
286
|
+
# The message to be used when reporting that a required option is missing
|
218
287
|
attr_reader :required_message
|
288
|
+
# The value constraint
|
289
|
+
attr_reader :constraint
|
219
290
|
# The option's extras
|
220
291
|
attr_reader :extras
|
221
292
|
|
293
|
+
# (Proc) The procedure
|
294
|
+
attr_reader :action
|
295
|
+
|
296
|
+
# @!visibility private
|
297
|
+
def action=(blk) # :nodoc: all
|
298
|
+
|
299
|
+
check_arity_(blk, 0..3, "flag")
|
300
|
+
|
301
|
+
@action = blk
|
302
|
+
end
|
303
|
+
|
222
304
|
# String form of the option
|
223
305
|
def to_s
|
224
306
|
|
225
|
-
"{#{name}; aliases=#{aliases.join(', ')}; values_range=[ #{values_range.join(', ')} ]; default_value='#{default_value}'; help='#{help}'; required?=#{required?}; extras=#{extras}}"
|
307
|
+
"{#{name}; aliases=#{aliases.join(', ')}; values_range=[ #{values_range.join(', ')} ]; default_value='#{default_value}'; help='#{help}'; required?=#{required?}; required_message=#{required_message}; constraint=#{constraint}; extras=#{extras}}"
|
226
308
|
end
|
227
309
|
|
310
|
+
# @!visibility private
|
228
311
|
def eql? rhs # :nodoc:
|
229
312
|
|
230
313
|
case rhs
|
@@ -309,7 +392,9 @@ end
|
|
309
392
|
# - +:aliases+ (::Array) An array of aliases, e.g. [ '-v', '-verb' ]. Ignored if +:alias+ is specified
|
310
393
|
# - +:extras+ An application-defined object, usually a hash of custom attributes
|
311
394
|
# - +:help+ (::String) A help string
|
312
|
-
|
395
|
+
#
|
396
|
+
# * *Block* An optional block that is called when a matching flag argument is found
|
397
|
+
def CLASP.Flag(name, options = {}, &blk)
|
313
398
|
|
314
399
|
aliases = nil
|
315
400
|
help = nil
|
@@ -342,7 +427,7 @@ def CLASP.Flag(name, options = {})
|
|
342
427
|
end
|
343
428
|
end
|
344
429
|
|
345
|
-
CLASP::FlagSpecification.new(name, aliases, help, extras)
|
430
|
+
CLASP::FlagSpecification.new(name, aliases, help, extras, &blk)
|
346
431
|
end
|
347
432
|
|
348
433
|
# Generator method that obtains a CLASP::OptionSpecification according to the given
|
@@ -364,9 +449,12 @@ end
|
|
364
449
|
# - +required+ (boolean) Whether the option is required. May be +nil+
|
365
450
|
# - +required_message+ (::String) Message to be used when reporting that a required option is missing. May be +nil+ in which case a message of the form "<option-name> not specified; use --help for usage". If begins with the nul character ("\0"), then is used in the place of the <option-name> and placed into the rest of the standard form message
|
366
451
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+.
|
452
|
+
# - +constraint+ (Hash) Constraint to be applied to the parsed values of options matching this specification. NOTE: only integer constraints are supported in the current version
|
367
453
|
# - +:values_range+ (::Array) An array defining the accepted values for the option
|
368
454
|
# - +:values+ [DEPRECATED] Alternative to +:values_range+
|
369
|
-
|
455
|
+
#
|
456
|
+
# * *Block* An optional block that is called when a matching option argument is found
|
457
|
+
def CLASP.Option(name, options = {}, &blk)
|
370
458
|
|
371
459
|
aliases = nil
|
372
460
|
help = nil
|
@@ -374,6 +462,7 @@ def CLASP.Option(name, options = {})
|
|
374
462
|
default_value = nil
|
375
463
|
required = false
|
376
464
|
require_message = nil
|
465
|
+
constraint = nil
|
377
466
|
extras = nil
|
378
467
|
|
379
468
|
options.each do |k, v|
|
@@ -405,6 +494,9 @@ def CLASP.Option(name, options = {})
|
|
405
494
|
when :extras
|
406
495
|
|
407
496
|
extras = v
|
497
|
+
when :constraint
|
498
|
+
|
499
|
+
constraint = v
|
408
500
|
else
|
409
501
|
|
410
502
|
raise ArgumentError, "invalid option for option: '#{k}' => '#{v}'"
|
@@ -415,7 +507,7 @@ def CLASP.Option(name, options = {})
|
|
415
507
|
end
|
416
508
|
end
|
417
509
|
|
418
|
-
CLASP::OptionSpecification.new(name, aliases, help, values_range, default_value, required, require_message, extras)
|
510
|
+
CLASP::OptionSpecification.new(name, aliases, help, values_range, default_value, required, require_message, constraint, extras, &blk)
|
419
511
|
end
|
420
512
|
|
421
513
|
def CLASP.Alias(name, *args)
|