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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: f92b789f37af02b75b9644ff0d68c2f8dc1fb37bed7372f85a2e3076bda3318c
4
- data.tar.gz: 915b038fa26a675ff5adef533286ed89dd1637cab521d9d187eb2cc28eb60405
2
+ SHA1:
3
+ metadata.gz: bdf2add70e2d8e134e6759718fabde89ecb5c158
4
+ data.tar.gz: dcf9e41a17a28f53406daef64bdba1f614f2a080
5
5
  SHA512:
6
- metadata.gz: 14b4ed81618a5564af21068ed04f8443cb0e699763f3489d91deae285bf3e7b2e5a8b77e0331185cec751659772ddd6d54a3a93ac1ee98aaf05f0a11c12d78b4
7
- data.tar.gz: 90b82b5a6b1553c540f8904dbc4c2b3fe7257a0c177fbb4cacc4004af9e46470f5f0af8e119a635cf25062ab1b41a7bee54c9c4a512e74a48807b9cda4da4779
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
  [![Gem Version](https://badge.fury.io/rb/clasp-ruby.svg)](https://badge.fury.io/rb/clasp-ruby)
5
5
 
6
- ## Installation & usage
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
- ## Examples
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.Option('--opt1=val1', alias: '-v'),
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
- ## Where to get help
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
- ## Contribution guidelines
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
- ## Related projects
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
- **CLASP.Ruby** is used in the **[libCLImate.Ruby](https://github.com/synesissoftware/libCLImate.Ruby)** library.
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
- ## License
238
+ ### License
217
239
 
218
240
  **CLASP.Ruby** is released under the 3-clause BSD license. See LICENSE for details.
219
241
 
@@ -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.Option('--opt1=val1', alias: '-v'),
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
 
@@ -6,7 +6,7 @@
6
6
  # CLASP.Ruby
7
7
  #
8
8
  # Created: 14th February 2014
9
- # Updated: 19th April 2019
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.rb')
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
- actual_value = value
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
- if value.nil? && argument_spec
169
+ warn "unexpected constraint on argument specification #{argument_spec} when parsing argument '#{arg}'"
170
+ end
171
+ else
146
172
 
147
- actual_value = argument_spec.default_value
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
- @value = actual_value
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
- want_option_value = false
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
- want_option_value = true
563
- options << OptionArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, nil, argument_spec ? argument_spec.extras : nil)
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 want_option_value and not forced_value
616
+ if pending_option
579
617
 
580
- option = options[-1]
581
- option.instance_eval("@value='#{arg}'")
582
- want_option_value = false
583
- else
618
+ value = forced_value ? nil : arg
584
619
 
585
- arg = arg.dup
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
- arg.define_singleton_method(:given_index) { arg_ix }
622
+ pending_option = nil
589
623
 
590
- values << arg
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
@@ -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
 
@@ -60,45 +60,49 @@ module CLASP
60
60
  =end
61
61
 
62
62
  # :stopdoc:
63
- module CLI_helpers_
64
63
 
65
- module Constants
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
- # :nodoc:
72
- def self.generate_version_string_ options
76
+ # @!visibility private
77
+ def self.generate_version_string_ options # :nodoc:
73
78
 
74
- program_name = options[:program_name] || File.basename($0)
79
+ program_name = options[:program_name] || File.basename($0)
75
80
 
76
- version_prefix = options[:version_prefix]
81
+ version_prefix = options[:version_prefix]
77
82
 
78
- if options[:version]
83
+ if options[:version]
79
84
 
80
- case options[:version]
81
- when ::Array
82
- version = options[:version].join('.')
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
- version_major = options[:version_major] or raise ArgumentError, "options must specify :version or :version_major [ + :version_minor [ + :version_revision [ + :version_build ]]]"
89
- version_minor = options[:version_minor]
90
- version_rev = options[:version_revision]
91
- version_build = options[:version_build]
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
- version = version_major.to_s
94
- version += ".#{version_minor}" if version_minor
95
- version += ".#{version_rev}" if version_rev
96
- version += ".#{version_build}" if version_build
97
- end
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
  # ######################################################################## #
@@ -5,7 +5,7 @@
5
5
  # Purpose: Argument specification classes
6
6
  #
7
7
  # Created: 25th October 2014
8
- # Updated: 19th April 2019
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
- def initialize(name, aliases, help, extras = nil)
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
- def self.Help(extras = nil)
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
- return self.new(h.name, h.aliases, h.help, extras) if extras
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
- def self.Version(extras = nil)
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
- return self.new(h.name, h.aliases, h.help, extras) if extras
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
- def initialize(name, aliases, help, values_range, default_value, required, required_message, extras = nil)
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
- def CLASP.Flag(name, options = {})
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
- def CLASP.Option(name, options = {})
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)