optiflag 0.6 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ReleaseNotes.txt +35 -0
- data/doc/classes/OptiFlag.html +439 -0
- data/doc/classes/OptiFlag.src/M000001.html +49 -0
- data/doc/classes/OptiFlag.src/M000002.html +49 -0
- data/doc/classes/OptiFlag.src/M000003.html +30 -0
- data/doc/classes/OptiFlag/Flagset.html +459 -0
- data/doc/classes/OptiFlag/Flagset.src/M000003.html +45 -0
- data/doc/classes/OptiFlag/Flagset.src/M000004.html +45 -0
- data/doc/classes/OptiFlag/Flagset.src/M000005.html +18 -0
- data/doc/classes/OptiFlag/Flagset.src/M000006.html +20 -0
- data/doc/classes/OptiFlag/Flagset.src/M000007.html +35 -0
- data/doc/classes/OptiFlag/Flagset.src/M000008.html +23 -0
- data/doc/classes/OptiFlag/Flagset.src/M000009.html +24 -0
- data/doc/classes/OptiFlag/Flagset.src/M000010.html +28 -0
- data/doc/classes/OptiFlag/Flagset.src/M000011.html +20 -0
- data/doc/classes/OptiFlag/Flagset.src/M000012.html +24 -0
- data/doc/classes/OptiFlag/Flagset.src/M000013.html +24 -0
- data/doc/classes/OptiFlag/Flagset.src/M000014.html +32 -0
- data/doc/classes/OptiFlag/Flagset.src/M000015.html +25 -0
- data/doc/classes/OptiFlag/Flagset.src/M000016.html +53 -0
- data/doc/classes/OptiFlag/Flagset.src/M000017.html +53 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.html +930 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000024.html +36 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000025.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000026.html +36 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000027.html +36 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000028.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000029.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000030.html +19 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000031.html +19 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000032.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000033.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000034.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000035.html +22 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000036.html +19 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000037.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000038.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000039.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000040.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000041.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000042.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000043.html +19 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000044.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000045.html +19 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000046.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000047.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000048.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000049.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000050.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000051.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000052.html +20 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000053.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000054.html +18 -0
- data/doc/classes/OptiFlag/Flagset/EachFlag.src/M000055.html +22 -0
- data/doc/classes/OptiFlag/Flagset/Errors.html +192 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000021.html +18 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000022.html +19 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000023.html +18 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000024.html +18 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000025.html +19 -0
- data/doc/classes/OptiFlag/Flagset/Errors.src/M000026.html +36 -0
- data/doc/classes/OptiFlag/Flagset/Help.html +125 -0
- data/doc/classes/OptiFlag/Flagset/Help/Bundle.html +160 -0
- data/doc/classes/OptiFlag/Flagset/Help/Bundle.src/M000018.html +18 -0
- data/doc/classes/OptiFlag/Flagset/Help/Bundle.src/M000019.html +18 -0
- data/doc/classes/OptiFlag/Flagset/Help/StandardHelpBundle.html +118 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.html +296 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000017.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000018.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000019.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000020.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000021.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000022.html +18 -0
- data/doc/classes/OptiFlag/Flagset/NewInterface.src/M000023.html +18 -0
- data/doc/created.rid +1 -0
- data/doc/files/optiflag-help_rb.html +101 -0
- data/doc/files/optiflag-parse_rb.html +101 -0
- data/doc/files/optiflag_rb.html +167 -0
- data/doc/files/optiflag_rb.src/M000001.html +18 -0
- data/doc/fr_class_index.html +34 -0
- data/doc/fr_file_index.html +29 -0
- data/doc/fr_method_index.html +82 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/examples/example_1.rb +21 -0
- data/examples/example_1_1.rb +21 -0
- data/{doc/example → examples}/example_1_2.rb +8 -8
- data/examples/example_2.rb +31 -0
- data/{doc/example → examples}/example_2_1.rb +4 -4
- data/{doc/example → examples}/example_2_2.rb +7 -5
- data/{doc/example → examples}/example_2_3.rb +9 -9
- data/{doc/example → examples}/example_2_4.rb +4 -4
- data/{doc/example → examples}/example_2_5.rb +4 -4
- data/{doc/example → examples}/example_2_6.rb +6 -6
- data/{doc/example → examples}/example_3.rb +7 -6
- data/examples/example_6.rb +20 -0
- data/{doc/example → examples}/example_7.rb +5 -4
- data/examples/example_8.rb +26 -0
- data/optiflag-help.rb +42 -0
- data/optiflag-parse.rb +281 -0
- data/optiflag.gemspec +4 -3
- data/optiflag.rb +972 -0
- data/quick.rb +12 -0
- data/{test → testcases}/tc_advanced_usage_helping.rb +4 -0
- data/{test → testcases}/tc_basic_alternate_forms.rb +0 -0
- data/{test → testcases}/tc_basic_char_flags.rb +12 -12
- data/{test → testcases}/tc_basic_optional_flag.rb +0 -0
- data/{test → testcases}/tc_basic_parsing.rb +0 -0
- data/{test → testcases}/tc_basic_usage_helping.rb +0 -0
- data/{test → testcases}/tc_basic_value_validation.rb +0 -0
- data/{test → testcases}/tc_bug_one.rb +0 -0
- data/{test → testcases}/tc_bug_two.rb +0 -0
- data/{test → testcases}/tc_change_symbols.rb +0 -0
- data/{test → testcases}/tc_enumerated_value_validation.rb +0 -0
- data/{test → testcases}/tc_flagall.rb +4 -0
- data/{test → testcases}/tc_flagless_arg.rb +0 -0
- data/{test → testcases}/tc_keyword.rb +0 -0
- data/testcases/tc_new_basic_parsing.rb +51 -0
- data/testcases/tc_poro_tester.rb +30 -0
- data/{test → testcases}/tc_values_as_hash.rb +0 -0
- metadata +152 -52
- data/doc/example/example_1.rb +0 -30
- data/doc/example/example_1_1.rb +0 -27
- data/doc/example/example_2.rb +0 -28
- data/doc/example/example_4.rb +0 -12
- data/doc/example/example_5.rb +0 -26
- data/doc/example/example_6.rb +0 -17
- data/lib/optiflag.rb +0 -860
data/optiflag.gemspec
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'rake'
|
2
2
|
Gem::Specification.new do |spec|
|
3
3
|
spec.name = "optiflag"
|
4
|
-
|
5
|
-
spec.
|
4
|
+
spec.require_path = '.'
|
5
|
+
spec.version = "0.6.5"
|
6
|
+
spec.summary = "OptiFlag is an embeddable DSL library for declaring and using command-line options/flags in any Ruby program."
|
6
7
|
spec.author = "Daniel Eklund"
|
7
8
|
spec.email = "doeklund@gmail.com"
|
8
9
|
spec.homepage = "http://rubyforge.org/projects/optiflag/"
|
9
10
|
spec.files = FileList['**/*'].to_a
|
10
|
-
spec.test_files = FileList['
|
11
|
+
spec.test_files = FileList['testcases/tc*'].to_a - ["testcases/tc_flagall.rb"]
|
11
12
|
spec.has_rdoc = true
|
12
13
|
spec.rubyforge_project = 'optiflag'
|
13
14
|
end
|
data/optiflag.rb
ADDED
@@ -0,0 +1,972 @@
|
|
1
|
+
# == OptiFlag "Command Line DSL" Parser
|
2
|
+
# Please see:
|
3
|
+
# http://optiflag.rubyforge.org
|
4
|
+
# for useful examples and discussion.
|
5
|
+
#
|
6
|
+
# Author:: Daniel O. Eklund
|
7
|
+
# Copyright:: Copyright (c) 2006 Daniel O. Eklund. All rights reserved.
|
8
|
+
# License:: Ruby license.
|
9
|
+
module OptiFlag
|
10
|
+
VERSION = "0.6.5"
|
11
|
+
end
|
12
|
+
|
13
|
+
load 'optiflag-help.rb'
|
14
|
+
load 'optiflag-parse.rb'
|
15
|
+
|
16
|
+
module OptiFlag
|
17
|
+
module Flagset
|
18
|
+
@dash_symbol = "-"
|
19
|
+
attr_reader :dash_symbol
|
20
|
+
module_function :dash_symbol
|
21
|
+
# method called by 'send' using a hash of
|
22
|
+
# values, the key being the name
|
23
|
+
# of the method (this method) and the
|
24
|
+
# value being the parameter to be passed
|
25
|
+
# to the method. Therefore,
|
26
|
+
# module Example extend OptiFlagSet(:flag_symbol => "/")
|
27
|
+
# is invoking this method 'flag_symbol' and passing
|
28
|
+
# the value "/" as the parameter.
|
29
|
+
# See the RDoc for the *method* 'OptiFlag::Flagset()'
|
30
|
+
# in the OptiFlag module,
|
31
|
+
# *not* the module OptiFlag::Flagset which it resembles.
|
32
|
+
#
|
33
|
+
# This method, when invoked using the above expression
|
34
|
+
# changes the default flag symbol from "-" to whatever
|
35
|
+
# is passed in. Thus, if we wanted to simulate
|
36
|
+
# the MSDos flags, we would use:
|
37
|
+
# module Example extend OptiFlagSet(:flag_symbol => "/")
|
38
|
+
# which would then parse a command line looking like:
|
39
|
+
# /h /renew /username daniel /password fluffy
|
40
|
+
def self.flag_symbol(val)
|
41
|
+
@dash_symbol = val
|
42
|
+
end
|
43
|
+
def self.increment_order_counter()
|
44
|
+
@counter ||= 0
|
45
|
+
@counter = @counter + 1
|
46
|
+
return @counter -1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module OptiFlag
|
52
|
+
module Flagset
|
53
|
+
# The class *EachFlag* is the template for each flag
|
54
|
+
# instantiated by a <i>flag set declaration</i>.
|
55
|
+
# One EachFlag is instantiated for each <i>flag
|
56
|
+
# declaration</i>. For example, the following <i>flag-set
|
57
|
+
# declaration</i>:
|
58
|
+
#
|
59
|
+
# module Example extend OptiFlagSet
|
60
|
+
# flag "dir"
|
61
|
+
# optional_flag "log"
|
62
|
+
# flag "username"
|
63
|
+
# flag "password"
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# will instantiate four EachFlag instances.
|
67
|
+
#
|
68
|
+
# The <i>flag declarations</i> are methods on the OptiFlag::Flagset
|
69
|
+
# module that actually instantiate each
|
70
|
+
# one of these EachFlag instances. They are listed in the
|
71
|
+
# RDoc for the OptiFlag::Flagset sub-module and are labeled
|
72
|
+
# as top-level flag-declarers.
|
73
|
+
#
|
74
|
+
# An EachFlag object has many methods belonging to
|
75
|
+
# different categories of usage (though nothing enforced
|
76
|
+
# by the language or the code itself).
|
77
|
+
#
|
78
|
+
# == Clause Level Modifiers
|
79
|
+
# These are methods that are used by the API _user_ of the
|
80
|
+
# OptiFlag suite,(i.e. a programmer of other Ruby code but not
|
81
|
+
# the OptiFlag code itself). These methods are used *within*
|
82
|
+
# a <i>flag declaration</i>. For example, in the following code:
|
83
|
+
#
|
84
|
+
# module Example extend OptiFlagSet
|
85
|
+
# flag "dir" do
|
86
|
+
# alternate_forms "directory","D","d"
|
87
|
+
# description "The Appliction Directory"
|
88
|
+
# end
|
89
|
+
# optional_flag "log" do
|
90
|
+
# description "The directory in which to find the log files"
|
91
|
+
# long_form "logging-directory" # long form is keyed after the '--' symbol
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# There will be two EachFlag instances instantiated. For the
|
96
|
+
# first EachFlag instance, the one named "dir", two of these
|
97
|
+
# <i>clause-level modifiers</i> are invoked *on* the Eachflag instance
|
98
|
+
# by the OptiFlag *user*. These clause-level modifiers modify the
|
99
|
+
# expected behavior of each
|
100
|
+
#
|
101
|
+
# == List (clause API) of <i>clause level modifiers</i>
|
102
|
+
# * 'description' -- the description of the
|
103
|
+
# * 'required' -- indicates whether this flag is required
|
104
|
+
#
|
105
|
+
# == Internal Implementation Notes
|
106
|
+
# This RDoc section is of concern only to implementors
|
107
|
+
# of OptiFlag. If you are using OptiFlag in your
|
108
|
+
# application, chances are this section is of little use to you.
|
109
|
+
#
|
110
|
+
# === 'the' members.
|
111
|
+
# Because OptiFlag seeks to provide a nice DSL to the user,
|
112
|
+
# many of the names of the clause-level modifiers are also
|
113
|
+
# useful names for methods which could access the internal
|
114
|
+
# field.
|
115
|
+
#
|
116
|
+
# So, we have a problem. For instance, in the following
|
117
|
+
# code:
|
118
|
+
# module Example extend OptiFlagSet
|
119
|
+
# flag "username", :description => "Database username." # alternate form
|
120
|
+
#
|
121
|
+
# and_process!
|
122
|
+
# end
|
123
|
+
# the method 'description' has been written to modify the EachClass
|
124
|
+
# instance appropriately. But now, if you are accessing this
|
125
|
+
# EachClass instance in some other part of the OptiFlag internals
|
126
|
+
# (as, for instance, the help functionality would), then the use
|
127
|
+
# of the attr syntax would clash with this method.
|
128
|
+
# attr_accessor :description
|
129
|
+
# # this meta-code would generate both the
|
130
|
+
# # getter and the setter, where the getter method
|
131
|
+
# # def description()
|
132
|
+
# # return @desciption
|
133
|
+
# # end
|
134
|
+
# # would conflict with the description method we
|
135
|
+
# # have provided for the user
|
136
|
+
# The solution to this problem is to leave the standard (useful)
|
137
|
+
# method names for the <i>clause level modifiers</i> of the
|
138
|
+
# EachFlag instance and introduce another *consistent* name
|
139
|
+
# for <b>the actual</b> internal field.
|
140
|
+
# For a while, these internal fields and their attr's were
|
141
|
+
# named the_actual_description etc. But this proved to
|
142
|
+
# be a mouthful. Thereafter, the consistent naming scheme was
|
143
|
+
# to place 'the_' in front of the field.
|
144
|
+
#
|
145
|
+
# Therefore, for most of the data based <i>clause level modifiers</i>
|
146
|
+
# (live 'description' which saves the description the user
|
147
|
+
# has provided), there is provided a parallel 'the_description'
|
148
|
+
# accessor ( or reader or writer, depending on the needs).
|
149
|
+
#
|
150
|
+
# In summary, 'description' is a public API (for use by
|
151
|
+
# users of the OptiFlag suite) and 'the_description' is a
|
152
|
+
# a package-protected API.
|
153
|
+
class EachFlag
|
154
|
+
attr_reader :name, :flag, :order_added,:validation_error,:enclosing_module,:default_used
|
155
|
+
# the 'the' values.. the actual means by which to access the values
|
156
|
+
# set by the clause-level modifiers.
|
157
|
+
attr_reader :the_pretranslate,:the_posttranslate,
|
158
|
+
:the_posttranslate_all,:the_pretranslate_all,:the_description,:the_long_dash_symbol,:the_dash_symbol,
|
159
|
+
:the_arity,:the_long_form,:the_alternate_forms,:the_validation_rules,
|
160
|
+
:the_is_required
|
161
|
+
attr_writer :the_form_that_is_actually_used
|
162
|
+
attr_accessor :value,:for_help,:for_extended_help,:proxied_bound_method
|
163
|
+
def initialize(name,flag,enclosing_module)
|
164
|
+
# these next two lines are a highly complicated hack needed to make
|
165
|
+
# the use of two module definitions in one file, one with a flag_symbol
|
166
|
+
# and one without.. See tc_change_symbols.rb for the two tests that used to
|
167
|
+
# cause the problem... also see the changes as part of the definition of
|
168
|
+
# OptiFlag.Flagset().... -- D.O.E 5/30/06
|
169
|
+
# Search for 'def OptiFlag.Flagset(hash)' in this
|
170
|
+
singleton_class_of_enclosing_module = class << enclosing_module; self; end;
|
171
|
+
x = singleton_class_of_enclosing_module.included_modules.select do |x|
|
172
|
+
(x.to_s =~ /OptiF/) or (x.to_s =~ /#<Modu/)
|
173
|
+
end[0]
|
174
|
+
# the following batch of code is pure initialization
|
175
|
+
@the_compresses,@enclosing_module = false,enclosing_module
|
176
|
+
@validation_error,@the_validation_rules = [],[]
|
177
|
+
@order_added = OptiFlag::Flagset::increment_order_counter()
|
178
|
+
@name,@flag,@the_long_form = name,flag,flag
|
179
|
+
@the_dash_symbol, @the_arity, @the_alternate_forms,
|
180
|
+
@the_is_required, @the_long_dash_symbol = x.dash_symbol, 1, [], true, "--"
|
181
|
+
# puts "#{ @order_added } --- #{ @name }"
|
182
|
+
end
|
183
|
+
# translate() is a clause-level flag-modifier.
|
184
|
+
# It can be used in the following form:
|
185
|
+
#
|
186
|
+
def translate(position=0,&theblock)
|
187
|
+
pretranslate(position,&theblock)
|
188
|
+
end
|
189
|
+
# clause-level flag-modifier
|
190
|
+
def translate_all(&theblock)
|
191
|
+
pretranslate_all(&theblock)
|
192
|
+
end
|
193
|
+
# clause-level flag-modifier
|
194
|
+
def pretranslate(position=0,&theblock)
|
195
|
+
@the_pretranslate ||= []
|
196
|
+
@the_pretranslate[position] = theblock
|
197
|
+
end
|
198
|
+
# clause-level flag-modifier
|
199
|
+
def posttranslate(position=0,&theblock)
|
200
|
+
@the_posttranslate ||= []
|
201
|
+
@the_posttranslate[position] = theblock
|
202
|
+
end
|
203
|
+
# clause-level flag-modifier
|
204
|
+
def pretranslate_all(&theblock)
|
205
|
+
@the_pretranslate_all = theblock
|
206
|
+
end
|
207
|
+
# clause-level flag-modifier
|
208
|
+
def posttranslate_all(&theblock)
|
209
|
+
@the_posttranslate_all = theblock
|
210
|
+
end
|
211
|
+
# clause-level flag-modifier
|
212
|
+
def is_required(yes_or_no)
|
213
|
+
@the_is_required = yes_or_no
|
214
|
+
end
|
215
|
+
# clause-level flag-modifier
|
216
|
+
def value_matches(desc_regexp_pair,arg_position=0)
|
217
|
+
if desc_regexp_pair.class == Regexp
|
218
|
+
desc_regexp_pair =
|
219
|
+
["This value does not match the pattern: #{ desc_regexp_pair.source }",
|
220
|
+
desc_regexp_pair]
|
221
|
+
end
|
222
|
+
validates_against do |flag,errors|
|
223
|
+
value = [flag.value] if value.class != Array
|
224
|
+
desc,regexp = desc_regexp_pair
|
225
|
+
if ! value[arg_position].match regexp
|
226
|
+
problem = "For the flag: '#{ flag.as_string_basic }' the value you gave was '#{ value[arg_position] }'."
|
227
|
+
problem << "\n #{ desc }"
|
228
|
+
errors << problem
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
# clause-level flag-modifier
|
233
|
+
def value_in_set(array_of_acceptable_values,arg_position=0)
|
234
|
+
# refactored to use validates_against
|
235
|
+
validates_against do |flag,errors|
|
236
|
+
value = [flag.value] if value.class != Array
|
237
|
+
something_matches =
|
238
|
+
array_of_acceptable_values.select{|x| x.to_s == value[arg_position] }
|
239
|
+
if something_matches.length == 0
|
240
|
+
problem = <<-PROBLEMO
|
241
|
+
For the flag: '#{ flag.as_string_basic }' the value you gave was '#{ value[arg_position] }'.
|
242
|
+
But the value must be one of the following: [#{ array_of_acceptable_values.join(', ') }]
|
243
|
+
PROBLEMO
|
244
|
+
errors << problem
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
# <b>Clause-level modifier.</b>
|
249
|
+
# The user of this construct will pass a block that accepts two arguments:
|
250
|
+
# * the flag (of class EachFlag) and
|
251
|
+
# * an errors array.
|
252
|
+
# If the user wants to indicate that a validation error has occurred
|
253
|
+
# (and that further processing should stop) he/she needs to add a
|
254
|
+
# string of the problem to the errrors array.<br/>
|
255
|
+
# The following (silly) example validates that the username is 'daniel'.
|
256
|
+
# If it's not, the code adds to the errors array, and OptiFlag will
|
257
|
+
# indicate a validation error.
|
258
|
+
# flag "username"
|
259
|
+
# description "The username"
|
260
|
+
# validates_against do |flag,errors|
|
261
|
+
# if flag.value != "daniel"
|
262
|
+
# errors << "You are NOT DANIEL!"
|
263
|
+
# end
|
264
|
+
# end
|
265
|
+
# end
|
266
|
+
def validates_against(&theblock)
|
267
|
+
@the_validation_rules ||= []
|
268
|
+
@the_validation_rules << theblock
|
269
|
+
end
|
270
|
+
# clause-level flag-modifier
|
271
|
+
def required
|
272
|
+
is_required(true)
|
273
|
+
end
|
274
|
+
# clause-level flag-modifier
|
275
|
+
def optional
|
276
|
+
is_required(false)
|
277
|
+
end
|
278
|
+
# * Clause-level flag-modifier.
|
279
|
+
# * Synonym for 'no_args'.
|
280
|
+
# * Takes no arguments (for itself).
|
281
|
+
# * Indicates that the flag takes no arguments. (i.e.
|
282
|
+
# the flag has zero arity).
|
283
|
+
# * Sample usage (embedded within a <i>flag set declaration</i>):
|
284
|
+
# flag "log" do
|
285
|
+
# no_arg
|
286
|
+
# end
|
287
|
+
def no_arg
|
288
|
+
no_args
|
289
|
+
end
|
290
|
+
# Clause-level flag-modifier.
|
291
|
+
def no_args
|
292
|
+
arity 0
|
293
|
+
end
|
294
|
+
# clause-level flag-modifier
|
295
|
+
def one_arg
|
296
|
+
arity 1
|
297
|
+
end
|
298
|
+
# clause-level flag-modifier
|
299
|
+
def two_args
|
300
|
+
arity 2
|
301
|
+
end
|
302
|
+
# clause-level flag-modifier
|
303
|
+
def alternate_forms(*args)
|
304
|
+
@the_alternate_forms = *args if args[0].class == Array
|
305
|
+
@the_alternate_forms = @the_alternate_forms + args if args[0].class != Array
|
306
|
+
end
|
307
|
+
# clause-level flag-modifier
|
308
|
+
def long_form(form)
|
309
|
+
@the_long_form = form
|
310
|
+
end
|
311
|
+
|
312
|
+
# clause-level flag-modifier
|
313
|
+
def default(default_value)
|
314
|
+
@default_used = true
|
315
|
+
@value = default_value
|
316
|
+
end
|
317
|
+
|
318
|
+
# clause-level flag-modifier
|
319
|
+
def arity(num)
|
320
|
+
@the_arity = num
|
321
|
+
end
|
322
|
+
# clause-level flag-modifier
|
323
|
+
def dash_symbol(symb)
|
324
|
+
@the_dash_symbol = symb
|
325
|
+
end
|
326
|
+
# clause-level flag-modifier
|
327
|
+
def long_dash_symbol(symb)
|
328
|
+
@the_long_dash_symbol = symb
|
329
|
+
end
|
330
|
+
# clause-level flag-modifier
|
331
|
+
def description(desc)
|
332
|
+
@the_description = desc
|
333
|
+
end
|
334
|
+
# clause-level flag-modifier
|
335
|
+
def compresses(val=true)
|
336
|
+
@the_compresses = val
|
337
|
+
end
|
338
|
+
def as_string_basic
|
339
|
+
"#{ self.the_dash_symbol }#{ self.flag }"
|
340
|
+
end
|
341
|
+
def as_alternate_forms
|
342
|
+
ret = @the_alternate_forms.collect do |x|
|
343
|
+
"#{ self.the_dash_symbol }#{ x }"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
def as_string_extended
|
347
|
+
"#{ self.the_long_dash_symbol }#{self.the_long_form }"
|
348
|
+
end
|
349
|
+
def as_the_form_that_is_actually_used
|
350
|
+
@the_form_that_is_actually_used
|
351
|
+
end
|
352
|
+
def value=(val)
|
353
|
+
@default_used = false
|
354
|
+
@value = val
|
355
|
+
if pbMeth = self.proxied_bound_method
|
356
|
+
pbMeth.call val
|
357
|
+
end
|
358
|
+
end
|
359
|
+
alias :with_long_form :long_form
|
360
|
+
end # end of EachFlag class
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
module OptiFlag
|
365
|
+
# testing to see if this shows (1)
|
366
|
+
module Flagset
|
367
|
+
# top-level flag-declarer
|
368
|
+
def flag(flag_name_pair,hash={},&the_block)
|
369
|
+
if flag_name_pair.class == String or flag_name_pair.class == Symbol
|
370
|
+
flag_name_pair = [flag_name_pair.to_s,flag_name_pair.to_sym]
|
371
|
+
end
|
372
|
+
flag = flag_name_pair[0]
|
373
|
+
if flag_name_pair[1]
|
374
|
+
name = flag_name_pair[1]
|
375
|
+
else
|
376
|
+
name = flag.to_sym
|
377
|
+
end
|
378
|
+
@all_flags ||= {}
|
379
|
+
obj = @all_flags[name]
|
380
|
+
obj ||= EachFlag.new(name,flag,self)
|
381
|
+
obj.instance_eval &the_block if block_given?
|
382
|
+
hash.each_pair do |fxn,val|
|
383
|
+
obj.send(fxn,val)
|
384
|
+
end
|
385
|
+
@all_flags[name] = obj
|
386
|
+
return obj
|
387
|
+
end
|
388
|
+
# top-level flag-declarer
|
389
|
+
def optional_flag(flag_name_pair,hash={},&the_block)
|
390
|
+
flag(flag_name_pair,hash,&the_block)
|
391
|
+
flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
|
392
|
+
name = flag_name_pair[1] || flag_name_pair[0]
|
393
|
+
flag_properties name.to_sym do
|
394
|
+
optional
|
395
|
+
end
|
396
|
+
end
|
397
|
+
# top-level flag-declarer
|
398
|
+
def optional_switch_flag(flag_name_pair,hash={},&the_block)
|
399
|
+
flag(flag_name_pair,hash,&the_block)
|
400
|
+
flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
|
401
|
+
name = flag_name_pair[1] || flag_name_pair[0]
|
402
|
+
flag_properties name.to_sym do
|
403
|
+
optional
|
404
|
+
arity 0
|
405
|
+
end
|
406
|
+
end
|
407
|
+
# top-level flag-declarer
|
408
|
+
def keyword(flag_name_pair,hash={},&the_block)
|
409
|
+
@all_keywords ||= []
|
410
|
+
@all_keywords << name
|
411
|
+
flag(flag_name_pair,hash,&the_block)
|
412
|
+
flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
|
413
|
+
name = flag_name_pair[1] || flag_name_pair[0]
|
414
|
+
flag_properties name.to_sym do
|
415
|
+
dash_symbol ""
|
416
|
+
long_dash_symbol ""
|
417
|
+
arity 0
|
418
|
+
optional
|
419
|
+
end
|
420
|
+
end
|
421
|
+
# top-level flag-declarer
|
422
|
+
def flagless_arg(name)
|
423
|
+
@all_flagless_arg ||= []
|
424
|
+
mine = flag(name.to_sym)
|
425
|
+
@all_flagless_arg << mine
|
426
|
+
end
|
427
|
+
# top-level flag-declarer
|
428
|
+
def usage_flag(*args)
|
429
|
+
# to ensure the existence of the @all_flags
|
430
|
+
@all_flags ||= {}
|
431
|
+
first,*rest = args
|
432
|
+
|
433
|
+
# the next two statements are necessary because
|
434
|
+
# a user might declare a usage flag, but so might
|
435
|
+
# the and_process! method. We need to make
|
436
|
+
# sure that they both refer to the same EachFlag
|
437
|
+
any_help_already_set = @all_flags.select {|key,val| val.for_help == true}
|
438
|
+
if any_help_already_set[0] != nil
|
439
|
+
# reassign rest to be the orginal first plus the rest
|
440
|
+
# UNLESS the first is the exact same one as your previous
|
441
|
+
# first -- GOTCHA!!
|
442
|
+
rest = [first] + rest if first.to_sym != any_help_already_set[0][0].to_sym
|
443
|
+
# and now use the discovered existing help flag key as our new first
|
444
|
+
# remember that the optional_flag statement below will
|
445
|
+
# merely reopen the existing object stored in the hash
|
446
|
+
# instead of creating a new one
|
447
|
+
first = any_help_already_set[0][0]
|
448
|
+
end
|
449
|
+
optional_flag [first] do
|
450
|
+
self.for_help = true
|
451
|
+
description "Help"
|
452
|
+
no_args
|
453
|
+
alternate_forms *rest if rest.length > 0
|
454
|
+
end
|
455
|
+
end
|
456
|
+
# top-level flag-declarer
|
457
|
+
def extended_help_flag(*args)
|
458
|
+
first,*rest = args
|
459
|
+
optional_flag [first] do
|
460
|
+
self.for_extended_help = true
|
461
|
+
description "Extended Help"
|
462
|
+
no_args
|
463
|
+
alternate_forms *rest if rest.length > 0
|
464
|
+
end
|
465
|
+
end
|
466
|
+
# top-level flag-declarer
|
467
|
+
def character_flag(switch,group="default",&the_block)
|
468
|
+
throw "Character switches can only be 1 character long" if switch.to_s.length > 1
|
469
|
+
flag(switch.to_sym,&the_block)
|
470
|
+
@group ||= {}
|
471
|
+
the_flag_we_just_added = @all_flags[switch.to_sym]
|
472
|
+
|
473
|
+
key = [group.to_sym,the_flag_we_just_added.the_dash_symbol]
|
474
|
+
# puts "#{ key.join(',') }"
|
475
|
+
@group[key] ||= []
|
476
|
+
@group[key] << the_flag_we_just_added
|
477
|
+
# re-assert ourselves
|
478
|
+
flag [switch.to_s, switch] do
|
479
|
+
optional
|
480
|
+
arity 0
|
481
|
+
compresses
|
482
|
+
end
|
483
|
+
end
|
484
|
+
# top-level flag-declarer
|
485
|
+
def flag_properties(symb,hash={},&the_block)
|
486
|
+
raise "Block needed for flag_properties" if not block_given? and hash=={}
|
487
|
+
@all_flags ||= {}
|
488
|
+
obj = @all_flags[symb.to_sym]
|
489
|
+
return if obj==nil
|
490
|
+
obj.instance_eval &the_block if block_given?
|
491
|
+
hash.each_pair do |fxn,val|
|
492
|
+
obj.send(fxn,val)
|
493
|
+
end
|
494
|
+
end
|
495
|
+
alias :properties :flag_properties
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
# defining the callable client-interface
|
500
|
+
module OptiFlag
|
501
|
+
module Flagset
|
502
|
+
# The NewInterface module is used to augment the ARGV
|
503
|
+
# constant with some special methods that it never used
|
504
|
+
# to have before.
|
505
|
+
#
|
506
|
+
# This is one of two hallmark ideas in making the
|
507
|
+
# OptiFlag suite easier to use:
|
508
|
+
# - easy declarative DSL syntax (all the <i>flag set and flag declarations</i>)
|
509
|
+
# - and this, an easy to use interface for accessing
|
510
|
+
# the results *after* the processor has finished processing.
|
511
|
+
#
|
512
|
+
# To emphasize this point, consider the following declaration:
|
513
|
+
#
|
514
|
+
# module AppArgs extend OptiFlagSet
|
515
|
+
# flag "dir"
|
516
|
+
# optional_flag "log"
|
517
|
+
# flag "username"
|
518
|
+
# flag "password"
|
519
|
+
#
|
520
|
+
# and_process!
|
521
|
+
# end
|
522
|
+
#
|
523
|
+
# Note the <i>special command</i> 'and_process!'
|
524
|
+
# This method, which should, by rote, be placed at the end
|
525
|
+
# of the DSL-zone (the code internal to the module block)
|
526
|
+
# is augmenting the ARGV constant so that the results of the
|
527
|
+
# parsing are now available. Thus:
|
528
|
+
# ARGV.flag_value.dir
|
529
|
+
# has a value of whatever the user passed in on the command
|
530
|
+
# line for the '-dir' flag.
|
531
|
+
# And
|
532
|
+
# ARGV.flag_value.log?
|
533
|
+
# tells us whether the user supplied the log flag and if
|
534
|
+
# she did, we can access it using
|
535
|
+
#
|
536
|
+
# ARGV.flag_value.log
|
537
|
+
# Better looking code would be:
|
538
|
+
#
|
539
|
+
# log_file = ARGV.flag_value.log if ARGV.flag_value.log?
|
540
|
+
module NewInterface
|
541
|
+
attr_accessor :errors,:flag_value,:specification_errors,:help_requested_on,:warnings
|
542
|
+
attr_writer :help_requested,:extended_help_requested
|
543
|
+
def errors?
|
544
|
+
self.errors != nil
|
545
|
+
end
|
546
|
+
def warnings?
|
547
|
+
self.warnings != nil
|
548
|
+
end
|
549
|
+
def help_requested?
|
550
|
+
@help_requested != nil
|
551
|
+
end
|
552
|
+
def extended_help_requested?
|
553
|
+
@extended_help_requested !=nil
|
554
|
+
end
|
555
|
+
alias :flags :flag_value
|
556
|
+
end
|
557
|
+
class Errors
|
558
|
+
attr_accessor :missing_flags,:other_errors,:validation_errors
|
559
|
+
def initialize
|
560
|
+
@missing_flags,@other_errors,@validation_errors = [],[],[]
|
561
|
+
end
|
562
|
+
def any_errors?
|
563
|
+
@missing_flags.length >0 or @other_errors.length >0 or
|
564
|
+
@validation_errors.length > 0
|
565
|
+
end
|
566
|
+
def divulge_problems(output=$stdout)
|
567
|
+
output.puts "Errors found:"
|
568
|
+
if @missing_flags.length >0
|
569
|
+
output.puts "Missing Flags:"
|
570
|
+
@missing_flags.each do |x|
|
571
|
+
output.puts " #{ x }"
|
572
|
+
end
|
573
|
+
end
|
574
|
+
if @other_errors.length >0
|
575
|
+
output.puts "Other Errors:"
|
576
|
+
@other_errors.each do |x|
|
577
|
+
output.puts " #{ x }"
|
578
|
+
end
|
579
|
+
end
|
580
|
+
if @validation_errors.length >0
|
581
|
+
output.puts "Validation Errors:"
|
582
|
+
@validation_errors.each do |x|
|
583
|
+
output.puts " #{ x }"
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
private
|
589
|
+
def create_new_value_class()
|
590
|
+
klass = Hash.new
|
591
|
+
klass.instance_eval do
|
592
|
+
def init_with_these(all_objs)
|
593
|
+
@all_flags = all_objs
|
594
|
+
end
|
595
|
+
end
|
596
|
+
klass.init_with_these(@all_flags)
|
597
|
+
@all_flags.each_value do |y|
|
598
|
+
# only allow alphabetic symbols to create methods
|
599
|
+
if (y.name.to_s =~ /^[a-zA-Z]+/)
|
600
|
+
klass.instance_eval %{
|
601
|
+
def #{y.name}()
|
602
|
+
@all_flags[:#{ y.name }].value if @all_flags[:#{ y.name }]
|
603
|
+
end
|
604
|
+
def #{y.name}_details()
|
605
|
+
@all_flags[:#{ y.name }] if @all_flags[:#{ y.name }]
|
606
|
+
end}
|
607
|
+
end
|
608
|
+
all_names = [y.name]
|
609
|
+
all_names << y.the_alternate_forms if y.the_alternate_forms.length > 0
|
610
|
+
all_names.flatten!
|
611
|
+
all_names = all_names.select{|x| x.to_s =~ /^[a-zA-Z]+/}
|
612
|
+
all_names.each do |x|
|
613
|
+
klass.instance_eval %{
|
614
|
+
def #{x}?()
|
615
|
+
ret = @all_flags[:#{ y.name }].value
|
616
|
+
return false if ret == nil
|
617
|
+
if @all_flags[:#{ y.name }] and !@all_flags[:#{ y.name }].default_used
|
618
|
+
return @all_flags[:#{ y.name }].value
|
619
|
+
end
|
620
|
+
end}
|
621
|
+
end
|
622
|
+
end
|
623
|
+
return klass
|
624
|
+
end
|
625
|
+
|
626
|
+
end # end of Flagset module
|
627
|
+
end # end of OptiFlag module
|
628
|
+
|
629
|
+
|
630
|
+
|
631
|
+
module OptiFlag
|
632
|
+
# Special command (at the same level as a <i>flag declaration</i>)
|
633
|
+
def OptiFlag.using_object(a_single_object,&the_block)
|
634
|
+
class_hierarchy = [a_single_object.class]
|
635
|
+
clazz = a_single_object.class
|
636
|
+
begin
|
637
|
+
clazz = clazz.superclass
|
638
|
+
class_hierarchy << clazz
|
639
|
+
end until clazz != Object
|
640
|
+
potential_methods =
|
641
|
+
class_hierarchy.collect{|x| x.instance_methods(false)}.flatten.sort
|
642
|
+
|
643
|
+
require 'enumerator'
|
644
|
+
valid_instance_var = []
|
645
|
+
potential_opt_switch_flags, potential_methods =
|
646
|
+
potential_methods.partition {|x| x =~ /\?$/ }
|
647
|
+
potential_methods.each_slice(2) do |getter,setter|
|
648
|
+
if setter == (getter + "=")
|
649
|
+
valid_instance_var << [getter,setter];
|
650
|
+
end
|
651
|
+
end
|
652
|
+
mod = Module.new
|
653
|
+
mod.extend Flagset
|
654
|
+
valid_instance_var.each do |getter,setter|
|
655
|
+
bound_method = a_single_object.method(setter)
|
656
|
+
mod.instance_eval do
|
657
|
+
flag getter do
|
658
|
+
self.proxied_bound_method = bound_method
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
mod.instance_eval &the_block if the_block
|
663
|
+
mod.instance_eval do
|
664
|
+
handle_errors_and_help
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
# This is a method that looks like a module.
|
669
|
+
# It is an excellent example of the syntactic tricks
|
670
|
+
# that ruby permits us.
|
671
|
+
# This method allows us to provide code like
|
672
|
+
# the following:
|
673
|
+
# module Example extend OptiFlagSet(:flag_symbol => "/")
|
674
|
+
# flag "dir"
|
675
|
+
# flag "log"
|
676
|
+
# flag "username"
|
677
|
+
# flag "password"
|
678
|
+
#
|
679
|
+
# and_process!
|
680
|
+
# end
|
681
|
+
# You will note that the top line looks a lot like
|
682
|
+
# the standard top line
|
683
|
+
# # our top line
|
684
|
+
# module Example extend OptiFlagSet(:flag_symbol => "/")
|
685
|
+
# versus
|
686
|
+
# # standard top line
|
687
|
+
# module Example extend OptiFlagSet
|
688
|
+
# The difference is that while the latter (a standard
|
689
|
+
# top line) is a reference to a module, the former is
|
690
|
+
# a call to this method, that *returns* the OptiFlag::Flagset
|
691
|
+
# module with some defaults changed.
|
692
|
+
#
|
693
|
+
# As of now the only symbol/method supported by this
|
694
|
+
# method that looks like a module, is the
|
695
|
+
# 'OptiFlag::Flagset.flag_symbol' class method.
|
696
|
+
#
|
697
|
+
# For those still not understanding the syntactic trick,
|
698
|
+
# or who find it odd, consider that something
|
699
|
+
# similar to this is done
|
700
|
+
# in the ruby core language using the proxy/delegate
|
701
|
+
# pattern. (See delegate.rb in the Ruby core library)
|
702
|
+
# class Tempfile < DelegateClass(File)
|
703
|
+
# # ...
|
704
|
+
# # ...
|
705
|
+
# end
|
706
|
+
#
|
707
|
+
# You will note that the DelegateClass() is also
|
708
|
+
# a method that superficially resembles a class
|
709
|
+
# that parameterizes itself.
|
710
|
+
# This can be done because Ruby expects:
|
711
|
+
# class <identifier> < <expression>
|
712
|
+
# and not
|
713
|
+
# class <identifier> < <identifier>
|
714
|
+
# like some other languages. And likewise
|
715
|
+
# module <identifier> extend <expression>
|
716
|
+
# which allows us to create this method which
|
717
|
+
# has the exact same name as the module.
|
718
|
+
# Clever ruby.
|
719
|
+
def OptiFlag.Flagset(hash)
|
720
|
+
# changed this from just returning Flagset...
|
721
|
+
# Reason Being: a user can specify two modules in one file
|
722
|
+
# one with this method, and one just using Flagset...
|
723
|
+
# if you don't clone at this point, you are left with
|
724
|
+
# a global change... BUT to get the cloning working
|
725
|
+
# I had to do some singleton_class trickeration as part of
|
726
|
+
# the initialize method for EachFlag... I am not
|
727
|
+
# 100% sure I understand what I just did. -- D.O.E 5/30/06
|
728
|
+
mod = Flagset.clone
|
729
|
+
hash.each_pair do |symb,val|
|
730
|
+
mod.send(symb.to_sym,val)
|
731
|
+
end
|
732
|
+
return mod
|
733
|
+
end
|
734
|
+
|
735
|
+
end
|
736
|
+
|
737
|
+
module OptiFlag
|
738
|
+
module Flagset
|
739
|
+
# Special command (at the same level as a <i>flag declaration</i>)
|
740
|
+
def handle_errors_and_help(options={})
|
741
|
+
return if !@all_flags
|
742
|
+
# the next three lines allow me
|
743
|
+
# to increase testability of
|
744
|
+
# this function, allowing client code to
|
745
|
+
# simulate ARGV passing without actually
|
746
|
+
# depending on ARGV being there
|
747
|
+
options[:argv] ||= ARGV # set it, only if not set
|
748
|
+
options[:level] ||= :not_strict # breaks backwards compatability
|
749
|
+
argv = options[:argv]
|
750
|
+
# the next two lines add the help
|
751
|
+
# flag to the list.
|
752
|
+
usage_flag "h","?" # make this part of the standard config
|
753
|
+
properties "h", :long_form=>"help"
|
754
|
+
parse(argv,false)
|
755
|
+
if argv.help_requested?
|
756
|
+
if !argv.help_requested_on
|
757
|
+
show_help
|
758
|
+
elsif the_on = argv.help_requested_on
|
759
|
+
show_individual_extended_help(the_on.to_sym)
|
760
|
+
end
|
761
|
+
exit
|
762
|
+
end
|
763
|
+
if argv.extended_help_requested?
|
764
|
+
show_extended_help
|
765
|
+
exit
|
766
|
+
end
|
767
|
+
if argv.errors?
|
768
|
+
argv.errors.divulge_problems
|
769
|
+
# show_help
|
770
|
+
exit
|
771
|
+
end
|
772
|
+
if argv.warnings? and options[:level] == :with_no_warnings
|
773
|
+
puts "In strict warning handling mode. Warnings will cause process to exit."
|
774
|
+
argv.warnings.each do |x|
|
775
|
+
puts " #{ x }"
|
776
|
+
end
|
777
|
+
puts "Please fix these warnings and try again."
|
778
|
+
exit
|
779
|
+
end
|
780
|
+
# the next three lines augment the
|
781
|
+
# name of the module that the user
|
782
|
+
# has declared... not just argv.
|
783
|
+
self.extend NewInterface
|
784
|
+
self.flag_value = argv.flag_value
|
785
|
+
self.errors = argv.errors
|
786
|
+
argv
|
787
|
+
end # end of method handle_errors_and_help
|
788
|
+
alias :and_process! :handle_errors_and_help
|
789
|
+
end # end of Flagset
|
790
|
+
end # end of OptiFlag
|
791
|
+
|
792
|
+
module OptiFlag
|
793
|
+
# testing to see if this shows (2)
|
794
|
+
module Flagset
|
795
|
+
attr_accessor :help_bundle;
|
796
|
+
|
797
|
+
private
|
798
|
+
def render_help(stdo=$stdout)
|
799
|
+
@help_bundle.banner.call stdo
|
800
|
+
@all_flags.each_pair do |name_of_flag,flag|
|
801
|
+
@help_bundle.help.call stdo, flag
|
802
|
+
end
|
803
|
+
end
|
804
|
+
def show_help(start_message="",stdo=$stdout)
|
805
|
+
stdo.puts start_message
|
806
|
+
render_help(stdo)
|
807
|
+
@all_keywords ||= []
|
808
|
+
end
|
809
|
+
def show_extended_help(start_message="",stdo=$stdout)
|
810
|
+
@all_flags.keys.each do |name|
|
811
|
+
show_individual_extended_help(name,stdo)
|
812
|
+
end
|
813
|
+
end
|
814
|
+
def show_individual_extended_help(name,stdo=$stdout)
|
815
|
+
the_flag = @all_flags[name]
|
816
|
+
return if !the_flag
|
817
|
+
extended_help = @help_bundle.extended_help
|
818
|
+
extended_help.call stdo, the_flag
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
|
824
|
+
|
825
|
+
# Specification error possibilities (at FlagsetDefinition)
|
826
|
+
# 1) a value_matches and a value_in_set on the same argument
|
827
|
+
# 2) ambiguous flag names (e.g. two flags both with name -help)
|
828
|
+
# 3) short symbol flag and long symbol flags match each other
|
829
|
+
# Specification error possibilities (at DefinitionSwitcher)
|
830
|
+
# 1)
|
831
|
+
# 2)
|
832
|
+
# Warning conditions
|
833
|
+
# 1) Left-over arguments
|
834
|
+
|
835
|
+
|
836
|
+
# OptiFlag is the module that provides namespacing for the entire
|
837
|
+
# optiflag functionality. For usage and examples, see
|
838
|
+
# http://optiflag.rubyforge.org
|
839
|
+
#
|
840
|
+
# = Terminology
|
841
|
+
# Please treat the following terminology as specific only
|
842
|
+
# to the OptiFlag code suite. In the remaining RDoc, we shall
|
843
|
+
# try to emphasize this consistent terminology with italics.
|
844
|
+
# If you see an italicized phrase, chances are that it
|
845
|
+
# is defined here.
|
846
|
+
#
|
847
|
+
# == Flag Set Declaration
|
848
|
+
# A <i>flag set declaration</i> is a set of flag declarations
|
849
|
+
# created by the user of the OptiFlag suite and corresponds
|
850
|
+
# to the following code snippet:
|
851
|
+
# module AppArgs extend OptiFlagSet
|
852
|
+
# # individual flag declaration goes here ...
|
853
|
+
# # ... and here
|
854
|
+
# end
|
855
|
+
# In this case, the module *AppArgs* is a <i>flag set declaration</i>,
|
856
|
+
# and all code within the module definition (i.e. up to the end of
|
857
|
+
# *end* of the module) is either a <i>flag declaration</i> or a
|
858
|
+
# special command.
|
859
|
+
#
|
860
|
+
# Another way to treat this declaration is as a demarcation
|
861
|
+
# between the normal Ruby world and the mini-DSL (Domain Specific
|
862
|
+
# Language) that OptiFlag offers. In this view,
|
863
|
+
# the declaration provides a DSL-zone in which the DSL
|
864
|
+
# is allowed.
|
865
|
+
# module AppArgs extend OptiFlagSet
|
866
|
+
# # DSL-zone
|
867
|
+
# # DSL-zone (for declaring and modifying flags)
|
868
|
+
# # DSL-zone
|
869
|
+
# end
|
870
|
+
# the first line
|
871
|
+
# module AppArgs extend OptiFlagSet
|
872
|
+
# is really just rote.
|
873
|
+
#
|
874
|
+
# Supply your own module
|
875
|
+
# argument name and make sure it extends this
|
876
|
+
# OptiFlag::Flagset as is written.
|
877
|
+
# You will then have a scoped space to write
|
878
|
+
# in a command line DSL.
|
879
|
+
#
|
880
|
+
# == Flag Declaration
|
881
|
+
# A <i>flag declaration</i> is placed within a <i>flag set declaration</i>
|
882
|
+
# to indicate that one input parameter per declaration is requested
|
883
|
+
# from the command line. A <i>flag declaration</i> is the mini-DSL's main
|
884
|
+
# programming construct. In the following code, four <i>flag declarations</i>
|
885
|
+
# are placed within the overall <i>flag *set* declaration</i> named AppArgs:
|
886
|
+
# module AppArgs extend OptiFlagSet
|
887
|
+
# flag "dir"
|
888
|
+
# flag "log"
|
889
|
+
# flag "username"
|
890
|
+
# flag "password"
|
891
|
+
# end
|
892
|
+
# Please note that there are other <i>flag set declaration</i> nouns
|
893
|
+
# other than flag. For instance in the following snippet:
|
894
|
+
# module Example extend OptiFlagSet
|
895
|
+
# flag "dir" do
|
896
|
+
# alternate_forms "directory","D","d"
|
897
|
+
# description "The Appliction Directory"
|
898
|
+
# end
|
899
|
+
# optional_flag "log" do
|
900
|
+
# description "The directory in which to find the log files"
|
901
|
+
# long_form "logging-directory" # long form is keyed after the '--' symbol
|
902
|
+
# end
|
903
|
+
# flag "username", :description => "Database username." # alternate form
|
904
|
+
# flag "password" do
|
905
|
+
# description "Database password."
|
906
|
+
# end
|
907
|
+
# usage_flag "h","help","?"
|
908
|
+
# extended_help_flag "superhelp"
|
909
|
+
#
|
910
|
+
# and_process!
|
911
|
+
# end
|
912
|
+
# there are six <i>flag declarations</i> in total:
|
913
|
+
# * a flag named "dir"
|
914
|
+
# * an optional flag named "log"
|
915
|
+
# * a flag named "username"
|
916
|
+
# * a flag named "password"
|
917
|
+
# * a usage flag for summoning help on how to use the flags
|
918
|
+
# * an extended help flag for summoning detailed usage for the flags
|
919
|
+
# Everything else is either a <i>clause level modifier</i> (e.g.
|
920
|
+
# alternate_forms, description, etc.) or a <i>special command</i>.
|
921
|
+
#
|
922
|
+
# <b>For a list of all <i>flag set declarations</i> and how to
|
923
|
+
# use them, see the RDoc for the OptiFlag::Flagset module.</b>
|
924
|
+
#
|
925
|
+
# == Clause Level Modifier
|
926
|
+
# As seen above, a <i>clause level modifier</i> is a word
|
927
|
+
# used to modify the basic flag, usually within a nested do
|
928
|
+
# block. It it this nesting which has inspired the use
|
929
|
+
# of the word clause. For instance:
|
930
|
+
# module Example extend OptiFlagSet
|
931
|
+
# flag "dir" do
|
932
|
+
# alternate_forms "directory","D","d"
|
933
|
+
# description "The Appliction Directory"
|
934
|
+
# end
|
935
|
+
# end
|
936
|
+
# We could read this as a sentence:
|
937
|
+
# 'Create a flag "dir" which has three alternate forms "directory", "D", and "d"
|
938
|
+
# and which has a description that reads "The Application Directory'.
|
939
|
+
#
|
940
|
+
# For the most part, these <i>clause level modifiers</i> are nested
|
941
|
+
# within a do-block, though OptiFlag allows us to conserve
|
942
|
+
# vertical space by using symbol hashes. (It is recommended
|
943
|
+
# that one only uses these in simple cases). For instance,
|
944
|
+
# the following two <i>flag set declarations</i> are
|
945
|
+
# equivalent:
|
946
|
+
# module Example extend OptiFlagSet
|
947
|
+
# flag "username", :description => "Database username." # alternate form
|
948
|
+
#
|
949
|
+
# and_process!
|
950
|
+
# end
|
951
|
+
# and
|
952
|
+
# module Example extend OptiFlagSet
|
953
|
+
# flag "username" do
|
954
|
+
# description "Database username."
|
955
|
+
# end
|
956
|
+
#
|
957
|
+
# and_process!
|
958
|
+
# end
|
959
|
+
# with the first being a syntactically friendly
|
960
|
+
# hash of the <i>clause level modifier</i> as a
|
961
|
+
# symbol pointing to the value of the modification.
|
962
|
+
#
|
963
|
+
# For a complete list of <i>clause level modifiers</i>
|
964
|
+
# see the RDoc for OptiFlag::Flagset::EachFlag
|
965
|
+
module OptiFlag
|
966
|
+
|
967
|
+
end
|
968
|
+
|
969
|
+
OptiFlagSet = OptiFlag::Flagset
|
970
|
+
def OptiFlagSet(hash)
|
971
|
+
OptiFlag::Flagset(hash)
|
972
|
+
end
|