require 'open3'
require 'pp'
-# Error class for all exceptions to do with option casts.
-class CastError < StandardError
-end
-
# Biopieces are command line scripts and uses OptionParser to parse command line
# options according to a list of casts. Each cast prescribes the long and short
# name of the option, the type, if it is mandatory, the default value, and allowed
# of lines with a key/value pair seperated by a colon and a white space ': '.
# Each record is separated by a line with three dashes '---'.
class Biopieces
- TYPES = %w[flag string list int uint float file file! files files! dir dir! genome]
- MANDATORY = %w[long short type mandatory default allowed disallowed]
REGEX_LIST = /^(list|files|files!)$/
REGEX_INT = /^(int|uint)$/
REGEX_STRING = /^(string|file|file!|dir|dir!|genome)$/
# Check the integrity of a list of casts, followed by parsion options from argv
# and finally checking the options according to the casts. Returns nil if
# argv is empty, otherwise an options hash.
- def parse(argv,casts=[],script_path=$0)
- @casts = casts
- @script_path = script_path
+ def parse(argv,cast_list=[],script_path=$0)
+ casts = Casts.new(cast_list)
+
+ pp casts.class
+ pp casts
- cast_ubiquitous
- cast_check
+ @script_path = script_path
@options = {}
options_template = OptionParser.new do |option|
- @casts.each do |cast|
+ casts.each do |cast|
if cast[:type] == 'flag'
option.on("-#{cast[:short]}", "--#{cast[:long]}") do |o|
@options[cast[:long]] = o
path
end
- # Add ubiquitous options casts.
- def cast_ubiquitous
- @casts << {:long => 'help', :short => '?', :type => 'flag', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
- @casts << {:long => 'stream_in', :short => 'I', :type => 'files!', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
- @casts << {:long => 'stream_out', :short => 'O', :type => 'file', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
- @casts << {:long => 'verbose', :short => 'v', :type => 'flag', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
- end
-
- # Check integrity of the casts.
- def cast_check
- cast_check_keys
- cast_check_values
- cast_check_duplicates
- end
-
- # Check if all mandatory keys are present in casts and raise if not.
- def cast_check_keys
- @casts.each do |cast|
- MANDATORY.each do |mandatory|
- raise CastError, "Missing symbol in cast: '#{mandatory.to_sym}'" unless cast.has_key? mandatory.to_sym
- end
- end
- end
-
- # Check if all values in casts are valid.
- def cast_check_values
- @casts.each do |cast|
- cast_check_val_long(cast)
- cast_check_val_short(cast)
- cast_check_val_type(cast)
- cast_check_val_mandatory(cast)
- cast_check_val_default(cast)
- cast_check_val_allowed(cast)
- cast_check_val_disallowed(cast)
- end
- end
-
- # Check if the values to long are legal and raise if not.
- def cast_check_val_long(cast)
- unless cast[:long].is_a? String and cast[:long].length > 1
- raise CastError, "Illegal cast of long: '#{cast[:long]}'"
- end
- end
-
- # Check if the values to short are legal and raise if not.
- def cast_check_val_short(cast)
- unless cast[:short].is_a? String and cast[:short].length == 1
- raise CastError, "Illegal cast of short: '#{cast[:short]}'"
- end
- end
-
- # Check if values to type are legal and raise if not.
- def cast_check_val_type(cast)
- type_hash = {}
- TYPES.each do |type|
- type_hash[type] = true
- end
-
- unless type_hash.has_key? cast[:type]
- raise CastError, "Illegal cast of type: '#{cast[:type]}'"
- end
- end
-
- # Check if values to mandatory are legal and raise if not.
- def cast_check_val_mandatory(cast)
- unless cast[:mandatory] == true or cast[:mandatory] == false
- raise CastError, "Illegal cast of mandatory: '#{cast[:mandatory]}'"
- end
- end
-
- # Check if values to default are legal and raise if not.
- def cast_check_val_default(cast)
- unless cast[:default].nil? or
- cast[:default].is_a? String or
- cast[:default].is_a? Integer or
- cast[:default].is_a? Float
- raise CastError, "Illegal cast of default: '#{cast[:default]}'"
- end
- end
-
- # Check if values to allowed are legal and raise if not.
- def cast_check_val_allowed(cast)
- unless cast[:allowed].is_a? String or cast[:allowed].nil?
- raise CastError, "Illegal cast of allowed: '#{cast[:allowed]}'"
- end
- end
-
- # Check if values to disallowed are legal and raise if not.
- def cast_check_val_disallowed(cast)
- unless cast[:disallowed].is_a? String or cast[:disallowed].nil?
- raise CastError, "Illegal cast of disallowed: '#{cast[:disallowed]}'"
- end
- end
-
- # Check cast for duplicate long or short options names.
- def cast_check_duplicates
- check_hash = {}
- @casts.each do |cast|
- raise CastError, "Duplicate argument: '--#{cast[:long]}'" if check_hash.has_key? cast[:long]
- raise CastError, "Duplicate argument: '-#{cast[:short]}'" if check_hash.has_key? cast[:short]
- check_hash[cast[:long]] = true
- check_hash[cast[:short]] = true
- end
- end
-
# Check if full "usage info" should be printed.
def print_usage_full?
@options["help"]
# Set default options value from cast unless a value is set.
def options_default
- @casts.each do |cast|
+ casts.each do |cast|
if cast[:default]
@options[cast[:long]] = cast[:default] unless @options.has_key? cast[:long]
end
# Expands glob expressions to a full list of paths.
# Examples: "*.fna" or "foo.fna,*.fna" or "foo.fna,/bar/*.fna"
def options_glob
- @casts.each do |cast|
+ casts.each do |cast|
if cast[:type] == 'files' or cast[:type] == 'files!'
if @options.has_key? cast[:long]
files = []
# Check all options according to casts.
def options_check
- @casts.each do |cast|
+ casts.each do |cast|
options_check_mandatory(cast)
options_check_int(cast)
options_check_uint(cast)
# stdin or from a list of files specified in options["stream_in"].
def stream_in_open
if not $stdin.tty?
- stream = $stdin
+ p "IN"
+ stream = @input
else
stream = read(@options["stream_in"])
end
if @options["stream_out"]
stream = write(@options["stream_out"], @options["compress"])
else
+ p "OUT"
stream = @output
end
end
end
+# Error class for all exceptions to do with option casts.
+class CastError < StandardError
+end
+
+# Class to handle casts of command line options. Each cast prescribes the long and
+# short name of the option, the type, if it is mandatory, the default value, and
+# allowed and disallowed values. An optional list of extra casts can be supplied,
+# and the integrity of the casts are checked.
+class Casts < Array
+ TYPES = %w[flag string list int uint float file file! files files! dir dir! genome]
+ MANDATORY = %w[long short type mandatory default allowed disallowed]
+
+ def initialize(casts=[])
+ @casts = casts
+ ubiquitous
+ check
+ end
+
+ # Add ubiquitous options casts.
+ def ubiquitous
+ @casts << {:long => 'help', :short => '?', :type => 'flag', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
+ @casts << {:long => 'stream_in', :short => 'I', :type => 'files!', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
+ @casts << {:long => 'stream_out', :short => 'O', :type => 'file', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
+ @casts << {:long => 'verbose', :short => 'v', :type => 'flag', :mandatory => false, :default => nil, :allowed => nil, :disallowed => nil}
+ end
+
+ # Check integrity of the casts.
+ def check
+ check_keys
+ check_values
+ check_duplicates
+ end
+
+ # Check if all mandatory keys are present in casts and raise if not.
+ def check_keys
+ @casts.each do |cast|
+ MANDATORY.each do |mandatory|
+ raise CastError, "Missing symbol in cast: '#{mandatory.to_sym}'" unless cast.has_key? mandatory.to_sym
+ end
+ end
+ end
+
+ # Check if all values in casts are valid.
+ def check_values
+ @casts.each do |cast|
+ check_val_long(cast)
+ check_val_short(cast)
+ check_val_type(cast)
+ check_val_mandatory(cast)
+ check_val_default(cast)
+ check_val_allowed(cast)
+ check_val_disallowed(cast)
+ end
+ end
+
+ # Check if the values to long are legal and raise if not.
+ def check_val_long(cast)
+ unless cast[:long].is_a? String and cast[:long].length > 1
+ raise CastError, "Illegal cast of long: '#{cast[:long]}'"
+ end
+ end
+
+ # Check if the values to short are legal and raise if not.
+ def check_val_short(cast)
+ unless cast[:short].is_a? String and cast[:short].length == 1
+ raise CastError, "Illegal cast of short: '#{cast[:short]}'"
+ end
+ end
+
+ # Check if values to type are legal and raise if not.
+ def check_val_type(cast)
+ type_hash = {}
+ TYPES.each do |type|
+ type_hash[type] = true
+ end
+
+ unless type_hash.has_key? cast[:type]
+ raise CastError, "Illegal cast of type: '#{cast[:type]}'"
+ end
+ end
+
+ # Check if values to mandatory are legal and raise if not.
+ def check_val_mandatory(cast)
+ unless cast[:mandatory] == true or cast[:mandatory] == false
+ raise CastError, "Illegal cast of mandatory: '#{cast[:mandatory]}'"
+ end
+ end
+
+ # Check if values to default are legal and raise if not.
+ def check_val_default(cast)
+ unless cast[:default].nil? or
+ cast[:default].is_a? String or
+ cast[:default].is_a? Integer or
+ cast[:default].is_a? Float
+ raise CastError, "Illegal cast of default: '#{cast[:default]}'"
+ end
+ end
+
+ # Check if values to allowed are legal and raise if not.
+ def check_val_allowed(cast)
+ unless cast[:allowed].is_a? String or cast[:allowed].nil?
+ raise CastError, "Illegal cast of allowed: '#{cast[:allowed]}'"
+ end
+ end
+
+ # Check if values to disallowed are legal and raise if not.
+ def check_val_disallowed(cast)
+ unless cast[:disallowed].is_a? String or cast[:disallowed].nil?
+ raise CastError, "Illegal cast of disallowed: '#{cast[:disallowed]}'"
+ end
+ end
+
+ # Check cast for duplicate long or short options names.
+ def check_duplicates
+ check_hash = {}
+ @casts.each do |cast|
+ raise CastError, "Duplicate argument: '--#{cast[:long]}'" if check_hash.has_key? cast[:long]
+ raise CastError, "Duplicate argument: '-#{cast[:short]}'" if check_hash.has_key? cast[:short]
+ check_hash[cast[:long]] = true
+ check_hash[cast[:short]] = true
+ end
+ end
+end
+
__END__