class CTioga2::MetaBuilder::Type
A class that handles a parameter type. It has to be subclassed to actually provide a parameter. The subclasses must provide the following:
-
a
string_to_type
function to convert from string to the type; -
a
type_to_string
to convert back from type to string -
an instance
type_name
that returns a really small description of the type, to be used for instance to name command-line parameters. -
a
type_name
statement that registers the current class to theType
system.
Moerover, it is a good idea to reimplement the qt4_create_input_widget method; the default implementation works, but you probably wish it would look better.
Types
are implemented using hashes: this way, additionnal parameters can easily be added. The hash must have a :type key that will be interpreted by the children of Type
. Examples:
{ :type => :integer} { :type => :file, :filter => "Text Files (*.txt)}
And so on. You definitely should document your type and it's attributes properly, if you ever want that someone uses it.
The list of currently recognised types is here:
:integer
:float
:string
:file
:boolean
:list
Additionally to the parameters the given type is requiring, you can pass some other kind of information using this hash, such as option parser short argument, aliases, and so on. This has nothing to do with type conversion, but it is the best place where to put this kind of things, in my humble opinion. The currently recognized such additional parameters are:
-
:option_parser_short: a short option name for option_parser.
-
:namespace: a ruby module that will be searched by
string_to_type
for a constant. If one of the given name is found, its value is returned. -
:shortctus: a hash specifiying strings shortcuts for given values. Elements of this hash that are regular expressions are taken
Attributes
An array of module whose constants can be used “as such”
When a :namespace option is provided, this hash provides a lookup 'lowercase name' => constant value.
If the given string matches this regular expression, it is passed through without further modification.
A hash Regexp -> value. All elements will be looked for matches for every single string conversion, so don't dump too many of them here.
A hash shortcut -> value. Can be nil
The initial type specification that was given to the Type
Public Class Methods
Shortcut to convert directly a string to the given type specification. Handy shortcut.
# File lib/ctioga2/metabuilder/type.rb, line 176 def self.from_string(type, string) return get_type(type).string_to_type(string) end
This function converts a 'description' (see the Type
) of the type wanted into a Type
child. As a special treat, a lone symbol is converted into {:type => :symbol}
# File lib/ctioga2/metabuilder/type.rb, line 161 def self.get_param_type(type) if type.is_a?(Symbol) type = {:type => type} end raise InvalidType,"The type argument must be a Hash" unless type.is_a?(Hash) begin return @@types.fetch(type[:type]) rescue raise InvalidType, "Type #{type[:type]} unknown to the type system" end end
Returns a Type
child instance suitable for conversion of the given type specification
# File lib/ctioga2/metabuilder/type.rb, line 182 def self.get_type(type) if type.is_a? Type return type end return get_param_type(type).new(type) end
A default constructor. It should be safe to use it directly for children, unless something more specific is needed. Any descendent should always register type as @type - or, even better, call super.
# File lib/ctioga2/metabuilder/type.rb, line 118 def initialize(type) if type.is_a?(Symbol) type = {:type => type} end @type = type if @type[:shortcuts] @shortcuts = @type[:shortcuts] @re_shortcuts = {} for k,v in @shortcuts if k.is_a? Regexp @re_shortcuts[k] = v end end end if @type[:passthrough] @passthrough = @type[:passthrough] end end
This class function actually registers the current type to the Type
ancestor. name should be a symbol. Moreover, if the second argument is provided, it automatically creates a type_name
instance method returning this value.
# File lib/ctioga2/metabuilder/type.rb, line 143 def self.type_name(name, public_name = nil, default_value = nil) if @@types.has_key?(name) warn { "Redefining type #{name} " + "from #{@@types[name]} to #{self}" } end @@types[name] = self @@type_names[self] = name self.send(:define_method,:type_name) do public_name end self.send(:define_method,:default_value) do default_value end end
Public Instance Methods
Whether the type is a boolean. Booleans are special cased for their use in the command-line.
# File lib/ctioga2/metabuilder/type.rb, line 288 def boolean? return false end
Returns a default value for the given type. This is reimplemented systematically from children, with the Type::type_name
statement.
# File lib/ctioga2/metabuilder/type.rb, line 246 def default_value end
Returns a value to be fed to OptionParser#on as a 'long' option. It is separated from the rest to allow easy redefinition (in special cases). name is the name of the option.
# File lib/ctioga2/metabuilder/type.rb, line 280 def option_parser_long_option(name, param = nil) param ||= type_name param = param.gsub(/\s+/, '_') return "--#{name} #{param.upcase}" end
Creates an option for the OptionParser parser. The block is fed with the converted value. The default implementation should be fine for most classes, but this still leaves the room for reimplementation if necessary. The parameters are:
-
parser: the OptionParser;
-
name: the name of the option;
-
desc: it description,
-
block: the block used to set the data.
# File lib/ctioga2/metabuilder/type.rb, line 268 def option_parser_option(parser, name, desc, &block) args = [option_parser_long_option(name), desc] if @type.has_key?(:option_parser_short) args.unshift(@type[:option_parser_short]) end option_parser_raw(parser, *args, &block) end
This function converts the given string to the appropriate type. It is a wrapper around the string_to_type_internal
function that can take advantage of a few general features. It is recommanded to define a string_to_type_internal
function rather to redefine string_to_type
# File lib/ctioga2/metabuilder/type.rb, line 196 def string_to_type(string, tn = nil) begin # First, passthrough if @passthrough && @passthrough === string return stt_run_hook(string) end # First, shortcuts: if @shortcuts and @shortcuts.key? string return stt_run_hook(@shortcuts[string]) end if @re_shortcuts for k, v in @re_shortcuts if string =~ k return stt_run_hook(v) end end end # Then, constants lookup. if @type.key?(:namespace) begin return stt_run_hook(lookup_const(string)) rescue IncorrectInput end end return stt_run_hook(string_to_type_internal(string)) rescue Exception => e txt = if tn "to type '#{tn}' failed:\n\t -> " else "failed: " end raise "Conversion of '#{string}' #{txt}#{e.message}" end end
Returns a type name suitable for displaying, for instance, in an option parser, or inside a dialog box, and so on. Has to be one word (not to confuse the option parser, for instance); it is better if it is lowercase.
# File lib/ctioga2/metabuilder/type.rb, line 254 def type_name return 'notype' end
This function does the exact opposite of the string_to_type
one. It defaults to using the to_s methods of the parameter. Be careful: it is absolutely important that for any valid type,
string_to_type(type_to_string(type)) == type
# File lib/ctioga2/metabuilder/type.rb, line 238 def type_to_string(type) return type_to_string_internal(type) end
Protected Instance Methods
Part of the internal implementation of Types
. This should be used/redefined in children
# File lib/ctioga2/metabuilder/type.rb, line 298 def build_namespace_lookup if @type[:namespace] @namespace = [@type[:namespace]].flatten @namespace_lookup = {} for m in @namespace for c in m.constants @namespace_lookup[c.to_s.downcase] = m.const_get(c) end end end end
Looks for the value as a constant specified in the :namespace modules. Raises IncorrectInput
if not found.
# File lib/ctioga2/metabuilder/type.rb, line 314 def lookup_const(str) str = str.downcase if @type[:namespace] && (! @namespace_lookup) build_namespace_lookup end if @namespace_lookup.key? str return @namespace_lookup[str] else raise IncorrectInput, "Constant #{str} not found" end end
Creates on option for the OptionParser parser. The args will be fed directly to OptionParser#on. The block is called with the value in the target type.
# File lib/ctioga2/metabuilder/type.rb, line 352 def option_parser_raw(parser, *args, &block) b = block # For safe-keeping. c = proc do |str| b.call(string_to_type(str)) end parser.on(*args, &c) end
Does the actual conversion from a string to the type. Redefine this in children.
# File lib/ctioga2/metabuilder/type.rb, line 345 def string_to_type_internal(string) raise "The class #{self.class} should not be used by itself for conversion" end
Runs the string_to_type
conversion hook
# File lib/ctioga2/metabuilder/type.rb, line 335 def stt_run_hook(val) if @type.key?(:stt_hook) return @type[:stt_hook].call(val) else val end end
The internal function for converting type to a string. Used by type_to_string
, children should only reimplement this function and leave type_to_string
# File lib/ctioga2/metabuilder/type.rb, line 329 def type_to_string_internal(type) return type.to_s end