lib/como.rb in como-0.1.7 vs lib/como.rb in como-0.2.0
- old
+ new
@@ -272,15 +272,13 @@
# String values can be left out, since only the document
# string is used. Default option is referred with
# ":default" or "nil".
# [:exclusive] Option that does not co-exist with other
# options. :exclusive can have arguments as with
-# :opt_any, however :exclusive is documented like
-# :switch.
-# [:silent] Option that does not coexist with other options and is not
-# displayed as an option in Usage Help display. In effect a
-# sub-option of :exclusive.
+# :opt_any.
+# [:silent] Switch option that is not displayed as an option in Usage
+# Help display.
#
# Options use typically all the 4 option fields:
# [ type, name, mnemonic, doc ]
#
# "type" field is mandatory for all options.
@@ -297,10 +295,47 @@
# use a ":silent" option that can be used to terminate the argument
# list. For example:
# [ :silent, "terminator", "-", "The terminator." ],
#
#
+# == Option type primitives
+#
+# Como converts option types into option type primitives. Option types
+# are not completely orthogonal, but primitives are.
+#
+# Primitives:
+#
+# [:none] No arguments (i.e. switch).
+# [:one] One argument.
+# [:many] More than one argument.
+# [:opt] Optional argument(s).
+# [:default] Default option.
+# [:mutex] Mutually exclusive option.
+# [:hidden] Hidden option (no usage doc).
+#
+# Types to primitives mapping:
+#
+# [:switch] :none, :opt
+# [:single] :one
+# [:multi] :one, :many
+# [:opt_single] :one, :opt
+# [:opt_multi] :one, :many, :opt
+# [:opt_any] :none, :one, :many, :opt
+# [:default] :none, :one, :many, :opt, :default
+# [:exclusive] :none, :one, :many, :opt, :mutex
+# [:silent] :none, :opt, :hidden
+#
+# Primitives can be used in place of types if exotic options are
+# needed. Instead of a single Symbol an Array of primitives are given
+# for option type. Order of primitives is not significant.
+#
+# For example:
+# [ [ :none, :hidden, :opt ], "terminator", "-", "The terminator." ],
+#
+# Como does not check the primitive combinations, thus care and
+# consideration should be applied.
+#
# == Option specification method configuration
#
# Option behavior can be controlled with several configuration options.
#
# The configuration options are provided in a Hash. These are the
@@ -469,11 +504,10 @@
# Como version is returned with:
# Como.version
module Como
-
# IO stream options for Como classes.
class ComoCommon
# Default value for display output.
@@io = STDOUT
@@ -730,29 +764,85 @@
Opt.subcmd( opt_or_sub[1], opt_or_sub[3] )
else
- case opt_or_sub[0]
+ types = Spec.mapTypeToPrims( opt_or_sub[0] )
- when :switch, :exclusive, :silent, :single, :multi,
- :opt_single, :opt_multi, :opt_any
- Opt.full( opt_or_sub[1], opt_or_sub[2], opt_or_sub[0], opt_or_sub[3] )
-
- when :default
+ if types.index( :default )
Opt.defaultOpt( opt_or_sub[3] )
-
else
- raise "Unknown option type: \"#{opt_or_sub[0]}\"..."
-
+ Opt.full( opt_or_sub[1],
+ opt_or_sub[2],
+ Spec.mapTypeToPrims( opt_or_sub[0] ),
+ opt_or_sub[3] )
end
end
end
+ # Option type primitives.
+ TYPE_PRIMS = [
+ # No arguments (i.e. switch).
+ :none,
+ # One argument.
+ :one,
+ # More than one argument.
+ :many,
+ # Optional argument(s).
+ :opt,
+ # Default option.
+ :default,
+ # Mutually exclusive option.
+ :mutex,
+ # Hidden option (no usage doc).
+ :hidden
+ ]
+
+
+ # Convert option types (type definitions) to option type
+ # primitives.
+ def Spec.mapTypeToPrims( type )
+
+ prims = nil
+
+ if type.kind_of? Symbol
+ case type
+ when :switch; prims = [ :none, :opt ]
+ when :single; prims = [ :one ]
+ when :multi; prims = [ :one, :many ]
+ when :opt_single; prims = [ :one, :opt ]
+ when :opt_multi; prims = [ :one, :many, :opt ]
+ when :opt_any; prims = [ :none, :one, :many, :opt ]
+ when :default; prims = [ :none, :one, :many, :default, :opt ]
+ when :exclusive; prims = [ :none, :one, :many, :opt, :mutex ]
+ when :silent; prims = [ :none, :opt, :hidden ]
+ else
+ raise "Unknown option type: \"#{type}\"..."
+ end
+
+ elsif type.kind_of? Array
+ prims = []
+
+ # Check that type primivives are valid before taking
+ # them into use.
+ type.each do |t|
+ if TYPE_PRIMS.index( t )
+ prims.push t
+ else
+ raise "Unknown option type primitive: \"#{t}\"..."
+ end
+ end
+ else
+ raise "Invalid option type definition: \"#{type}\"..."
+ end
+
+ prims
+ end
+
# Command line options source.
@@argv = ARGV
# Set command line options source, i.e. @@argv (default: ARGV).
def Spec.setArgv( newArgv )
@@ -1002,11 +1092,11 @@
new( name, nil, :subcmd, doc, false )
end
# Create default option spec, no switch.
def Opt.defaultOpt( doc = "No doc." )
- new( "<default>", "<default>", :default, doc, [] )
+ new( "<default>", "<default>", [ :default, :none, :one, :many, :opt ], doc, [] )
end
# Options iterator for all options.
def Opt.each( &blk )
@@ -1072,11 +1162,11 @@
attr_accessor :shortOpt
# Long option string.
attr_accessor :longOpt
- # Option type.
+ # Option type as array of primitives (or :subcmd).
attr_accessor :type
# Option value.
attr_accessor :value
@@ -1100,32 +1190,27 @@
# Create Opt object.
# @param name [String] Option name.
# @param opt [String] Switch.
- # @param type [Symbol] Option type. One of:
- # * :switch
- # * :single
- # * :multi
- # * :opt_single
- # * :opt_multi
- # * :opt_any
- # * :default
- # * :exclusive
- # * :silent
+ # @param type [Array<Symbol>, Symbol] Option type in
+ # primitives (or :subcmd).
# @param doc [String] Option documentation.
# @param value [Object] Default value.
def initialize( name, opt, type, doc, value = nil )
@parent = nil
@name = name
@shortOpt = opt
@longOpt = "--#{name}"
@type = type
+
@value = value
- if hasMany && value == nil
- @value = []
+ if @type != :subcmd
+ if prim?( :many ) && value == nil
+ @value = []
+ end
end
@doc = doc
# Whether option was set or not.
@given = false
@@ -1239,11 +1324,11 @@
# Parse cmdline options from args.
def parse( args, checkInvalids = true )
while args.get
- #puts "Opt.parse (#{@name}): #{args.get}"
+ # puts "Opt.parse (#{@name}): #{args.get}"
if args.isOptTerm
# Rest of the args do not belong to this program.
args.next
@@ -1271,24 +1356,24 @@
o.value.push args.toValue
args.next
end
end
- elsif o && o.hasArg
+ elsif o && ( o.prim?( :one ) || o.prim?( :many ) )
args.next
if ( !args.get || args.isOpt ) &&
- o.type != :opt_any && o.type != :exclusive
+ !o.prim?( :none )
raise MissingArgument.new(
"No argument given for \"#{o.opt}\"...",
self )
else
- if o.hasMany
+ if o.prim?( :many )
# Get all argument for multi-option.
o.value = [] if !o.given
while args.get && !args.isOpt
o.value.push args.toValue
@@ -1373,20 +1458,20 @@
# Full cmd name.
cmd = ( getParents.map do |i| i.name end ).join( ' ' )
# Check for any exclusive args first.
@subopt.each do |o|
- if o.isExclusive && o.given
+ if o.prim?( :mutex ) && o.given
return
end
end
# Check for required arguments for this level before
# subcmds.
@subopt.each do |o|
- if o.isRequired
+ if !o.prim?( :opt )
unless o.given
raise MissingArgument.new(
"Option \"#{o.opt}\" missing for \"#{cmd}\"...",
self )
end
@@ -1521,11 +1606,11 @@
# Return option value if given otherwise the default.
# Example usage: fileName = Opt["file"].apply( "no_name.txt" )
def apply( default = nil )
if given
- if @type == :switch
+ if prim?( :none )
true
else
value
end
else
@@ -1593,11 +1678,11 @@
# Select option object by name.
def argByName( str )
if str == nil || str == :default
@subopt.each do |o|
- if o.type == :default
+ if o.prim?( :default )
return o
end
end
nil
else
@@ -1613,11 +1698,11 @@
# Select option object by name/opt/longOpt.
def argById( str )
if str == nil || str == :default
@subopt.each do |o|
- if o.type == :default
+ if o.prim?( :default )
return o
end
end
nil
else
@@ -1629,58 +1714,23 @@
nil
end
end
- # Option requires argument?
- def hasArg
- case @type
- when :single, :multi, :opt_single, :opt_multi, :opt_any, :exclusive; true
- else false
- end
+ # Check for primitive.
+ def prim?( prim )
+ @type.index( prim )
end
- # Option requires many arguments?
- def hasMany
- case @type
- when :multi, :opt_multi, :opt_any, :exclusive, :default; true
- else false
- end
- end
-
-
- # Is mandatory argument?
- def isRequired
- case @type
- when :single, :multi; true
- else false
- end
- end
-
-
- # Test if option is silent.
- def silent?
- @type == :silent
- end
-
-
- # Test if option is exclusive. In addition :exclusive also
- # :silent is exclusive.
- def isExclusive
- case @type
- when :exclusive, :silent; true
- else false
- end
- end
-
-
# Test if option is of switch type.
- def isSwitch
- case @type
- when :switch, :exclusive, :default; true
- else false
+ def hasSwitchStyleDoc
+ if ( prim?( :none ) && !prim?( :many ) ) ||
+ prim?( :default )
+ true
+ else
+ false
end
end
# ------------------------------------------------------------
@@ -1770,21 +1820,22 @@
def cmdline
opts = []
@subopt.each do |o|
- next if o.silent?
+ next if o.prim?( :hidden )
prural = nil
- case o.type
- when :multi, :opt_multi; prural = "+"
- when :opt_any; prural = "*"
- else prural = ""
+ if o.prim?( :none ) && o.prim?( :many )
+ prural = "*"
+ elsif o.prim?( :one ) && o.prim?( :many )
+ prural = "+"
+ else
+ prural = ""
end
-
- if !( o.isSwitch )
+ if !( o.hasSwitchStyleDoc )
name = " <#{o.name}>#{prural}"
else
name = ""
end
@@ -1792,11 +1843,11 @@
opt = o.longOpt
else
opt = o.shortOpt
end
- if o.isRequired
+ if !o.prim?( :opt )
opts.push "#{opt}#{name}"
else
opts.push "[#{opt}#{name}]"
end
end
@@ -1820,11 +1871,11 @@
str += "\n"
str += " Options:\n" if hasSubcmd && hasVisibleOptions
@subopt.each do |o|
- next if o.silent?
+ next if o.prim?( :hidden )
str += suboptDocFormat( o.opt, o.doc )
end
str += "\n" + suboptDocFormat( "Subcommands:", "" ) if hasSubcmd
@@ -1837,11 +1888,11 @@
# Find option object by option str.
def findOpt( str )
if str == nil
- suball.detect { |i| i.type == :default }
+ suball.detect { |i| i.prim?( :default ) }
elsif str[0..1] == "--"
suball.detect { |i| i.longOpt == str }
elsif str[0..0] != "-"
suball.detect { |i| i.name == str }
else
@@ -1967,10 +2018,10 @@
# Test if option is of subcmd type.
def hasVisibleOptions
# Count non-silent options.
- ( @subopt.select do |i| !i.silent? end ).length > 0
+ ( @subopt.select do |i| !i.prim?( :hidden ) end ).length > 0
end
# Test if option is of subcmd type.
def hasSubcmd