=begin
= class NumRu::Misc::KeywordOpt
== Overview
A class to facilitate optional keyword arguments. More specifically,
it helps the use of a Hash to mimic the keyword argument system.
== Usage example
Suppose that you introduce keyword arguments "flag" and "number"
to the method "hoge" in a class/module Foo. It can be done as
follows:
require 'numru/misc/keywordopt'
include NumRu
class Foo
@@opt_hoge = KeywordOpt.new(
['flag', false, 'whether or not ...'],
['number', 1, 'number of ...'],
['help', false, 'show help message']
)
def hoge(regular_arg1, regular_arg2, options=nil)
opt = @@opt_hoge.interpret(options)
if opt['help']
puts @@opt_hoge.help
puts ' Current values='+opt.inspect
raise HelpMessagingException, '** show help message and raise **'
end
# do what you want below
# (options are set in the Hash opt: opt['flag'] and opt['number'])
end
end
Here, the options are defined in the class variable @@opt_hoge
with option names, defualt values, and descriptions (for help
messaging). One can use the method hoge as follows:
foo = Foo.new
...
x = ...
y = ...
...
foo.hoge( x, y, {'flag'=>true, 'number'=>10} )
Or equivalently,
foo.hoge( x, y, 'flag'=>true, 'number'=>10 )
because '{}' can be omitted here. If you want to show the help message,
use
foo.hoge( x, y, 'help'=>true )
Tails of options names can be shortened as long as unambiguous:
foo.hoge( x, y, 'fla'=>true, 'num'=>10 )
This will cause an exception raised with the following help message such as:
\** Description of options **
option name => default value (description), ..:
{ "flag" => false (whether or not ...),
"number" => 1 (number of ...),
"help" => false (show help message)}
Current values={"help"=>true, "number"=>1, "flag"=>false}
NumRu::Misc::HelpMessagingException: ** show help message and raise **
from (irb):78:in `hoge'
from (irb):83
== Class methods
---KeywordOpt.new( *args )
Constructor.
ARGUMENTS
* args : arrays of two or three elements: [option name, defualt value,
description ], or [option name, defualt value] if you don't want to
write descriptions. Option names and descriptions must be String.
RETURN VALUE
* a KeywordOpt object
== Methods
---interpret(hash)
Interprets a hash that specifies option values.
ARGUMENTS
* hash (Hash) : a hash with string keys matching option names (initialized
when constructed). The matching is case sensitive and done such
that the tail of a option name can be omitted as long as
unambiguous (for example, 'num' for 'number').
RETURN VALUE
* a Hash containing the option values (default values overwritten
with hash).
POSSIBLE EXCEPTION
* hash has a key that does not match any of the option names.
* hash has a key that is ambigous
---help
Returns a help message
RETURN VALUE
* a String describing the option names, defualt values, and descriptions
=end
module NumRu
class HelpMessagingException < StandardError
end
class KeywordOpt
def initialize(*args)
# USAGE:
# KeywordOpt.new([key,val,description],[key,val,description],..)
# where key is a String, and description can be omitted.
@val=Hash.new
@description=Hash.new
@keys = []
args.each{ |x|
@keys.push(x[0])
@val[x[0]]=x[1]
@description[x[0]]= ( (x.length>=3) ? x[2] : '' )
}
@keys_sort = @keys.sort
end
def interpret(hash)
return @val if !hash
##
len = @val.length
im = 0
out = @val.dup
hash.keys.sort.each do |key|
rkey = /^#{key}/
loop do
if rkey =~ @keys_sort[im]
if im<len-1 && rkey=~@keys_sort[im+1]
raise "Ambiguous key specification '#{key}'."
end
out[@keys_sort[im]]=hash[key]
break
end
im += 1
raise "'#{key}' does not match any of the keys." if im==len
end
end
out
end
def help
"** Description of options **\n" +
" option name => default value (description), ..:\n{" +
@keys.collect{|k| " #{k.inspect} => #{@val[k].inspect} (#{@description[k]})"}.join(",\n") +
'}'
end
end
module DCL_Ext
module_function
#< def sgset sgstx udset udstx etc. >
# USAGE EAXPLE: usset('lxinv'=>true, 'xfac'=>10, 'cxttl'=>'longitude')
%w!gl sl sg sw uc ud ue ug ul um us uu uz!.each do |pkg|
%w!set stx!.each do |set|
eval <<-EOS
def #{pkg}#{set}( hash )
hash.each{|k,v|
DCL.#{pkg}p#{set}(k,v)
}
end
EOS
end
end
# < contour/tone level handling >
@@opt_levels = KeywordOpt.new(
['levels',nil, 'levels'],
['mjmn', nil, 'whether major or minor ex.[false,true,false,...]'],
['cmin', nil, 'minimum level'],
['cmax', nil, 'maximum level'],
['cint', nil, 'interval'],
['nlev', 10, 'number of levels'],
['help', nil, 'show help message']
)
def ud_set_levels(z,options=nil)
# < interpret options >
opt = @@opt_levels.interpret(options)
if opt['help']
puts @@opt_levels.help
puts ' Current values='+opt.inspect
return
end
if levels=opt['levels']
icycle = DCL.udiget('icycle')
indxmj = DCL.udiget('indxmj')
indxmn = DCL.udiget('indxmn')
idash = DCL.udiget('idash')
ldash = DCL.udlget('ldash')
label = DCL.udlget('label')
isolid = DCL.udiget('isolid')
rsizel = DCL.udrget('rsizel')
nlev=levels.length
if (mjmn=opt['mjmn'])
if mjmn.length != levels.length
raise ArgumentError,"lengths of levels and mjmn do not agree"
end
else
if levels.include?(0)
idx = levels.index(0)
ioffset = icycle*idx - idx
else
ioffset = 1
end
mjmn = (0...nlev).collect{|x| ((x+ioffset)%icycle)==0}
end
indices = mjmn.collect{|x| (x ? indxmj : indxmn)}
DCL.udiclv
(0...nlev).each{ |i|
lev = levels[i]
clev = DCL.udlabl(lev)
ityp = ( ldash && lev<0 ) ? idash : isolid
ht = ( mjmn[i] && label ) ? rsizel : 0.0
DCL.udsclv(lev,indices[i],ityp,clev,ht)
}
elsif opt['cmin'] || opt['cmax'] || opt['cint'] || opt['nlev']
cmin=opt['cmin']
cmax=opt['cmax']
cint=opt['cint']
nlev=opt['nlev']
dx = ( cint || -nlev )
if cmin || cmax
# if one or two of [cmin,cmax] is/are defined:
cmin = z.min if !cmin
cmax = z.max if !cmax
DCL.udgcla(cmin,cmax,dx)
else
DCL.udgclb(z,dx)
end
else
levels = nil
end
end
end
end
#################################################
if $0 == __FILE__
require "narray"
require "numru/dcl"
include NumRu
include Math
nx = 19
ny = 19
xmin = 0
xmax = 360
ymin = -90
ymax = 90
drad = PI/180
dz = 0.05
p = NArray.sfloat(nx, ny)
#-- data ---
for j in 0..ny-1
for i in 0..nx-1
alon = (xmin + (xmax-xmin)*i/(nx-1)) * drad
alat = (ymin + (ymax-ymin)*j/(ny-1)) * drad
slat = sin(alat)
p[i,j] = cos(alon) * (1-slat**2) * sin(2*PI*slat) + dz
end
end
#-- graph ---
iws = (ARGV[0] || (puts ' WORKSTATION ID (I) ? ;'; DCL::sgpwsn; gets)).to_i
DCL::gropn iws
DCL::sldiv('y',2,1)
DCL::grfrm
DCL::grswnd(xmin, xmax, ymin, ymax)
DCL::grsvpt(0.2, 0.8, 0.2, 0.8)
DCL::grstrn(1)
DCL::grstrf
DCL::usdaxs
DCL_Ext.udset('icycle'=>3,'idash'=>4)
DCL_Ext.ud_set_levels(p, 'nlev'=>8, 'help'=>true)
DCL_Ext.ud_set_levels(p,{'nlev'=>8, 'cmin'=>-0.2})
DCL::udcntr(p)
DCL::grfrm
DCL::grswnd(xmin, xmax, ymin, ymax)
DCL::grsvpt(0.2, 0.8, 0.2, 0.8)
DCL::grstrn(1)
DCL::grstrf
DCL::usdaxs
DCL_Ext.ud_set_levels(p,{'lev'=>[-0.3,-0.1,0,0.1,0.3]})
DCL::udcntr(p)
DCL::grcls
end
syntax highlighted by Code2HTML, v. 0.9.1