#
# = lib/evo/util/util.rb - Util class
#
-# Copyright:: Copyright (C) 2006-2007 Christian M. Zmasek
-# License:: GNU Lesser General Public License (LGPL)
+# Copyright:: Copyright (C) 2017 Christian M. Zmasek
+# License:: GNU Lesser General Public License (LGPL)
#
-# $Id: util.rb,v 1.17 2009/10/06 22:22:46 cmzmasek Exp $
-#
-# last modified: 05/15/2007
+# Last modified: 2017/04/27
+require 'pathname'
require 'lib/evo/util/constants'
module Evoruby
+ class Util
+ def Util.canonical_path( parent, child = nil )
+ if child == nil
+ return File.expand_path(Pathname.new(parent).cleanpath.to_s).to_s
+ end
- class Util
+ s = nil
+ if parent.end_with?('/')
+ s = parent + child
+ else
+ s = parent + '/' + child
+ end
+ File.expand_path(Pathname.new(s).cleanpath.to_s).to_s
+ end
- def Util.normalize_seq_name( name, length )
- if name.length > length
- name = name[ 0, length ]
- elsif name.length < length
- for i in 0 ... length - name.length
- name = name + " "
- end
- end
- name
+ def Util.get_matching_files( files, prefix_pattern, suffix_pattern )
+ matching_files = Array.new
+ files.each { | file |
+ if ( !File.directory?( file ) &&
+ file !~ /^\./ &&
+ file =~ /^#{prefix_pattern}.*#{suffix_pattern}$/ )
+ matching_files << file
end
+ }
+ matching_files
+ end
- # def Util.normalize_mol_sequence( seq )
- # new_seq = String.new()
- # for i in 0 ... seq.length
- # c = seq.get_slice( i )
- # if is_aa_gap_character?( c )
- # new_seq = new_seq + "-"
- # else
- # new_seq = new_seq + c
- # end
- # end
- # new_seq
- # end
-
-
- # Returns true if char_code corresponds to: space * - . _
- def Util.is_aa_gap_character?( char_code )
- return ( char_code <= 32 || char_code == 42 || char_code == 45 || char_code == 46 ||char_code == 95 )
- end
+ def Util.get_matching_file( dir_name, prefix, suffix )
+ unless Dir.exist? dir_name
+ raise IOError, "directory [#{dir_name}] does not exist"
+ end
- # Deletes *, digits, and whitespace, replaces BJOUZ? with X, and replaces non-(letters, -) with -
- def Util.clean_seq_str( seq_str )
- seq_str = seq_str.upcase
- seq_str = seq_str.gsub( /\s+/, '' )
- seq_str = seq_str.gsub( /\d+/, '' )
- seq_str = seq_str.gsub( '*', '' )
- seq_str = seq_str.gsub( /[BJOUZ?]/, 'X' )
- seq_str = seq_str.gsub( /[^A-Z\-]/, '-' )
- seq_str
- end
+ all_files = Dir.entries(dir_name)
- # raises ArgumentError
- def Util.check_file_for_readability( path )
- unless ( File.exist?( path ) )
- error_msg = "file [#{path}] does not exist"
- raise ArgumentError, error_msg
- end
- unless ( File.file?( path ) )
- error_msg = "file [#{path}] is not a regular file"
- raise ArgumentError, error_msg
- end
- unless ( File.readable?( path ) )
- error_msg = "file [#{path}] is not a readable file"
- raise ArgumentError, error_msg
- end
- if ( File.zero?( path ) )
- error_msg = "file [#{path}] is empty"
- raise ArgumentError, error_msg
- end
+ if ( all_files.size <= 2 )
+ raise IOError, "directory [#{dir_name}] is empty"
+ end
+ matching_files = Array.new
+ all_files.each { | file |
+ if (( !File.directory?( file )) && (file.end_with? suffix))
+ matching_files << file
end
+ }
- # raises ArgumentError
- def Util.check_file_for_writability( path )
- if File.directory?( path )
- error_msg = "file [#{path}] is an existing directory"
- raise ArgumentError, error_msg
- elsif File.exist?( path )
- error_msg = "file [#{path}] already exists"
- raise ArgumentError, error_msg
- elsif File.writable?( path )
- error_msg = "file [#{path}] is not writeable"
- raise ArgumentError, error_msg
- end
- end
+ if ( matching_files.size == 0 )
+ raise IOError, "no files ending with \"" + suffix + "\" found in [" + dir_name + "]"
+ end
+ my_prefix = prefix
+ done = false
+ more_than_one = false
+ the_one = nil;
+
+ loop do
- def Util.fatal_error_if_not_writable( prg_name, path )
- begin
- Util.check_file_for_writability( path )
- rescue ArgumentError => e
- Util.fatal_error( prg_name, e.to_s )
+ matches = 0
+ matching_files.each { | file |
+ if file.start_with?( my_prefix )
+ matches += 1
+ if matches > 1
+ the_one = nil
+ break
end
+ the_one = file
+ end
+ }
+ if matches > 1
+ more_than_one = true
+ done = true
end
+ if matches == 1
+ done = true
+ else
+ if my_prefix.length <= 1
+ raise IOError, "no file matching \"" + prefix + "\" and ending with \"" + suffix + "\" found in [" + dir_name + "]"
+ end
+ my_prefix = my_prefix[ 0 ... ( my_prefix.length - 1 ) ]
- def Util.fatal_error_if_not_readable( prg_name, path )
- begin
- Util.check_file_for_readability( path )
- rescue ArgumentError => e
- Util.fatal_error( prg_name, e.to_s )
- end
end
+ break if done
+ end
- def Util.get_env_variable_value( env_variable )
- value = ENV[env_variable]
- if value == nil || value.empty?
- error_msg = "apparently environment variable #{env_variable} has not been set"
- raise StandardError, error_msg
- end
- value
+ if more_than_one
+ raise IOError, "multiple files matching \"" + prefix +
+ "\" and ending with \"" + suffix + "\" found in [" + dir_name + "]"
+ elsif the_one != nil
+ else
+ raise IOError, "no file matching \"" + prefix + "\" and ending with \"" +
+ suffix + "\" found in [" + dir_name + "]"
+ end
+ the_one
+ end
+
+ def Util.normalize_seq_name( name, length, exception_if_too_long = false )
+ if name.length > length
+ if exception_if_too_long
+ error_msg = "sequence name \"#{name}\" is too long (>#{length})"
+ raise StandardError, error_msg
end
-
-
- # raises ArgumentError
- def Util.file2array( path, split_by_semicolon )
- Util.check_file_for_readability( path )
- a = Array.new()
- c = 0
- File.open( path ) do | file |
- while line = file.gets
- if ( line =~ /^\s*(\S.*?)\s*$/ )
- s = $1
- if ( split_by_semicolon && s =~/;/ )
- sa = s.split( /;/ )
- for i in 0 ... sa.length()
- a[ c ] = sa[ i ].strip!
- end
- else
- a[ c ] = s
- end
- c += 1
- end
- end
- end
- return a
+ name = name[ 0, length ]
+ elsif name.length < length
+ t = length - name.length
+ t.times do
+ name = name + " "
end
+ end
+ name
+ end
- def Util.print_program_information( prg_name,
- prg_version,
- prg_desc,
- date,
- copyright,
- contact,
- www,
- io = STDOUT )
-
- if RUBY_VERSION !~ /1.9/
- puts( "Your ruby version is #{RUBY_VERSION}, expected 1.9.x " )
- exit( -1 )
- end
+ # Returns true if char_code corresponds to: space * - . _
+ def Util.is_aa_gap_character?( char_code )
+ return ( char_code <= 32 || char_code == 42 || char_code == 45 || char_code == 46 ||char_code == 95 )
+ end
- ruby_version = RUBY_VERSION
- l = prg_name.length + prg_version.length + date.length + ruby_version.length + 12
- io.print( Evoruby::Constants::LINE_DELIMITER )
- io.print( prg_name + " " + prg_version + " [" + date + "] [ruby " + ruby_version + "]")
- io.print( Evoruby::Constants::LINE_DELIMITER )
- l.times {
- io.print( "_" )
- }
- io.print( Constants::LINE_DELIMITER )
- io.print( Constants::LINE_DELIMITER )
- io.print( prg_desc )
- io.print( Constants::LINE_DELIMITER )
- io.print( Constants::LINE_DELIMITER )
- io.print( "Copyright (C) " + copyright )
- io.print( Constants::LINE_DELIMITER )
- io.print( "Contact: " + contact )
- io.print( Constants::LINE_DELIMITER )
- io.print( " " + www )
- io.print( Constants::LINE_DELIMITER )
- io.print( Constants::LINE_DELIMITER )
- end
+ # Deletes *, digits, and whitespace, replaces BJOUZ? with X, and replaces non-(letters, -) with -
+ def Util.clean_seq_str( seq_str )
+ seq_str = seq_str.upcase
+ seq_str = seq_str.gsub( /\s+/, '' )
+ seq_str = seq_str.gsub( /\d+/, '' )
+ seq_str = seq_str.gsub( '*', '' )
+ seq_str = seq_str.gsub( /[BJOUZ?]/, 'X' )
+ seq_str = seq_str.gsub( /[^A-Z\-]/, '-' )
+ seq_str
+ end
- def Util.fatal_error( prg_name, message, io = STDOUT )
- io.print( Constants::LINE_DELIMITER )
- if ( !Util.is_string_empty?( prg_name ) )
- io.print( "[" + prg_name + "] > " + message )
- else
- io.print( " > " + message )
- end
- io.print( Constants::LINE_DELIMITER )
- io.print( Constants::LINE_DELIMITER )
- exit( -1 )
- end
+ # raises ArgumentError
+ def Util.check_file_for_readability( path )
+ unless ( File.exist?( path ) )
+ error_msg = "file [#{path}] does not exist"
+ raise IOError, error_msg
+ end
+ unless ( File.file?( path ) )
+ error_msg = "file [#{path}] is not a regular file"
+ raise IOError, error_msg
+ end
+ unless ( File.readable?( path ) )
+ error_msg = "file [#{path}] is not a readable file"
+ raise IOError, error_msg
+ end
+ if ( File.zero?( path ) )
+ error_msg = "file [#{path}] is empty"
+ raise IOError, error_msg
+ end
+ end
- def Util.print_message( prg_name, message, io = STDOUT )
- if ( !Util.is_string_empty?( prg_name ) )
- io.print( "[" + prg_name + "] > " + message )
- else
- io.print( " > " + message )
- end
- io.print( Constants::LINE_DELIMITER )
- end
+ # raises ArgumentError
+ def Util.check_file_for_writability( path )
+ if File.directory?( path )
+ error_msg = "file [#{path}] is an existing directory"
+ raise IOError, error_msg
+ elsif File.exist?( path )
+ error_msg = "file [#{path}] already exists"
+ raise IOError, error_msg
+ elsif File.writable?( path )
+ error_msg = "file [#{path}] is not writeable"
+ raise IOError, error_msg
+ end
+ end
- def Util.print_warning_message( prg_name, message, io = STDOUT )
- if ( !Util.is_string_empty?( prg_name ) )
- io.print( "[" + prg_name + "] > WARNING: " + message )
+ def Util.fatal_error_if_not_writable( prg_name, path )
+ begin
+ Util.check_file_for_writability( path )
+ rescue IOError => e
+ Util.fatal_error( prg_name, e.to_s )
+ end
+ end
+
+ def Util.fatal_error_if_not_readable( prg_name, path )
+ begin
+ Util.check_file_for_readability( path )
+ rescue IOError => e
+ Util.fatal_error( prg_name, e.to_s )
+ end
+ end
+
+ def Util.get_env_variable_value( env_variable )
+ value = ENV[env_variable]
+ if value == nil || value.empty?
+ error_msg = "apparently environment variable #{env_variable} has not been set"
+ raise StandardError, error_msg
+ end
+ value
+ end
+
+ # raises ArgumentError
+ def Util.file2array( path, split_by_semicolon )
+ Util.check_file_for_readability( path )
+ a = Array.new()
+ c = 0
+ File.open( path ) do | file |
+ while line = file.gets
+ if ( line =~ /^\s*(\S.*?)\s*$/ )
+ s = $1
+ if ( split_by_semicolon && s =~/;/ )
+ sa = s.split( /;/ )
+ for i in 0 ... sa.length()
+ a[ c ] = sa[ i ].strip!
+ end
else
- io.print( " > " + message )
+ a[ c ] = s
end
- io.print( Constants::LINE_DELIMITER )
+ c += 1
+ end
end
+ end
+ return a
+ end
- def Util.is_string_empty?( s )
- return ( s == nil || s.length < 1 )
- end
+ def Util.print_program_information( prg_name,
+ prg_version,
+ prg_desc,
+ date,
+ www,
+ io = STDOUT )
- # From "Ruby Cookbook"
- # counts_hash: key is a "name", value is the count (integer)
- def Util.draw_histogram( counts_hash, char = "#" )
- pairs = counts_hash.keys.collect { |x| [ x.to_s, counts_hash[ x ] ] }.sort
- largest_key_size = pairs.max { |x, y| x[ 0 ].size <=> y[ 0 ].size }[ 0 ].size
- pairs.inject( "" ) do | s, kv |
- s << "#{ kv[ 0 ].ljust( largest_key_size ) } | #{ char*kv[ 1 ] }" + Constants::LINE_DELIMITER
- end
- end
+ ruby_version = RUBY_VERSION
+ l = prg_name.length + prg_version.length + date.length + ruby_version.length + 12
+ io.print( Evoruby::Constants::LINE_DELIMITER )
+ io.print( prg_name + " " + prg_version + " [" + date + "] [ruby " + ruby_version + "]")
+ io.print( Evoruby::Constants::LINE_DELIMITER )
+ l.times {
+ io.print( "_" )
+ }
+ io.print( Constants::LINE_DELIMITER )
+ io.print( Constants::LINE_DELIMITER )
+ io.print( prg_desc )
+ io.print( Constants::LINE_DELIMITER )
+ io.print( Constants::LINE_DELIMITER )
+ io.print( "Website: " + www )
+ io.print( Constants::LINE_DELIMITER )
+ io.print( Constants::LINE_DELIMITER )
+ end
- def Util.looks_like_fasta?( path )
- Util.check_file_for_readability( path )
- File.open( path ) do | file |
- while line = file.gets
- if ( line !~ /\S/ || line =~ /^\s*#/ )
- elsif line =~ /^\s*>\s*(.+)/
- return true
- else
- return false
- end
- end
- end
- error_msg = "unexpected format"
- raise IOError, error_msg
+ def Util.fatal_error( prg_name, message, io = STDOUT )
+ io.print( Constants::LINE_DELIMITER )
+ if ( !Util.is_string_empty?( prg_name ) )
+ io.print( "[" + prg_name + "] > " + message )
+ else
+ io.print( " > " + message )
+ end
+ io.print( Constants::LINE_DELIMITER )
+ io.print( Constants::LINE_DELIMITER )
+ exit( -1 )
+ end
+
+ def Util.print_message( prg_name, message, io = STDOUT )
+ if ( !Util.is_string_empty?( prg_name ) )
+ io.print( "[" + prg_name + "] > " + message )
+ else
+ io.print( " > " + message )
+ end
+ io.print( Constants::LINE_DELIMITER )
+ end
+
+ def Util.print_warning_message( prg_name, message, io = STDOUT )
+ if ( !Util.is_string_empty?( prg_name ) )
+ io.print( "[" + prg_name + "] > WARNING: " + message )
+ else
+ io.print( " > " + message )
+ end
+ io.print( Constants::LINE_DELIMITER )
+ end
+
+ def Util.is_string_empty?( s )
+ return ( s == nil || s.length < 1 )
+ end
+
+ # From "Ruby Cookbook"
+ # counts_hash: key is a "name", value is the count (integer)
+ def Util.draw_histogram( counts_hash, char = "#" )
+ pairs = counts_hash.keys.collect { |x| [ x.to_s, counts_hash[ x ] ] }.sort
+ largest_key_size = pairs.max { |x, y| x[ 0 ].size <=> y[ 0 ].size }[ 0 ].size
+ pairs.inject( "" ) do | s, kv |
+ s << "#{ kv[ 0 ].ljust( largest_key_size ) } | #{ char*kv[ 1 ] }" + Constants::LINE_DELIMITER
+ end
+ end
+
+ def Util.looks_like_fasta?( path )
+ Util.check_file_for_readability( path )
+ File.open( path ) do | file |
+ while line = file.gets
+ if ( line !~ /\S/ || line =~ /^\s*#/ )
+ elsif line =~ /^\s*>\s*(.+)/
+ return true
+ else
+ return false
+ end
end
+ end
+ error_msg = "unexpected format"
+ raise IOError, error_msg
+ end
- end # class Util
+ end # class Util
end # module Evoruby