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:

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

Types::IntegerParameter

:float

Types::FloatParameter

:string

Types::StringParameter

:file

Types::FileParameter

:boolean

Types::BooleanParameter

:list

Types::ListParameter

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:

Attributes

namespace[RW]

An array of module whose constants can be used “as such”

namespace_lookup[RW]

When a :namespace option is provided, this hash provides a lookup 'lowercase name' => constant value.

passthrough[RW]

If the given string matches this regular expression, it is passed through without further modification.

re_shortcuts[RW]

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.

shortcuts[RW]

A hash shortcut -> value. Can be nil

type[RW]

The initial type specification that was given to the Type

Public Class Methods

from_string(type, string) click to toggle source

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
get_param_type(type) click to toggle source

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
get_type(type) click to toggle source

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
new(type) click to toggle source

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
type_name(name, public_name = nil, default_value = nil) click to toggle source

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

boolean?() click to toggle source

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
default_value() click to toggle source

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
option_parser_long_option(name, param = nil) click to toggle source

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
option_parser_option(parser, name, desc, &block) click to toggle source

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
string_to_type(string, tn = nil) click to toggle source

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
type_name() click to toggle source

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
type_to_string(type) click to toggle source

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

build_namespace_lookup() click to toggle source

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
lookup_const(str) click to toggle source

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
option_parser_raw(parser, *args, &block) click to toggle source

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
string_to_type_internal(string) click to toggle source

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
stt_run_hook(val) click to toggle source

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
type_to_string_internal(type) click to toggle source

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