2 # = lib/evo/util/util.rb - Util class
4 # Copyright:: Copyright (C) 2017 Christian M. Zmasek
5 # License:: GNU Lesser General Public License (LGPL)
7 # Last modified: 2017/04/27
10 require 'lib/evo/util/constants'
14 def Util.canonical_path( parent, child = nil )
16 return File.expand_path(Pathname.new(parent).cleanpath.to_s).to_s
20 if parent.end_with?('/')
23 s = parent + '/' + child
25 File.expand_path(Pathname.new(s).cleanpath.to_s).to_s
28 def Util.get_matching_files( files, prefix_pattern, suffix_pattern )
29 matching_files = Array.new
31 if ( !File.directory?( file ) &&
33 file =~ /^#{prefix_pattern}.*#{suffix_pattern}$/ )
34 matching_files << file
40 def Util.get_matching_file( dir_name, prefix, suffix )
41 unless Dir.exist? dir_name
42 raise IOError, "directory [#{dir_name}] does not exist"
45 all_files = Dir.entries(dir_name)
47 if ( all_files.size <= 2 )
48 raise IOError, "directory [#{dir_name}] is empty"
50 matching_files = Array.new
51 all_files.each { | file |
52 if (( !File.directory?( file )) && (file.end_with? suffix))
53 matching_files << file
57 if ( matching_files.size == 0 )
58 raise IOError, "no files ending with \"" + suffix + "\" found in [" + dir_name + "]"
68 matching_files.each { | file |
69 if file.start_with?( my_prefix )
85 if my_prefix.length <= 1
86 raise IOError, "no file matching \"" + prefix + "\" and ending with \"" + suffix + "\" found in [" + dir_name + "]"
88 my_prefix = my_prefix[ 0 ... ( my_prefix.length - 1 ) ]
95 raise IOError, "multiple files matching \"" + prefix +
96 "\" and ending with \"" + suffix + "\" found in [" + dir_name + "]"
99 raise IOError, "no file matching \"" + prefix + "\" and ending with \"" +
100 suffix + "\" found in [" + dir_name + "]"
105 def Util.normalize_seq_name( name, length, exception_if_too_long = false )
106 if name.length > length
107 if exception_if_too_long
108 error_msg = "sequence name \"#{name}\" is too long (>#{length})"
109 raise StandardError, error_msg
111 name = name[ 0, length ]
112 elsif name.length < length
113 t = length - name.length
121 # Returns true if char_code corresponds to: space * - . _
122 def Util.is_aa_gap_character?( char_code )
123 return ( char_code <= 32 || char_code == 42 || char_code == 45 || char_code == 46 ||char_code == 95 )
126 # Deletes *, digits, and whitespace, replaces BJOUZ? with X, and replaces non-(letters, -) with -
127 def Util.clean_seq_str( seq_str )
128 seq_str = seq_str.upcase
129 seq_str = seq_str.gsub( /\s+/, '' )
130 seq_str = seq_str.gsub( /\d+/, '' )
131 seq_str = seq_str.gsub( '*', '' )
132 seq_str = seq_str.gsub( /[BJOUZ?]/, 'X' )
133 seq_str = seq_str.gsub( /[^A-Z\-]/, '-' )
137 # raises ArgumentError
138 def Util.check_file_for_readability( path )
139 unless ( File.exist?( path ) )
140 error_msg = "file [#{path}] does not exist"
141 raise IOError, error_msg
143 unless ( File.file?( path ) )
144 error_msg = "file [#{path}] is not a regular file"
145 raise IOError, error_msg
147 unless ( File.readable?( path ) )
148 error_msg = "file [#{path}] is not a readable file"
149 raise IOError, error_msg
151 if ( File.zero?( path ) )
152 error_msg = "file [#{path}] is empty"
153 raise IOError, error_msg
157 # raises ArgumentError
158 def Util.check_file_for_writability( path )
159 if File.directory?( path )
160 error_msg = "file [#{path}] is an existing directory"
161 raise IOError, error_msg
162 elsif File.exist?( path )
163 error_msg = "file [#{path}] already exists"
164 raise IOError, error_msg
165 elsif File.writable?( path )
166 error_msg = "file [#{path}] is not writeable"
167 raise IOError, error_msg
171 def Util.fatal_error_if_not_writable( prg_name, path )
173 Util.check_file_for_writability( path )
175 Util.fatal_error( prg_name, e.to_s )
179 def Util.fatal_error_if_not_readable( prg_name, path )
181 Util.check_file_for_readability( path )
183 Util.fatal_error( prg_name, e.to_s )
187 def Util.get_env_variable_value( env_variable )
188 value = ENV[env_variable]
189 if value == nil || value.empty?
190 error_msg = "apparently environment variable #{env_variable} has not been set"
191 raise StandardError, error_msg
196 # raises ArgumentError
197 def Util.file2array( path, split_by_semicolon )
198 Util.check_file_for_readability( path )
201 File.open( path ) do | file |
202 while line = file.gets
203 if ( line =~ /^\s*(\S.*?)\s*$/ )
205 if ( split_by_semicolon && s =~/;/ )
207 for i in 0 ... sa.length()
208 a[ c ] = sa[ i ].strip!
220 def Util.print_program_information( prg_name,
227 ruby_version = RUBY_VERSION
228 l = prg_name.length + prg_version.length + date.length + ruby_version.length + 12
229 io.print( Evoruby::Constants::LINE_DELIMITER )
230 io.print( prg_name + " " + prg_version + " [" + date + "] [ruby " + ruby_version + "]")
231 io.print( Evoruby::Constants::LINE_DELIMITER )
235 io.print( Constants::LINE_DELIMITER )
236 io.print( Constants::LINE_DELIMITER )
238 io.print( Constants::LINE_DELIMITER )
239 io.print( Constants::LINE_DELIMITER )
240 io.print( "Website: " + www )
241 io.print( Constants::LINE_DELIMITER )
242 io.print( Constants::LINE_DELIMITER )
245 def Util.fatal_error( prg_name, message, io = STDOUT )
246 io.print( Constants::LINE_DELIMITER )
247 if ( !Util.is_string_empty?( prg_name ) )
248 io.print( "[" + prg_name + "] > " + message )
250 io.print( " > " + message )
252 io.print( Constants::LINE_DELIMITER )
253 io.print( Constants::LINE_DELIMITER )
257 def Util.print_message( prg_name, message, io = STDOUT )
258 if ( !Util.is_string_empty?( prg_name ) )
259 io.print( "[" + prg_name + "] > " + message )
261 io.print( " > " + message )
263 io.print( Constants::LINE_DELIMITER )
266 def Util.print_warning_message( prg_name, message, io = STDOUT )
267 if ( !Util.is_string_empty?( prg_name ) )
268 io.print( "[" + prg_name + "] > WARNING: " + message )
270 io.print( " > " + message )
272 io.print( Constants::LINE_DELIMITER )
275 def Util.is_string_empty?( s )
276 return ( s == nil || s.length < 1 )
279 # From "Ruby Cookbook"
280 # counts_hash: key is a "name", value is the count (integer)
281 def Util.draw_histogram( counts_hash, char = "#" )
282 pairs = counts_hash.keys.collect { |x| [ x.to_s, counts_hash[ x ] ] }.sort
283 largest_key_size = pairs.max { |x, y| x[ 0 ].size <=> y[ 0 ].size }[ 0 ].size
284 pairs.inject( "" ) do | s, kv |
285 s << "#{ kv[ 0 ].ljust( largest_key_size ) } | #{ char*kv[ 1 ] }" + Constants::LINE_DELIMITER
289 def Util.looks_like_fasta?( path )
290 Util.check_file_for_readability( path )
291 File.open( path ) do | file |
292 while line = file.gets
293 if ( line !~ /\S/ || line =~ /^\s*#/ )
294 elsif line =~ /^\s*>\s*(.+)/
301 error_msg = "unexpected format"
302 raise IOError, error_msg