Class: NumRu::Misc::KeywordOpt
- Inherits:
-
Object
- Object
- NumRu::Misc::KeywordOpt
- Defined in:
- lib/numru/misc/keywordopt.rb
Overview
Overview
A class to facilitate optional keyword arguments. More specifically, it helps the use of a Hash to mimic the keyword argument system. With this, you can set default values and description to each keyword argument.
Classes defined supplementarilly
class NumRu::Misc::HelpMessagingException < StandardError
This is for your convenience. See the usage example below.
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' # or, specifically, require 'numru/misc/keywordopt'
include NumRu
class Foo
@@opt_hoge = Misc::KeywordOpt.new(
['flag', false, 'whether or not ...'],
['number', 1, 'number of ...'],
['help', false, 'show help message']
)
def hoge(regular_arg1, regular_arg2, =nil)
opt = @@opt_hoge.interpret()
if opt['help']
puts @@opt_hoge.help
puts ' Current values='+opt.inspect
raise Misc::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, default 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.
Tails of options names can be shortened as long as unambiguous:
foo.hoge( x, y, 'fla'=>true, 'num'=>10 )
To show the help message, call
foo.hoge( x, y, 'help'=>true )
This will cause the following help message printed with the exception HelpMessagingException raised.
<< 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: ** help messaging done **
from (irb):78:in "hoge"
from (irb):83
Do not affraid to write long descriptions. The help method
breaks lines nicely if they are long.
Direct Known Subclasses
Instance Method Summary collapse
-
#[](k) ⇒ Object
Returns a value associated with the key (exact matching unlike interpret).
-
#help ⇒ Object
Returns a help message.
-
#initialize(*args) ⇒ KeywordOpt
constructor
Constructor.
-
#interpret(hash) ⇒ Object
POSSIBLE EXCEPTION * hash has a key that does not match any of the option names.
-
#keys ⇒ Object
Returns the keys.
-
#select_existent(hash_or_keys) ⇒ Object
Copies hash_or_keys, exclude ones that are not included in the option (by comparing keys), and returns it.
-
#set(hash) ⇒ Object
Similar to #interpret but changes internal values.
Constructor Details
#initialize(*args) ⇒ KeywordOpt
Constructor.
ARGUMENTS
* args : (case 1) arrays of two or three elements: [option name,
default value, description ], or [option name, default value]
if you do not want to write descriptions. Option names and
descriptions must be String. (case 2) another KeywordOpt.
Cases 1 and 2 can be mixed.
When case 2, a link to the other KeywordOpt is kept. Thus, change
of values in it is reflected to the current one. However,
the link is deleted if values are changed by <b>#set</b>.
RETURN VALUE
* a KeywordOpt object
EXAMPLE
* case 1
opt = Misc::KeywordOpt.new(
['flag', false, 'whether or not ...'],
['help', false, 'show help message']
)
* case 2
opt = Misc::KeywordOpt.new( optA, optB )
* case 1 & 2
opt = Misc::KeywordOpt.new(
['flag', false, 'whether or not ...'],
optA
)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/numru/misc/keywordopt.rb', line 122 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| case x when Array unless (x[0]=='help') && @keys.include?(x[0]) #^only 'help' can overwrap in the arguments @keys.push(x[0]) @val[x[0]] = x[1] @description[x[0]] = ( (x.length>=3) ? x[2] : '' ) end when KeywordOpt x.keys.each{|k| unless k=='help' && @keys.include?(k) #^only 'help' can overwrap in the arguments @keys.push(k) @val[k] = x #.val[k] @description[k] = x.description[k] end } def @val.[](k) val = super(k) val.is_a?(KeywordOpt) ? val[k] : val end def @val.dup out = Hash.new each{|k,val| out[k] = (val.is_a?(KeywordOpt) ? val[k] : val)} out end else raise ArgumentError, "invalid argument: #{x.inspect}" end } @keys_sort = @keys.sort if @keys_sort.length != @keys_sort.uniq.length raise ArgumentError, "keys are not unique" end end |
Instance Method Details
#[](k) ⇒ Object
Returns a value associated with the key (exact matching unlike interpret)
302 303 304 305 306 307 308 |
# File 'lib/numru/misc/keywordopt.rb', line 302 def [](k) v = @val[k] if v.is_a?(KeywordOpt) v = v.val[k] end v end |
#help ⇒ Object
Returns a help message
RETURN VALUE
* a String describing the option names, default values, and descriptions
294 295 296 297 298 299 |
# File 'lib/numru/misc/keywordopt.rb', line 294 def help " option name\tdefault value\t# description:\n" + @keys.collect{|k| __line_feed(" #{k.inspect}\t#{@val[k].inspect}\t# #{@description[k]}", 66) }.join("\n") end |
#interpret(hash) ⇒ Object
POSSIBLE EXCEPTION
* hash has a key that does not match any of the option names.
* hash has a key that is ambiguous
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/numru/misc/keywordopt.rb', line 185 def interpret(hash) return @val.dup if hash.nil? ## 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] && key != @keys_sort[im] # not identical raise ArgumentError, "Ambiguous key specification '#{key}'." end out[@keys_sort[im]]=hash[key] break end im += 1 if im==len raise ArgumentError, "'#{key}' does not match any of the keys." end end end out end |
#keys ⇒ Object
Returns the keys.
311 312 313 |
# File 'lib/numru/misc/keywordopt.rb', line 311 def keys @keys.dup end |
#select_existent(hash_or_keys) ⇒ Object
Copies hash_or_keys, exclude ones that are not included in the option
(by comparing keys), and returns it. I.e. select only the ones
exsitent.
NOTE: ambiguity is not checked, so the resultant value is not
necessarily accepted by <b>#interpret</b>.
ARGUMENTS
* hash_or_keys (Hash or Array)
RETURN VALUE
* a Hash or Array depending on the class of the argument hash_or_keys
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/numru/misc/keywordopt.rb', line 223 def select_existent(hash_or_keys) hash_or_keys = hash_or_keys.dup # not to alter the original len = @val.length im = 0 kys = ( Array === hash_or_keys ? hash_or_keys : hash_or_keys.keys ) kys.sort.each do |key| rkey = /^#{key}/ loop do break if rkey =~ @keys_sort[im] im += 1 if im==len hash_or_keys.delete(key) im = 0 # rewind break end end end hash_or_keys end |
#set(hash) ⇒ Object
Similar to #interpret but changes internal values.
ARGUMENTS
* hash (Hash) : see <b>#interpret</b>. (Here, nil is not permitted though)
RETURN VALUE
* a Hash containing the values replaced (the ones before calling this
method)
POSSIBLE EXCEPTION
* the argument is not a Hash
* others are same as in <b>#interpret</b>
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/numru/misc/keywordopt.rb', line 255 def set(hash) raise ArgumentError, "not a hash" if !hash.is_a?(Hash) ## replaced = Hash.new len = @val.length im = 0 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 replaced[@keys_sort[im]] = @val[@keys_sort[im]] @val[@keys_sort[im]]=hash[key] break end im += 1 raise "'#{key}' does not match any of the keys." if im==len end end replaced end |