clasp-ruby 0.23.0.1 → 0.23.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 +4 -4
- data/README.md +63 -52
- data/examples/cr-example.rb +16 -16
- data/examples/flag_and_option_specifications.md +25 -25
- data/examples/flag_and_option_specifications.rb +15 -15
- data/examples/show_usage_and_version.md +5 -5
- data/examples/show_usage_and_version.rb +10 -11
- data/examples/simple_command_line_no_specifications.rb +1 -1
- data/lib/clasp/arguments.rb +543 -543
- data/lib/clasp/clasp.rb +15 -11
- data/lib/clasp/cli.rb +145 -139
- data/lib/clasp/doc_.rb +3 -3
- data/lib/clasp/old_module.rb +9 -9
- data/lib/clasp/specifications.rb +346 -339
- data/lib/clasp/util/exceptions.rb +22 -23
- data/lib/clasp/util/value_parser.rb +101 -103
- data/lib/clasp/version.rb +20 -20
- data/lib/clasp-ruby.rb +9 -7
- data/lib/clasp.rb +9 -7
- data/test/scratch/test_list_command_line.rb +6 -6
- data/test/scratch/test_specifications.rb +14 -14
- data/test/scratch/test_usage.rb +6 -6
- data/test/scratch/test_usage_from_DATA.rb +1 -1
- data/test/scratch/test_usage_with_duplicate_specifications.rb +6 -6
- data/test/unit/tc_ARGV_rewrite.rb +36 -38
- data/test/unit/tc_arguments_1.rb +694 -694
- data/test/unit/tc_arguments_2.rb +52 -53
- data/test/unit/tc_arguments_3.rb +77 -77
- data/test/unit/tc_arguments_inspect.rb +55 -56
- data/test/unit/tc_cli.rb +4 -4
- data/test/unit/tc_default_value.rb +91 -91
- data/test/unit/tc_defaults_1.rb +38 -38
- data/test/unit/tc_examples_Arguments.rb +130 -132
- data/test/unit/tc_extras.rb +24 -26
- data/test/unit/tc_option_required.rb +38 -39
- data/test/unit/tc_option_value_aliases.rb +45 -45
- data/test/unit/tc_specifications.rb +7 -8
- data/test/unit/tc_typed_options.rb +204 -204
- data/test/unit/tc_usage.rb +112 -55
- data/test/unit/tc_with_action.rb +23 -24
- data/test/unit/ts_all.rb +1 -1
- metadata +12 -10
data/lib/clasp/clasp.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
|
2
2
|
# ######################################################################## #
|
3
|
-
# File:
|
3
|
+
# File: clasp/clasp.rb
|
4
4
|
#
|
5
|
-
# Purpose:
|
5
|
+
# Purpose: Common 'require file' for CLASP.Ruby library
|
6
6
|
#
|
7
|
-
# Created:
|
8
|
-
# Updated:
|
7
|
+
# Created: 14th February 2014
|
8
|
+
# Updated: 6th March 2025
|
9
9
|
#
|
10
|
-
# Home:
|
10
|
+
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
11
11
|
#
|
12
|
-
# Author:
|
12
|
+
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
+
# Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems
|
14
15
|
# Copyright (c) 2014-2019, Matthew Wilson and Synesis Software
|
15
16
|
# All rights reserved.
|
16
17
|
#
|
@@ -50,15 +51,18 @@ require 'clasp/specifications'
|
|
50
51
|
require 'clasp/cli'
|
51
52
|
require 'clasp/version'
|
52
53
|
|
54
|
+
=begin
|
55
|
+
=end
|
56
|
+
|
53
57
|
module CLASP
|
54
58
|
|
55
|
-
|
56
|
-
|
59
|
+
# TBC (but is a shorthand for calling +Arguments.new()+
|
60
|
+
def self.parse(argv = ARGV, specifications = nil, options = {})
|
57
61
|
|
58
|
-
|
59
|
-
|
62
|
+
return Arguments.new(argv, specifications, options)
|
63
|
+
end
|
60
64
|
end # module CLASP
|
61
65
|
|
62
|
-
# ############################## end of file ############################# #
|
63
66
|
|
67
|
+
# ############################## end of file ############################# #
|
64
68
|
|
data/lib/clasp/cli.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
|
2
2
|
# ######################################################################## #
|
3
|
-
# File:
|
3
|
+
# File: clasp/cli.rb
|
4
4
|
#
|
5
|
-
# Purpose:
|
5
|
+
# Purpose: Command-line interface
|
6
6
|
#
|
7
|
-
# Created:
|
8
|
-
# Updated:
|
7
|
+
# Created: 27th July 2015
|
8
|
+
# Updated: 6th March 2025
|
9
9
|
#
|
10
|
-
# Home:
|
10
|
+
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
11
11
|
#
|
12
|
-
# Author:
|
12
|
+
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
+
# Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems
|
14
15
|
# Copyright (c) 2015-2019, Matthew Wilson and Synesis Software
|
15
16
|
# All rights reserved.
|
16
17
|
#
|
@@ -53,6 +54,7 @@
|
|
53
54
|
|
54
55
|
module CLASP
|
55
56
|
|
57
|
+
|
56
58
|
# ######################################################################## #
|
57
59
|
# helpers
|
58
60
|
|
@@ -64,47 +66,48 @@ module CLASP
|
|
64
66
|
# @!visibility private
|
65
67
|
module CLI_helpers_ # :nodoc: all
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
+
# @!visibility private
|
70
|
+
module Constants # :nodoc: all
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
# @!visibility private
|
73
|
+
VALID_ALIAS_TYPES = [ FlagSpecification, OptionSpecification, AliasSpecification ]
|
74
|
+
# @!visibility private
|
75
|
+
VALID_ALIAS_TYPES_STRING = VALID_ALIAS_TYPES[0...-1].join(', ') + ', or ' + VALID_ALIAS_TYPES[-1].to_s
|
76
|
+
end # module Constants
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
+
# @!visibility private
|
79
|
+
def self.generate_version_string_ options # :nodoc:
|
78
80
|
|
79
|
-
|
81
|
+
program_name = options[:program_name] || File.basename($0)
|
80
82
|
|
81
|
-
|
83
|
+
version_prefix = options[:version_prefix]
|
82
84
|
|
83
|
-
|
85
|
+
if options[:version]
|
84
86
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
case options[:version]
|
88
|
+
when ::Array
|
89
|
+
version = options[:version].join('.')
|
90
|
+
else
|
91
|
+
version = options[:version]
|
92
|
+
end
|
93
|
+
else
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
version_major = options[:version_major] or raise ArgumentError, "options must specify :version or :version_major [ + :version_minor [ + :version_revision [ + :version_build ]]]"
|
96
|
+
version_minor = options[:version_minor]
|
97
|
+
version_rev = options[:version_revision]
|
98
|
+
version_build = options[:version_build]
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
version = version_major.to_s
|
101
|
+
version += ".#{version_minor}" if version_minor
|
102
|
+
version += ".#{version_rev}" if version_rev
|
103
|
+
version += ".#{version_build}" if version_build
|
104
|
+
end
|
103
105
|
|
104
|
-
|
105
|
-
|
106
|
+
"#{program_name} #{version_prefix}#{version}"
|
107
|
+
end
|
106
108
|
end # module CLI_helpers_
|
107
109
|
|
110
|
+
|
108
111
|
# ######################################################################## #
|
109
112
|
# methods
|
110
113
|
|
@@ -132,141 +135,142 @@ end # module CLI_helpers_
|
|
132
135
|
# - +:default_indicator+ (String) a string placed after the matching value in the listing of an option's range of values. Defaults to "(default)". If +nil+ default is used. If empty string no indication given
|
133
136
|
def self.show_usage specifications, options={}
|
134
137
|
|
135
|
-
|
138
|
+
options ||= {}
|
136
139
|
|
137
|
-
|
138
|
-
|
140
|
+
raise ArgumentError, "specifications may not be nil" if specifications.nil?
|
141
|
+
raise TypeError, "specifications must be an array or must respond to each, reject and select" unless ::Array === specifications || (specifications.respond_to?(:each) && specifications.respond_to?(:reject) && specifications.respond_to?(:select))
|
139
142
|
|
140
|
-
|
141
|
-
specifications.each { |s| raise ::TypeError, "each element in specifications array must be one of the types #{constants::VALID_ALIAS_TYPES_STRING}" unless constants::VALID_ALIAS_TYPES.any? { |c| c === s } }
|
143
|
+
constants = CLI_helpers_::Constants
|
142
144
|
|
143
|
-
|
144
|
-
specifications.each { |s| s.aliases.each { |aa| warn "WARNING: alias '#{aa}' is already used for specification '#{s}'" if alias_dups.has_key? aa; alias_dups[aa] = s; } }
|
145
|
+
specifications.each { |s| raise ::TypeError, "each element in specifications array must be one of the types #{constants::VALID_ALIAS_TYPES_STRING}" unless constants::VALID_ALIAS_TYPES.any? { |c| c === s } }
|
145
146
|
|
146
|
-
|
147
|
+
alias_dups = {}
|
148
|
+
specifications.each { |s| s.aliases.each { |aa| warn "WARNING: alias '#{aa}' is already used for specification '#{s}'" if alias_dups.has_key? aa; alias_dups[aa] = s; } }
|
147
149
|
|
148
|
-
|
149
|
-
program_name = options[:program_name] || File.basename($0)
|
150
|
+
suppress_blanks = options[:suppress_blank_lines_between_options] || ENV['SUPPRESS_BLANK_LINES_BETWEEN_OPTIONS']
|
150
151
|
|
151
|
-
|
152
|
-
|
153
|
-
when ::Array
|
152
|
+
stream = options[:stream] || $stdout
|
153
|
+
program_name = options[:program_name] || File.basename($0)
|
154
154
|
|
155
|
-
|
156
|
-
|
155
|
+
info_lines = options[:info_lines]
|
156
|
+
case info_lines
|
157
|
+
when ::Array
|
157
158
|
|
158
|
-
|
159
|
-
|
159
|
+
;
|
160
|
+
when ::NilClass
|
160
161
|
|
161
|
-
|
162
|
-
|
163
|
-
info_lines = info_lines.map do |line|
|
162
|
+
info_lines = []
|
163
|
+
else
|
164
164
|
|
165
|
-
|
166
|
-
|
165
|
+
info_lines = [ info_lines ] unless [ :each, :empty? ].all? { |m| info_lines.respond_to? m }
|
166
|
+
end
|
167
|
+
info_lines = info_lines.map do |line|
|
167
168
|
|
168
|
-
|
169
|
-
|
169
|
+
case line
|
170
|
+
when :version
|
170
171
|
|
171
|
-
|
172
|
-
|
173
|
-
end
|
172
|
+
CLI_helpers_.generate_version_string_ options
|
173
|
+
else
|
174
174
|
|
175
|
-
|
176
|
-
|
175
|
+
line
|
176
|
+
end
|
177
|
+
end
|
177
178
|
|
178
|
-
|
179
|
-
|
179
|
+
values = options[:values] || ''
|
180
|
+
values = " #{values}" if !values.empty? && ' ' != values[0]
|
180
181
|
|
181
|
-
|
182
|
-
|
182
|
+
flags_and_options = options[:flags_and_options] || ' [ ... flags and options ... ]'
|
183
|
+
flags_and_options = " #{flags_and_options}" if !flags_and_options.empty? && ' ' != flags_and_options[0]
|
183
184
|
|
184
|
-
|
185
|
-
|
185
|
+
default_indicator = options[:default_indicator] || '(default)'
|
186
|
+
default_indicator = nil if default_indicator.empty?
|
186
187
|
|
187
|
-
|
188
|
+
# sift the specifications to sort out which are value-option
|
189
|
+
# specifications (VOAs)
|
188
190
|
|
189
|
-
|
191
|
+
voas = {}
|
190
192
|
|
191
|
-
|
193
|
+
specifications.select { |s| s.name =~ /^-+[a-zA-Z0-3_-]+[=:].+/ }.each do |s|
|
192
194
|
|
193
|
-
|
194
|
-
voas[$1] << [ s, $2 ]
|
195
|
-
end
|
195
|
+
s.name =~ /^(-+[a-zA-Z0-3_-]+)[=:](.+)$/
|
196
196
|
|
197
|
-
|
197
|
+
voas[$1] = [] unless voas.has_key? $1
|
198
|
+
voas[$1] << [ s, $2 ]
|
199
|
+
end
|
198
200
|
|
199
|
-
|
201
|
+
fas = {}
|
200
202
|
|
201
|
-
|
202
|
-
fas[s.name] << s
|
203
|
-
end
|
203
|
+
specifications.select { |s| AliasSpecification === s }.each do |s|
|
204
204
|
|
205
|
-
|
205
|
+
fas[s.name] = [] unless fas.has_key? $1
|
206
|
+
fas[s.name] << s
|
207
|
+
end
|
206
208
|
|
207
|
-
|
209
|
+
specifications = specifications.reject { |s| s.name =~ /^-+[a-zA-Z0-3_-]+[=:].+/ }
|
208
210
|
|
209
|
-
|
210
|
-
stream.puts
|
211
|
+
info_lines.each { |info_line| stream.puts info_line } unless info_lines.empty?
|
211
212
|
|
212
|
-
|
213
|
+
stream.puts "USAGE: #{program_name}#{flags_and_options}#{values}"
|
214
|
+
stream.puts
|
213
215
|
|
214
|
-
|
215
|
-
stream.puts
|
216
|
-
specifications.each do |s|
|
216
|
+
unless specifications.empty?
|
217
217
|
|
218
|
-
|
219
|
-
|
218
|
+
stream.puts "flags/options:"
|
219
|
+
stream.puts
|
220
|
+
specifications.each do |s|
|
220
221
|
|
221
|
-
|
222
|
-
|
222
|
+
case s
|
223
|
+
when AliasSpecification
|
223
224
|
|
224
|
-
|
225
|
+
next
|
226
|
+
when FlagSpecification
|
225
227
|
|
226
|
-
|
228
|
+
if fas.has_key? s.name
|
227
229
|
|
228
|
-
|
229
|
-
end
|
230
|
-
end
|
231
|
-
s.aliases.each { |al| stream.puts "\t#{al}" }
|
232
|
-
stream.puts "\t#{s.name}"
|
233
|
-
stream.puts "\t\t#{s.help}"
|
234
|
-
when OptionSpecification
|
230
|
+
fas[s.name].each do |fa|
|
235
231
|
|
236
|
-
|
232
|
+
fa.aliases.each { |al| stream.puts "\t#{al}" }
|
233
|
+
end
|
234
|
+
end
|
235
|
+
s.aliases.each { |al| stream.puts "\t#{al}" }
|
236
|
+
stream.puts "\t#{s.name}"
|
237
|
+
stream.puts "\t\t#{s.help}"
|
238
|
+
when OptionSpecification
|
237
239
|
|
238
|
-
|
240
|
+
if voas.has_key? s.name
|
239
241
|
|
240
|
-
|
241
|
-
end
|
242
|
-
end
|
243
|
-
s.aliases.each { |al| stream.puts "\t#{al} <value>" }
|
244
|
-
stream.puts "\t#{s.name}=<value>"
|
245
|
-
stream.puts "\t\t#{s.help}"
|
246
|
-
unless s.values_range.empty?
|
242
|
+
voas[s.name].each do |ar|
|
247
243
|
|
248
|
-
|
244
|
+
ar[0].aliases.each { |al| stream.puts "\t#{al} #{ar[0].name}" }
|
245
|
+
end
|
246
|
+
end
|
247
|
+
s.aliases.each { |al| stream.puts "\t#{al} <value>" }
|
248
|
+
stream.puts "\t#{s.name}=<value>"
|
249
|
+
stream.puts "\t\t#{s.help}"
|
250
|
+
unless s.values_range.empty?
|
249
251
|
|
250
|
-
|
251
|
-
s.values_range.each do |v|
|
252
|
+
d = s.default_value
|
252
253
|
|
253
|
-
|
254
|
+
stream.puts "\t\twhere <value> one of:"
|
255
|
+
s.values_range.each do |v|
|
254
256
|
|
255
|
-
|
256
|
-
else
|
257
|
+
if default_indicator && v == d
|
257
258
|
|
258
|
-
|
259
|
-
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
stream.puts unless suppress_blanks
|
264
|
-
end
|
265
|
-
end
|
259
|
+
stream.puts "\t\t\t#{v}\t#{default_indicator}"
|
260
|
+
else
|
266
261
|
|
267
|
-
|
262
|
+
stream.puts "\t\t\t#{v}"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
stream.puts unless suppress_blanks
|
268
|
+
end
|
269
|
+
end
|
268
270
|
|
269
|
-
|
271
|
+
exit_code = options[:exit_code] || options[:exit]
|
272
|
+
|
273
|
+
exit exit_code if exit_code
|
270
274
|
end
|
271
275
|
|
272
276
|
# Displays version for the program according to the given specifications and options
|
@@ -289,30 +293,32 @@ end
|
|
289
293
|
# - +:version_prefix+ optional string to prefix the version number(s).
|
290
294
|
def self.show_version specifications, options = {}
|
291
295
|
|
292
|
-
|
296
|
+
options ||= {}
|
297
|
+
|
298
|
+
raise ArgumentError, "specifications may not be nil" if specifications.nil?
|
299
|
+
raise TypeError, "specifications must be an array or must respond to each, reject and select" unless ::Array === specifications || (specifications.respond_to?(:each) && specifications.respond_to?(:reject) && specifications.respond_to?(:select))
|
293
300
|
|
294
|
-
|
295
|
-
raise TypeError, "specifications must be an array or must respond to each, reject and select" unless ::Array === specifications || (specifications.respond_to?(:each) && specifications.respond_to?(:reject) && specifications.respond_to?(:select))
|
301
|
+
constants = CLI_helpers_::Constants
|
296
302
|
|
297
|
-
|
298
|
-
specifications.each { |s| raise ::TypeError, "each element in specifications array must be one of the types #{constants::VALID_ALIAS_TYPES_STRING}" unless constants::VALID_ALIAS_TYPES.any? { |c| c === s } }
|
303
|
+
specifications.each { |s| raise ::TypeError, "each element in specifications array must be one of the types #{constants::VALID_ALIAS_TYPES_STRING}" unless constants::VALID_ALIAS_TYPES.any? { |c| c === s } }
|
299
304
|
|
300
|
-
|
305
|
+
stream = options[:stream] || $stdout
|
301
306
|
|
302
|
-
|
307
|
+
version_string = CLI_helpers_.generate_version_string_ options
|
303
308
|
|
304
|
-
|
309
|
+
stream.puts version_string
|
305
310
|
|
306
|
-
|
311
|
+
exit_code = options[:exit_code] || options[:exit]
|
307
312
|
|
308
|
-
|
313
|
+
exit exit_code if exit_code
|
309
314
|
end
|
310
315
|
|
316
|
+
|
311
317
|
# ######################################################################## #
|
312
318
|
# module
|
313
319
|
|
314
320
|
end # module CLASP
|
315
321
|
|
316
|
-
# ############################## end of file ############################# #
|
317
322
|
|
323
|
+
# ############################## end of file ############################# #
|
318
324
|
|
data/lib/clasp/doc_.rb
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
# Purpose: Documentation of the CLASP.Ruby modules
|
6
6
|
#
|
7
7
|
# Created: 11th June 2016
|
8
|
-
# Updated:
|
8
|
+
# Updated: 20th January 2024
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
12
12
|
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
-
# Copyright (c) 2016-
|
14
|
+
# Copyright (c) 2016-2024, Matthew Wilson and Synesis Software
|
15
15
|
# All rights reserved.
|
16
16
|
#
|
17
17
|
# Redistribution and use in source and binary forms, with or without
|
@@ -163,6 +163,6 @@ module CLASP
|
|
163
163
|
|
164
164
|
end # module CLASP
|
165
165
|
|
166
|
-
# ############################## end of file ############################# #
|
167
166
|
|
167
|
+
# ############################## end of file ############################# #
|
168
168
|
|
data/lib/clasp/old_module.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
|
2
2
|
# ######################################################################## #
|
3
|
-
# File:
|
3
|
+
# File: clasp/old_module.rb
|
4
4
|
#
|
5
|
-
# Purpose:
|
6
|
-
# gem)
|
5
|
+
# Purpose: Introduces old module Clasp (which clashes with an existing gem)
|
7
6
|
#
|
8
|
-
# Created:
|
9
|
-
# Updated:
|
7
|
+
# Created: 10th June 2016
|
8
|
+
# Updated: 6th March 2025
|
10
9
|
#
|
11
|
-
# Home:
|
10
|
+
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
12
11
|
#
|
13
|
-
# Author:
|
12
|
+
# Author: Matthew Wilson
|
14
13
|
#
|
15
|
-
# Copyright (c)
|
14
|
+
# Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems
|
15
|
+
# Copyright (c) 2016-2019, Matthew Wilson and Synesis Software
|
16
16
|
# All rights reserved.
|
17
17
|
#
|
18
18
|
# Redistribution and use in source and binary forms, with or without
|
@@ -50,6 +50,6 @@ require 'clasp'
|
|
50
50
|
# Backwards-compatible alias for the CLASP library's CLASP module
|
51
51
|
Clasp = CLASP
|
52
52
|
|
53
|
-
# ############################## end of file ############################# #
|
54
53
|
|
54
|
+
# ############################## end of file ############################# #
|
55
55
|
|