numru-misc 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ <?xml version="1.0" ?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml">
6
+ <head>
7
+ <title>lib/numru/misc/misc.rb</title>
8
+ </head>
9
+ <body>
10
+ <h1><a name="label:0" id="label:0">module NumRu::Misc</a></h1><!-- RDLabel: "module NumRu::Misc" -->
11
+ <h2><a name="label:1" id="label:1">Overview</a></h2><!-- RDLabel: "Overview" -->
12
+ <p>Miscellaneous functions and classes to facilitate programming.</p>
13
+ <h2><a name="label:2" id="label:2">Index</a></h2><!-- RDLabel: "Index" -->
14
+ <p>CLASSES</p>
15
+ <ul>
16
+ <li><a href="keywordopt.html">class KeywordOpt</a>
17
+ to support keyward arguments with default values.</li>
18
+ <li><a href="narray_ext.html">class NArray (enhancement of NArray made by M Tanaka)</a></li>
19
+ </ul>
20
+ <p>MODULES</p>
21
+ <ul>
22
+ <li><a href="md_iterators.html">module MD_Iterators</a> A Mixin for classes with
23
+ multi-dimension indexing support (such as NArray).</li>
24
+ <li><a href="emath.html">module EMath</a>
25
+ To be included instead of the Math predefined module (or NMath in NArray).
26
+ Unlike Math and NMath, EMath handles unknown classes by calling its
27
+ native instance method (assuming the same name).</li>
28
+ </ul>
29
+ <p>MODULE FUNCTIONS</p>
30
+ <ul>
31
+ <li><a href="#label:4">check_shape_consistency</a></li>
32
+ </ul>
33
+ <h2><a name="label:3" id="label:3">Module functions</a></h2><!-- RDLabel: "Module functions" -->
34
+ <dl>
35
+ <dt><a name="label:4" id="label:4"><code>check_shape_consistency(<var>cshapes</var>, *<var>args</var>)</code></a></dt><!-- RDLabel: "check_shape_consistency" -->
36
+ <dd>
37
+ <p>Check the consistency of array shapes (multi-dim such as NArray).
38
+ Exception is raised if inconsistent.</p>
39
+ <p>ARGUMENTS</p>
40
+ <ul>
41
+ <li>cshapes (String) : description of the shapes of the args.
42
+ Delimited by one-or-more spaces between arrays,
43
+ and the shape of each array is delimited by a comma. The lengths are
44
+ expressed with string names as identifiers (in that case, length
45
+ values are unquestioned) or specified as positive integers.
46
+ Use '..' or '...' for repetition of the last shape.
47
+ See EXAMPLES below.</li>
48
+ <li>args (multi-dim arrays such as NArray): arrays to be checked</li>
49
+ </ul>
50
+ <p>RETURN VALUE</p>
51
+ <ul>
52
+ <li>nil</li>
53
+ </ul>
54
+ <p>POSSIBLE EXCEPTIONS</p>
55
+ <ul>
56
+ <li>exception is raised if cshapes and args are inconsistent:
57
+ <ul>
58
+ <li>RuntimeError, if the arrays do not have shapes specified by cshapes.</li>
59
+ <li>ArgeumentError, if the number of args are inconsistent with cshapes.
60
+ This is likely a coding error of the user.</li>
61
+ </ul></li>
62
+ </ul>
63
+ <p>EXAMPLES</p>
64
+ <ul>
65
+ <li><p>to check whether three arrays u, v, and w are shaped as
66
+ u[nx], v[ny], and w[nx,ny], where nx and ny are any integer:</p>
67
+ <pre>NumRu::Misc.check_shape_consistency('nx ny nx,ny',u,v,w)</pre>
68
+ <p>Or equivalently,</p>
69
+ <pre>NumRu::Misc.check_shape_consistency('m n m,n',u,v,w)</pre>
70
+ <p>because actual strings does not matter.</p></li>
71
+ <li><p>To specify fixed lengths, use integers instead of names:</p>
72
+ <pre>NumRu::Misc.check_shape_consistency('4 n 4,n',u,v,w)</pre>
73
+ <p>In this case, u,v,w must have shapes [4], [ny], and [4,ny],
74
+ where ny is any length.</p></li>
75
+ <li><p>Use '..' or '...' to repeat the same shape:</p>
76
+ <pre>NumRu::Misc.check_shape_consistency('nx,ny ...',u,v,w)</pre>
77
+ <p>This ensures that u, v, and w are 2D arrays with the same shape.
78
+ Note: '..' and '...' are the same, so you can use whichever you like.</p></li>
79
+ </ul></dd>
80
+ </dl>
81
+
82
+ </body>
83
+ </html>
@@ -0,0 +1,104 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ include Config
4
+
5
+ if CONFIG["MINOR"].to_i > 6 then $rb_18 = true else $rb_18 = false end
6
+ if $rb_18
7
+ require 'fileutils'
8
+ else
9
+ require 'ftools'
10
+ end
11
+
12
+ =begin
13
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
14
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
15
+ # $archdir = File.join($libdir, CONFIG["arch"])
16
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
17
+ if !$site_libdir
18
+ $site_libdir = File.join($libdir, "site_ruby")
19
+ elsif Regexp.compile($site_libdir) !~ Regexp.quote($version)
20
+ $site_libdir = File.join($site_libdir, $version)
21
+ end
22
+
23
+ default_destdir = $site_libdir
24
+ =end
25
+
26
+ default_destdir = CONFIG["sitelibdir"]
27
+
28
+ def install_rb(srcdir, destdir)
29
+ libdir = "lib"
30
+ libdir = File.join(srcdir, libdir) if srcdir
31
+ path = []
32
+ dir = []
33
+ Find.find(libdir) do |f|
34
+ next unless FileTest.file?(f)
35
+ next if (f = f[libdir.length+1..-1]) == nil
36
+ next if (/CVS$/ =~ File.dirname(f))
37
+ path.push f
38
+ dir |= [File.dirname(f)]
39
+ end
40
+ for f in dir
41
+ next if f == "."
42
+ next if f == "CVS"
43
+ if $rb_18
44
+ FileUtils.makedirs(File.join(destdir, f))
45
+ else
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ end
49
+ for f in path
50
+ next if (/\~$/ =~ f)
51
+ next if (/^\./ =~ File.basename(f))
52
+ if $rb_18
53
+ FileUtils.install(File.join("lib", f), File.join(destdir, f), {:mode => 0644, :verbose => true})
54
+ else
55
+ File::install(File.join("lib", f), File.join(destdir, f), 0644, true)
56
+ end
57
+ end
58
+ end
59
+
60
+ def ARGV.switch
61
+ return nil if self.empty?
62
+ arg = self.shift
63
+ return nil if arg == '--'
64
+ if arg =~ /^-(.)(.*)/
65
+ return arg if $1 == '-'
66
+ raise 'unknown switch "-"' if $2.index('-')
67
+ self.unshift "-#{$2}" if $2.size > 0
68
+ "-#{$1}"
69
+ else
70
+ self.unshift arg
71
+ nil
72
+ end
73
+ end
74
+
75
+ def ARGV.req_arg
76
+ self.shift || raise('missing argument')
77
+ end
78
+
79
+ destdir = default_destdir
80
+
81
+ begin
82
+ while switch = ARGV.switch
83
+ case switch
84
+ when '-d', '--destdir'
85
+ destdir = ARGV.req_arg
86
+ # when '-u', '--uninstall'
87
+ # uninstall = true
88
+ else
89
+ raise "unknown switch #{switch.dump}"
90
+ end
91
+ end
92
+ rescue
93
+ STDERR.puts $!.to_s
94
+ STDERR.puts File.basename($0) +
95
+ " -d <destdir>"
96
+ exit 1
97
+ end
98
+
99
+ #if( defined?(uninstall) && uninstall )
100
+ # uninstall_rb(nil, destdir)
101
+ #else
102
+ install_rb(nil, destdir)
103
+ #end
104
+
@@ -0,0 +1,4 @@
1
+ require 'numru/misc/misc'
2
+ require 'numru/misc/keywordopt'
3
+ require 'numru/misc/md_iterators'
4
+ require 'numru/misc/emath'
@@ -0,0 +1,75 @@
1
+ =begin
2
+ =module NumRu::Misc::EMath
3
+
4
+ To be included instead of the Math predefined module (or NMath in NArray).
5
+ Unlike Math and NMath, EMath handles unknown classes by calling its
6
+ native instance method (assuming the same name).
7
+
8
+ Therefore, if included, its function (module method) is used as:
9
+
10
+ cos( obj )
11
+
12
+ and so on. If obj is not of a supported class, EMath calls, obj.cos in
13
+ this case. (If cos is not a method of obj, then an exception is
14
+ raised.) Supported classes are Numeric (by Math) and NArray (by
15
+ NMath). EMath stands for "good Math" (for obvious reason for a
16
+ Japanese).
17
+
18
+ Note: as for atan2(a,b), a.atan2(b) will be called if a or b
19
+ is not supported. This is the case for all functions that take
20
+ two or more arguments.
21
+
22
+ =end
23
+
24
+ require "narray"
25
+
26
+ module NumRu
27
+ module Misc
28
+ module EMath
29
+
30
+ E = Math::E
31
+ PI = Math::PI
32
+
33
+ funcs = ["acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh",
34
+ "cos", "cosh", "erf", "erfc", "exp", "frexp", "hypot",
35
+ "ldexp", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"]
36
+ # FUNCS: from ruby 1.8.0, ( Math.methods - Object.methods ).sort
37
+
38
+ module_function
39
+ funcs.each{|func|
40
+ eval <<-EOS,nil,__FILE__,__LINE__+1
41
+ def #{func}(*arg)
42
+ case arg[0]
43
+ when Numeric
44
+ Math.#{func}(*arg)
45
+ when NArray
46
+ NMath.#{func}(*arg)
47
+ else
48
+ obj = arg.shift
49
+ begin
50
+ obj.#{func}(*arg)
51
+ rescue NameError
52
+ raise TypeError,"cannot handle \#{obj.class}: \#{obj.inspect}"
53
+ end
54
+ end
55
+ end
56
+ EOS
57
+ }
58
+ end
59
+ end
60
+ end
61
+
62
+ if __FILE__ == $0
63
+ include NumRu::Misc::EMath
64
+ p cos( PI )
65
+ p cos( Complex(0, 1) )
66
+ p cos( NArray[0,PI/3,PI/2] )
67
+ begin
68
+ p cos( "ggg" )
69
+ rescue
70
+ print "* error as expected >>: ",$!,"\n"
71
+ end
72
+ require 'narray_miss'
73
+ nam = NArrayMiss.to_nam( NArray[0,PI/3,PI/2] )
74
+ p cos(nam)
75
+ end
@@ -0,0 +1,498 @@
1
+ =begin
2
+ ==Index
3
+ * ((<class NumRu::Misc::KeywordOpt>))
4
+ * ((<class NumRu::Misc::KeywordOptAutoHelp < NumRu::Misc::KeywordOpt>))
5
+
6
+ = class NumRu::Misc::KeywordOpt
7
+
8
+ == Overview
9
+
10
+ A class to facilitate optional keyword arguments. More specifically,
11
+ it helps the use of a Hash to mimic the keyword argument system.
12
+ With this, you can set default values and description to each
13
+ keyword argument.
14
+
15
+ == Classes defined supplementarilly
16
+
17
+ === class NumRu::Misc::HelpMessagingException < StandardError
18
+
19
+ This is for your convenience. See the usage example below.
20
+
21
+ == Usage example
22
+
23
+ Suppose that you introduce keyword arguments "flag" and "number"
24
+ to the method "hoge" in a class/module Foo. It can be done as
25
+ follows:
26
+
27
+ require 'numru/misc' # or, specifically, require 'numru/misc/keywordopt'
28
+ include NumRu
29
+
30
+ class Foo
31
+ @@opt_hoge = Misc::KeywordOpt.new(
32
+ ['flag', false, 'whether or not ...'],
33
+ ['number', 1, 'number of ...'],
34
+ ['help', false, 'show help message']
35
+ )
36
+ def hoge(regular_arg1, regular_arg2, options=nil)
37
+ opt = @@opt_hoge.interpret(options)
38
+ if opt['help']
39
+ puts @@opt_hoge.help
40
+ puts ' Current values='+opt.inspect
41
+ raise Misc::HelpMessagingException, '** show help message and raise **'
42
+ end
43
+ # do what you want below
44
+ # (options are set in the Hash opt: opt['flag'] and opt['number'])
45
+ end
46
+ end
47
+
48
+ Here, the options are defined in the class variable @@opt_hoge
49
+ with option names, default values, and descriptions (for help
50
+ messaging). One can use the method hoge as follows:
51
+
52
+ foo = Foo.new
53
+ ...
54
+ x = ...
55
+ y = ...
56
+ ...
57
+ foo.hoge( x, y, {'flag'=>true, 'number'=>10} )
58
+
59
+ Or equivalently,
60
+
61
+ foo.hoge( x, y, 'flag'=>true, 'number'=>10 )
62
+
63
+ because '{}' can be omitted here.
64
+
65
+ Tails of options names can be shortened as long as unambiguous:
66
+
67
+ foo.hoge( x, y, 'fla'=>true, 'num'=>10 )
68
+
69
+
70
+ To show the help message, call
71
+
72
+ foo.hoge( x, y, 'help'=>true )
73
+
74
+ This will cause the following help message printed with the
75
+ exception HelpMessagingException raised.
76
+
77
+ << Description of options >>
78
+ option name => default value description:
79
+ "flag" => false whether or not ...
80
+ "number" => 1 number of ...
81
+ "help" => false show help message
82
+ Current values={"help"=>true, "number"=>1, "flag"=>false}
83
+ NumRu::Misc::HelpMessagingException: ** help messaging done **
84
+ from (irb):78:in "hoge"
85
+ from (irb):83
86
+
87
+ Do not affraid to write long descriptions. The help method
88
+ breaks lines nicely if they are long.
89
+
90
+ == Class methods
91
+
92
+ ---KeywordOpt.new( *args )
93
+
94
+ Constructor.
95
+
96
+ ARGUMENTS
97
+ * args : (case 1) arrays of two or three elements: [option name,
98
+ default value, description ], or [option name, default value]
99
+ if you do not want to write descriptions. Option names and
100
+ descriptions must be String. (case 2) another KeywordOpt.
101
+ Cases 1 and 2 can be mixed.
102
+
103
+ When case 2, a link to the other KeywordOpt is kept. Thus, change
104
+ of values in it is reflected to the current one. However,
105
+ the link is deleted if values are changed by ((<set>)).
106
+
107
+ RETURN VALUE
108
+ * a KeywordOpt object
109
+
110
+ EXAMPLE
111
+ * case 1
112
+ opt = Misc::KeywordOpt.new(
113
+ ['flag', false, 'whether or not ...'],
114
+ ['help', false, 'show help message']
115
+ )
116
+ * case 2
117
+ opt = Misc::KeywordOpt.new( optA, optB )
118
+ * case 1 & 2
119
+ opt = Misc::KeywordOpt.new(
120
+ ['flag', false, 'whether or not ...'],
121
+ optA
122
+ )
123
+
124
+ == Methods
125
+ ---interpret(hash)
126
+
127
+ Interprets a hash that specifies option values.
128
+
129
+ ARGUMENTS
130
+ * hash (Hash or nil) : a hash with string keys matching option names
131
+ (initializedwhen constructed). The matching is case sensitive and done
132
+ such that the tail of a option name can be omitted as long as
133
+ unambiguous (for example, 'num' for 'number').
134
+ If the argument is nil, the current values are returned.
135
+ If there are two options like 'max' and 'maxval', to use
136
+ a key 'max' (identical to the former paramer) is allowed, although
137
+ it matches 'maxval' as well. (Again 'ma' is regarded ambiguous.)
138
+
139
+ RETURN VALUE
140
+ * a Hash containing the option values (default values overwritten
141
+ with hash).
142
+
143
+ POSSIBLE EXCEPTION
144
+ * hash has a key that does not match any of the option names.
145
+ * hash has a key that is ambiguous
146
+
147
+ ---set(hash)
148
+
149
+ Similar to ((<interpret>)) but changes internal values.
150
+
151
+ ARGUMENTS
152
+ * hash (Hash) : see ((<interpret>)). (Here, nil is not permitted though)
153
+
154
+ RETURN VALUE
155
+ * a Hash containing the values replaced (the ones before calling this
156
+ method)
157
+
158
+ POSSIBLE EXCEPTION
159
+ * the argument is not a Hash
160
+ * others are same as in ((<interpret>))
161
+
162
+ ---help
163
+
164
+ Returns a help message
165
+
166
+ RETURN VALUE
167
+ * a String describing the option names, default values, and descriptions
168
+
169
+ ---[](key)
170
+
171
+ Returns a value associated with the key (exact matching unlike interpret)
172
+
173
+ ---keys
174
+
175
+ Retunrs the keys.
176
+
177
+ ---select_existent(hash_or_keys)
178
+
179
+ Copies hash_or_keys, exclude ones that are not included in the option
180
+ (by comparing keys), and returns it. I.e. select only the ones
181
+ exsitent.
182
+
183
+ NOTE: ambiguity is not checked, so the resultant value is not
184
+ necessarily accepted by ((<interpret>)).
185
+
186
+ ARGUMENTS
187
+ * hash_or_keys (Hash or Array)
188
+
189
+ RETURN VALUE
190
+ * a Hash or Array depending on the class of the argument hash_or_keys
191
+
192
+ = class NumRu::Misc::KeywordOptAutoHelp < NumRu::Misc::KeywordOpt
193
+
194
+ Same as ((<class NumRu::Misc::KeywordOpt>)), but the method ((<interpret>))
195
+ shows a help message and raise an exception if option 'help' is provided
196
+ as an argument and is not nil or false
197
+ ((({NumRu::Misc::HelpMessagingException < StandardError})))
198
+ or if the arguments cannot be interpreted correctly ((({ArgumentError}))).
199
+ Option 'help' is automatically defined, so you do not have to define it
200
+ yourself.
201
+
202
+ =end
203
+
204
+ module NumRu
205
+
206
+ module Misc
207
+ class HelpMessagingException < StandardError
208
+ end
209
+
210
+ class KeywordOpt
211
+ def initialize(*args)
212
+ # USAGE:
213
+ # KeywordOpt.new([key,val,description],[key,val,description],..)
214
+ # where key is a String, and description can be omitted.
215
+ @val=Hash.new
216
+ @description=Hash.new
217
+ @keys = []
218
+ args.each{ |x|
219
+ case x
220
+ when Array
221
+ unless (x[0]=='help') && @keys.include?(x[0])
222
+ #^only 'help' can overwrap in the arguments
223
+ @keys.push(x[0])
224
+ @val[x[0]] = x[1]
225
+ @description[x[0]] = ( (x.length>=3) ? x[2] : '' )
226
+ end
227
+ when KeywordOpt
228
+ x.keys.each{|k|
229
+ unless k=='help' && @keys.include?(k)
230
+ #^only 'help' can overwrap in the arguments
231
+ @keys.push(k)
232
+ @val[k] = x #.val[k]
233
+ @description[k] = x.description[k]
234
+ end
235
+ }
236
+ def @val.[](k)
237
+ val = super(k)
238
+ val.is_a?(KeywordOpt) ? val[k] : val
239
+ end
240
+ def @val.dup
241
+ out = Hash.new
242
+ each{|k,val| out[k] = (val.is_a?(KeywordOpt) ? val[k] : val)}
243
+ out
244
+ end
245
+ else
246
+ raise ArgumentError, "invalid argument: #{x.inspect}"
247
+ end
248
+ }
249
+ @keys_sort = @keys.sort
250
+ if @keys_sort.length != @keys_sort.uniq.length
251
+ raise ArgumentError, "keys are not unique"
252
+ end
253
+ end
254
+
255
+ def interpret(hash)
256
+ return @val.dup if hash.nil?
257
+ ##
258
+ len = @val.length
259
+ im = 0
260
+ out = @val.dup
261
+ hash.keys.sort.each do |key|
262
+ rkey = /^#{key}/
263
+ loop do
264
+ if rkey =~ @keys_sort[im]
265
+ if im<len-1 && rkey=~@keys_sort[im+1] &&
266
+ key != @keys_sort[im] # not identical
267
+ raise ArgumentError, "Ambiguous key specification '#{key}'."
268
+ end
269
+ out[@keys_sort[im]]=hash[key]
270
+ break
271
+ end
272
+ im += 1
273
+ if im==len
274
+ raise ArgumentError, "'#{key}' does not match any of the keys."
275
+ end
276
+ end
277
+ end
278
+ out
279
+ end
280
+
281
+ def select_existent(hash_or_keys)
282
+ hash_or_keys = hash_or_keys.dup # not to alter the original
283
+ len = @val.length
284
+ im = 0
285
+ kys = ( Array === hash_or_keys ? hash_or_keys : hash_or_keys.keys )
286
+ kys.sort.each do |key|
287
+ rkey = /^#{key}/
288
+ loop do
289
+ break if rkey =~ @keys_sort[im]
290
+ im += 1
291
+ if im==len
292
+ hash_or_keys.delete(key)
293
+ im = 0 # rewind
294
+ break
295
+ end
296
+ end
297
+ end
298
+ hash_or_keys
299
+ end
300
+
301
+ def set(hash)
302
+ raise ArgumentError, "not a hash" if !hash.is_a?(Hash)
303
+ ##
304
+ replaced = Hash.new
305
+ len = @val.length
306
+ im = 0
307
+ hash.keys.sort.each do |key|
308
+ rkey = /^#{key}/
309
+ loop do
310
+ if rkey =~ @keys_sort[im]
311
+ if im<len-1 && rkey=~@keys_sort[im+1]
312
+ raise "Ambiguous key specification '#{key}'."
313
+ end
314
+ replaced[@keys_sort[im]] = @val[@keys_sort[im]]
315
+ @val[@keys_sort[im]]=hash[key]
316
+ break
317
+ end
318
+ im += 1
319
+ raise "'#{key}' does not match any of the keys." if im==len
320
+ end
321
+ end
322
+ replaced
323
+ end
324
+
325
+ # def __line_feed(str)
326
+ # if str.length >= 68
327
+ # idx = str[0..67].rindex(/\s/)
328
+ # if idx
329
+ # str[idx, 1] = "\n\t"
330
+ # end
331
+ # end
332
+ # str
333
+ # end
334
+ def __line_feed(str, len)
335
+ if str.length >= len
336
+ idx = str[0...len].rindex(/\s/)
337
+ if idx
338
+ str = str[0...idx] + "\n\t\t\t# " + __line_feed(str[(idx+1)..-1],50)
339
+ end
340
+ end
341
+ str
342
+ end
343
+ private :__line_feed
344
+
345
+ def help
346
+ " option name\tdefault value\t# description:\n" +
347
+ @keys.collect{|k|
348
+ __line_feed(" #{k.inspect}\t#{@val[k].inspect}\t# #{@description[k]}", 66)
349
+ }.join("\n")
350
+ end
351
+
352
+ def [](k)
353
+ v = @val[k]
354
+ if v.is_a?(KeywordOpt)
355
+ v = v.val[k]
356
+ end
357
+ v
358
+ end
359
+
360
+ def keys
361
+ @keys.dup
362
+ end
363
+
364
+ ##### protected methods #####
365
+ protected
366
+ attr_reader :val, :description
367
+ end
368
+
369
+ ##################################################
370
+
371
+ class KeywordOptAutoHelp < KeywordOpt
372
+ def initialize(*args)
373
+ args.push(['help', false, 'show help message if true'])
374
+ super(*args)
375
+ end
376
+
377
+ def interpret(hash)
378
+ begin
379
+ out = super(hash)
380
+ rescue
381
+ raise $!.inspect + "\n Available parameters are:\n" + help
382
+ end
383
+ if out['help']
384
+ puts "<< Description of options >>\n" + help
385
+ puts ' Current values=' + out.inspect
386
+ raise Misc::HelpMessagingException, '** help messaging done **'
387
+ end
388
+ out
389
+ end
390
+
391
+ def set(hash)
392
+ raise ArgumentError, "not a hash" if !hash.is_a?(Hash)
393
+ if hash['help']
394
+ puts "<< Description of options >>\n" + help
395
+ raise Misc::HelpMessagingException, '** help messaging done **'
396
+ end
397
+ super
398
+ end
399
+ end
400
+
401
+ end
402
+ end
403
+
404
+ if __FILE__ == $0
405
+ include NumRu
406
+
407
+ class Foo
408
+ @@opt_hoge = Misc::KeywordOpt.new(
409
+ ['flag', false, 'whether or not ...'],
410
+ ['number', 1, 'number of ...'],
411
+ ['fff', 1, 'fff...'],
412
+ ['help', false, 'show help message']
413
+ )
414
+ def self.change_default(hash)
415
+ @@opt_hoge.set(hash)
416
+ end
417
+ def hoge(regular_arg1, regular_arg2, options=nil)
418
+ opt = @@opt_hoge.interpret(options)
419
+ if opt['help']
420
+ puts "* Description of options:\n" + @@opt_hoge.help
421
+ puts ' Current values='+opt.inspect
422
+ raise Misc::HelpMessagingException, '** show help message and raise **'
423
+ end
424
+ # do what you want below
425
+ # (options are set in the Hash opt: opt['flag'] and opt['number'])
426
+ p opt
427
+ end
428
+ end
429
+
430
+ foo = Foo.new
431
+ x = 1
432
+ y = 1
433
+ print "### 0 ###\n"
434
+ foo.hoge( x, y, {'flag'=>true, 'number'=>10} )
435
+ foo.hoge( x, y )
436
+ print "### 1 ###\n"
437
+ foo.hoge( x, y, 'fla'=>true, 'num'=>10 )
438
+ print "### 2 ###\n"
439
+ begin
440
+ foo.hoge( x, y, 'help'=>true )
441
+ rescue
442
+ puts $!
443
+ end
444
+ print "### 3 ###\n"
445
+ Foo.change_default( {'number'=>3} )
446
+ begin
447
+ foo.hoge( x, y, 'fla'=>true, 'num'=>10, 'help'=>true)
448
+ rescue
449
+ puts $!
450
+ end
451
+ print "### 4 ###\n"
452
+ begin
453
+ foo.hoge( x, y, 'dummy'=>nil)
454
+ rescue
455
+ puts $!
456
+ end
457
+ print "### 5 ###\n"
458
+ begin
459
+ foo.hoge( x, y, 'f'=>nil)
460
+ rescue
461
+ puts $!
462
+ end
463
+
464
+ print "\n###### test of KeywordOptAutoHelp ######\n"
465
+ opt = Misc::KeywordOptAutoHelp.new(
466
+ ['flag', false, 'whether or not ...'],
467
+ ['number', 1, 'number of ...']
468
+ )
469
+ print "### 11 ###\n"
470
+ begin
471
+ opt.interpret('flag'=>10,'help'=>true)
472
+ rescue
473
+ puts $!
474
+ end
475
+ print "### 12 ###\n"
476
+ begin
477
+ opt.interpret('nnn'=>10)
478
+ rescue
479
+ puts $!
480
+ end
481
+
482
+ print "### 13 ###\n"
483
+ opt2 = Misc::KeywordOptAutoHelp.new(
484
+ ['flafla', false, 'whether or not ...']
485
+ )
486
+ opt3 = Misc::KeywordOptAutoHelp.new( opt, opt2 )
487
+ p opt3.interpret('flag'=>true)
488
+ begin
489
+ opt3.interpret('help'=>true)
490
+ rescue
491
+ puts $!
492
+ end
493
+
494
+ print "### 14 ###\n"
495
+ p opt2.keys, opt.keys
496
+ p opt.select_existent({"flag"=>99, "num"=>88, 'acb'=>333})
497
+ p opt.select_existent(["flag", "num", 'acb'])
498
+ end