Module: Misc

Defined in:
lib/rbbt/util/tar.rb,
lib/rbbt/util/misc.rb,
lib/rbbt/util/misc/lock.rb,
lib/rbbt/util/misc/math.rb,
lib/rbbt/util/misc/omics.rb,
lib/rbbt/util/misc/pipes.rb,
lib/rbbt/util/misc/format.rb,
lib/rbbt/util/misc/system.rb,
lib/rbbt/util/misc/inspect.rb,
lib/rbbt/util/misc/objects.rb,
lib/rbbt/util/misc/options.rb,
lib/rbbt/util/misc/development.rb,
lib/rbbt/util/misc/manipulation.rb

Overview

SOURCE: gist.github.com/sinisterchipmunk/1335041 Adapted for Rbbt

Constant Summary collapse

LOCK_MUTEX =
Mutex.new
LOCK_REPO_SERIALIZER =
Marshal
Log2Multiplier =
1.0 / Math.log(2.0)
IUPAC2BASE =
{
  "A" => ["A"],
  "C" => ["C"],
  "G" => ["G"],
  "T" => ["T"],
  "U" => ["U"],
  "R" => "A or G".split(" or "),
  "Y" => "C or T".split(" or "),
  "S" => "G or C".split(" or "),
  "W" => "A or T".split(" or "),
  "K" => "G or T".split(" or "),
  "M" => "A or C".split(" or "),
  "B" => "C or G or T".split(" or "),
  "D" => "A or G or T".split(" or "),
  "H" => "A or C or T".split(" or "),
  "V" => "A or C or G".split(" or "),
  "N" => %w(A C T G),
}
BASE2COMPLEMENT =
{
  "A" => "T",
  "C" => "G",
  "G" => "C",
  "T" => "A",
  "U" => "A",
}
THREE_TO_ONE_AA_CODE =
{
  "ala" =>   "A",
  "arg" =>   "R",
  "asn" =>   "N",
  "asp" =>   "D",
  "cys" =>   "C",
  "glu" =>   "E",
  "gln" =>   "Q",
  "gly" =>   "G",
  "his" =>   "H",
  "ile" =>   "I",
  "leu" =>   "L",
  "lys" =>   "K",
  "met" =>   "M",
  "phe" =>   "F",
  "pro" =>   "P",
  "ser" =>   "S",
  "thr" =>   "T",
  "trp" =>   "W",
  "tyr" =>   "Y",
  "val" =>   "V"
}
CODON_TABLE =
{
  "ATT" => "I",
  "ATC" => "I",
  "ATA" => "I",
  "CTT" => "L",
  "CTC" => "L",
  "CTA" => "L",
  "CTG" => "L",
  "TTA" => "L",
  "TTG" => "L",
  "GTT" => "V",
  "GTC" => "V",
  "GTA" => "V",
  "GTG" => "V",
  "TTT" => "F",
  "TTC" => "F",
  "ATG" => "M",
  "TGT" => "C",
  "TGC" => "C",
  "GCT" => "A",
  "GCC" => "A",
  "GCA" => "A",
  "GCG" => "A",
  "GGT" => "G",
  "GGC" => "G",
  "GGA" => "G",
  "GGG" => "G",
  "CCT" => "P",
  "CCC" => "P",
  "CCA" => "P",
  "CCG" => "P",
  "ACT" => "T",
  "ACC" => "T",
  "ACA" => "T",
  "ACG" => "T",
  "TCT" => "S",
  "TCC" => "S",
  "TCA" => "S",
  "TCG" => "S",
  "AGT" => "S",
  "AGC" => "S",
  "TAT" => "Y",
  "TAC" => "Y",
  "TGG" => "W",
  "CAA" => "Q",
  "CAG" => "Q",
  "AAT" => "N",
  "AAC" => "N",
  "CAT" => "H",
  "CAC" => "H",
  "GAA" => "E",
  "GAG" => "E",
  "GAT" => "D",
  "GAC" => "D",
  "AAA" => "K",
  "AAG" => "K",
  "CGT" => "R",
  "CGC" => "R",
  "CGA" => "R",
  "CGG" => "R",
  "AGA" => "R",
  "AGG" => "R",
  "TAA" => "*",
  "TAG" => "*",
  "TGA" => "*",
}
PIPE_MUTEX =
Mutex.new
OPEN_PIPE_IN =
[]
COLOR_LIST =
%w(#BC80BD #CCEBC5 #FFED6F #8DD3C7 #FFFFB3 #BEBADA #FB8072 #80B1D3 #FDB462 #B3DE69 #FCCDE5 #D9D9D9)
ARRAY_MAX_LENGTH =
1000
STRING_MAX_LENGTH =
ARRAY_MAX_LENGTH * 10
HASH2MD5_MAX_STRING_LENGTH =
1000
HASH2MD5_MAX_ARRAY_LENGTH =
100

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.sensiblewrite_dirObject

Returns the value of attribute sensiblewrite_dir.



4
5
6
# File 'lib/rbbt/util/misc/pipes.rb', line 4

def sensiblewrite_dir
  @sensiblewrite_dir
end

Class Method Details

.add_defaults(options, defaults = {}) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rbbt/util/misc/options.rb', line 112

def self.add_defaults(options, defaults = {})
  options ||= {}
  case
  when Hash === options
    new_options = options.dup
  when String === options
    new_options = string2hash options
  else
    raise "Format of '#{options.inspect}' not understood. It should be a hash"
  end

  defaults.each do |key, value|
    next if options.include? key

    new_options[key] = value 
  end

  new_options
end

.append_zipped(current, new) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rbbt/util/misc/objects.rb', line 37

def self.append_zipped(current, new)
  if current.empty?
    current.replace new.collect{|e| [e]}
  else
    current.each do |v|
      n = new.shift
      if Array === n
        v.concat new
      else
        v << n
      end
    end
  end
  current
end

.array2hash(array, default = nil) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/rbbt/util/misc/options.rb', line 24

def self.array2hash(array, default = nil)
  hash = {}
  array.each do |key, value|
    value = default.dup if value.nil? and not default.nil?
    hash[key] = value
  end
  hash
end

.benchmark(repeats = 1, message = nil) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/rbbt/util/misc/development.rb', line 14

def self.benchmark(repeats = 1, message = nil)
  require 'benchmark'
  res = nil
  begin
    measure = Benchmark.measure do
      repeats.times do
        res = yield
      end
    end
    if message
      puts "#{message }: #{ repeats } repeats"
    else
      puts "Benchmark for #{ repeats } repeats"
    end
    puts measure
  rescue Exception
    puts "Benchmark aborted"
    raise $!
  end
  res
end

.binary_include?(array, elem) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rbbt/util/misc/manipulation.rb', line 111

def self.binary_include?(array, elem)
  upper = array.size - 1
  lower = 0

  return -1 if upper < lower

  while(upper >= lower) do
    idx = lower + (upper - lower) / 2
    value = array[idx]

    case elem <=> value
    when 0
      return true
    when -1
      upper = idx - 1
    when 1
      lower = idx + 1
    else
      raise "Cannot compare #{[elem.inspect, value.inspect] * " with "}"
    end
  end

  return false
end

.camel_case(string) ⇒ Object



76
77
78
79
80
81
# File 'lib/rbbt/util/misc/format.rb', line 76

def self.camel_case(string)
  return string if string !~ /_/ && string =~ /[A-Z]+.*/
    string.split(/_|(\d+)/).map{|e| 
      (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize) 
    }.join
end

.camel_case_lower(string) ⇒ Object



83
84
85
86
87
# File 'lib/rbbt/util/misc/format.rb', line 83

def self.camel_case_lower(string)
    string.split('_').inject([]){ |buffer,e| 
      buffer.push(buffer.empty? ? e.downcase : (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize)) 
    }.join
end

.collapse_ranges(ranges) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/rbbt/util/misc/manipulation.rb', line 2

def self.collapse_ranges(ranges)
  processed = []
  last = nil
  final = []
  ranges.sort_by{|range| range.begin }.each do |range|
    rbegin = range.begin
    rend = range.end
    if last.nil? or rbegin > last
      processed << [rbegin, rend]
      last = rend
    else
     new_processed = []
      processed.each do |pbegin,pend|
        if pend < rbegin
          final << [pbegin, pend]
        else
          eend = [rend, pend].max
          new_processed << [pbegin, eend]
          break
        end
      end
      processed = new_processed
      last = rend if rend > last
    end
  end

  final.concat processed
  final.collect{|b,e| (b..e)}
end

.collapse_stream(s, line = nil, sep = "\t", header = nil) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/rbbt/util/misc/pipes.rb', line 287

def self.collapse_stream(s, line = nil, sep = "\t", header = nil)
  sep ||= "\t"
  Misc.open_pipe do |sin|
    sin.puts header if header
    process_stream(s) do |s|
      line ||= s.gets

      current_parts = []
      while line 
        key, *parts = line.strip.split(sep, -1)
        current_key ||= key
        case
        when key.nil?
        when current_key == key
          parts.each_with_index do |part,i|
            if current_parts[i].nil?
              current_parts[i] = part
            else
              current_parts[i] = current_parts[i] << "|" << part
            end
          end
        when current_key != key
          sin.puts [current_key, current_parts].flatten * sep
          current_key = key
          current_parts = parts
        end
        line = s.gets
      end

      sin.puts [current_key, current_parts].flatten * sep unless current_key.nil?
    end
  end
end

.colors_for(list) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/rbbt/util/misc/format.rb', line 4

def self.colors_for(list)
  unused = COLOR_LIST.dup

  used = {}
  colors = list.collect do |elem|
    if used.include? elem
      used[elem]
    else
      color = unused.shift
      used[elem]=color
      color
    end
  end

  [colors, used]
end

.common_path(dir, file) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rbbt/util/misc/system.rb', line 63

def self.common_path(dir, file)
  file = File.expand_path file
  dir = File.expand_path dir

  return true if file == dir
  while File.dirname(file) != file
    file = File.dirname(file)
    return true if file == dir
  end

  return false
end

.consolidate(list) ⇒ Object



26
27
28
29
30
31
32
33
34
35
# File 'lib/rbbt/util/misc/objects.rb', line 26

def self.consolidate(list)
  list.inject(nil){|acc,e|
    if acc.nil?
      acc = e
    else
      acc.concat e
      acc
    end
  }
end

.consume_stream(io, in_thread = false) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rbbt/util/misc/pipes.rb', line 148

def self.consume_stream(io, in_thread = false)
  return if Path === io
  return unless io.respond_to? :read 
  if io.respond_to? :closed? and io.closed?
    io.join if io.respond_to? :join
    return
  end

  Log.medium "Consuming stream #{Misc.fingerprint io}"
  if in_thread
    Thread.new do
      consume_stream(io, false)
    end
  else
    begin
      while block = io.read(2048)
      end
      io.join if io.respond_to? :join
    rescue Aborted
      Log.warn "Consume stream aborted #{Misc.fingerprint io}"
      io.abort if io.respond_to? :abort
    rescue Exception
      Log.warn "Exception consuming stream: #{Misc.fingerprint io}: #{$!.message}"
      io.abort if io.respond_to? :abort
      io.join
      raise $!
    end
  end
end

.correct_icgc_mutation(pos, ref, mut_str) ⇒ Object



119
120
121
122
123
124
# File 'lib/rbbt/util/misc/omics.rb', line 119

def self.correct_icgc_mutation(pos, ref, mut_str)
  mut = mut_str
  mut = '-' * (mut_str.length - 1) if mut =~/^-[ACGT]/
    mut = "+" << mut if ref == '-'
  [pos, [mut]]
end

.correct_vcf_mutation(pos, ref, mut_str) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/rbbt/util/misc/omics.rb', line 126

def self.correct_vcf_mutation(pos, ref, mut_str)
  muts = mut_str.nil? ? [] : mut_str.split(',')

  while ref.length >= 1 and muts.reject{|m| m[0] == ref[0]}.empty?
    ref = ref[1..-1]
    pos = pos + 1
    muts = muts.collect{|m| m[1..-1]}
  end

  muts = muts.collect do |m|
    case
    when ref.empty?
      "+" << m
    when (m.length < ref.length and (m.empty? or ref.index(m)))
      "-" * (ref.length - m.length)
    when (ref.length == 1 and m.length == 1)
      m
    else
      Log.debug{"Cannot understand: #{[ref, m]} (#{ muts })"}
      '-' * ref.length + m
    end
  end

  [pos, muts]
end

.counts(array) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/rbbt/util/misc/math.rb', line 32

def self.counts(array)
  counts = {}
  array.each do |e|
    counts[e] ||= 0
    counts[e] += 1
  end

  counts
end

.digest(text) ⇒ Object



108
109
110
# File 'lib/rbbt/util/misc/inspect.rb', line 108

def self.digest(text)
  Digest::MD5.hexdigest(text)
end

.divide(array, num) ⇒ Object

Divides the array into num chunks of the same size by placing one element in each chunk iteratively.



152
153
154
155
156
157
158
159
160
161
# File 'lib/rbbt/util/misc/development.rb', line 152

def self.divide(array, num)
  num = 1 if num == 0
  chunks = []
  num.to_i.times do chunks << [] end
  array.each_with_index{|e, i|
    c = i % num
    chunks[c] << e
  }
  chunks
end

.do_once(&block) ⇒ Object



108
109
110
111
112
113
# File 'lib/rbbt/util/misc/development.rb', line 108

def self.do_once(&block)
  return nil if $__did_once
  $__did_once = true
  yield
  nil
end

.dup_stream(stream) ⇒ Object



382
383
384
385
386
387
388
389
390
391
# File 'lib/rbbt/util/misc/pipes.rb', line 382

def self.dup_stream(stream)
  stream_dup = stream.dup
  if stream.respond_to? :annotate
    stream.annotate stream_dup
    stream.clear
  end
  tee1, tee2 = Misc.tee_stream stream_dup
  stream.reopen(tee1)
  tee2
end

.ensembl_server(organism) ⇒ Object



184
185
186
187
188
189
190
191
# File 'lib/rbbt/util/misc/omics.rb', line 184

def self.ensembl_server(organism)
  date = organism.split("/")[1]
  if date.nil?
    "www.ensembl.org"
  else
    "#{ date }.archive.ensembl.org"
  end
end

.env_add(var, value, sep = ":", prepend = true) ⇒ Object



38
39
40
41
42
43
44
45
46
# File 'lib/rbbt/util/misc/system.rb', line 38

def self.env_add(var, value, sep = ":", prepend = true)
  ENV[var] ||= ""
  return if ENV[var] =~ /(#{sep}|^)#{Regexp.quote value}(#{sep}|$)/
    if prepend
      ENV[var] = value + sep + ENV[var]
    else
      ENV[var] += sep + ENV[var]
    end
end

.field_position(fields, field, quiet = false) ⇒ Object

Raises:



58
59
60
61
62
63
64
65
# File 'lib/rbbt/util/misc/objects.rb', line 58

def self.field_position(fields, field, quiet = false)
  return field if Integer === field or Range === field
  raise FieldNotFoundError, "Field information missing" if fields.nil? && ! quiet
  fields.each_with_index{|f,i| return i if f == field}
  field_re = Regexp.new /^#{field}$/i
  fields.each_with_index{|f,i| return i if f =~ field_re}
  raise FieldNotFoundError, "Field #{ field.inspect } was not found" unless quiet
end

.filename?(string) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/rbbt/util/misc/system.rb', line 90

def self.filename?(string)
  String === string and string.length > 0 and string.length < 250 and File.exists?(string)
end

.fingerprint(obj) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rbbt/util/misc/inspect.rb', line 22

def self.fingerprint(obj)
  case obj
  when nil
    "nil"
  when (defined? Step and Step)
    obj.path || Misc.fingerprint([obj.task.name, obj.inputs])
  when TrueClass
    "true"
  when FalseClass
    "false"
  when Symbol
    ":" << obj.to_s
  when String
    if obj.length > 100
      "'" << obj.slice(0,20) << "<...#{obj.length}...>" << obj.slice(-10,10) << " " << "'"
    else 
      "'" << obj << "'"
    end
  when (defined? AnnotatedArray and AnnotatedArray)
    "<A: #{fingerprint Annotated.purge(obj)} #{fingerprint obj.info}>"
  when (defined? TSV and TSV::Parser)
    "<TSVStream:" + (obj.filename || "NOFILENAME") + "--" << Misc.fingerprint(obj.options) << ">"
  when IO
    (obj.respond_to?(:filename) and obj.filename ) ? "<IO:" + (obj.filename || obj.inspect) + ">" : obj.inspect
  when File
    "<File:" + obj.path + ">"
  when Array
    if (length = obj.length) > 10
      "[#{length}--" <<  (obj.values_at(0,1, length / 2, -2, -1).collect{|e| fingerprint(e)} * ",") << "]"
    else
      "[" << (obj.collect{|e| fingerprint(e) } * ",") << "]"
    end
  when (defined? TSV and TSV)
    obj.with_unnamed do
      "TSV:{"<< fingerprint(obj.all_fields|| []).inspect << ";" << fingerprint(obj.keys).inspect << "}"
    end
  when Hash
    if obj.length > 10
      "H:{"<< fingerprint(obj.keys) << ";" << fingerprint(obj.values) << "}"
    else
      new = "{"
      obj.each do |k,v|
        new << k.to_s << '=>' << fingerprint(v) << ' '
      end
      if new.length > 1
         new[-1] =  "}"
      else
        new << '}'
      end
      new
    end
  else
    obj.to_s
  end
end

.fixascii(string) ⇒ Object



144
145
146
147
148
149
150
# File 'lib/rbbt/util/misc/format.rb', line 144

def self.fixascii(string)
  if string.respond_to?(:encode)
    self.fixutf8(string).encode("ASCII-8BIT") 
  else
    string
  end
end

.fixutf8(string) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/rbbt/util/misc/format.rb', line 156

def self.fixutf8(string)
  return nil if string.nil?
  return string if (string.respond_to? :valid_encoding? and string.valid_encoding?) or
  (string.respond_to? :valid_encoding and string.valid_encoding)

  if string.respond_to?(:encode)
    string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
  else
    require 'iconv'
    @@ic ||= Iconv.new('UTF-8//IGNORE', 'UTF-8')
    @@ic.iconv(string)
  end
end

.format_definition_list(defs, size = 80, indent = 20, color = :yellow) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/rbbt/util/misc/format.rb', line 67

def self.format_definition_list(defs, size = 80, indent = 20, color = :yellow)
  entries = []
  defs.each do |dt,dd|
    text = format_definition_list_item(dt,dd,size,indent,color)
    entries << text
  end
  entries * "\n\n"
end

.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rbbt/util/misc/format.rb', line 49

def self.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow)
  dd = "" if dd.nil?
  dt = dt.to_s + ":" unless dd.empty?
  dt = Log.color color, dt if color
  len = Log.uncolor(dt).length

  if indent < 0
    text = format_paragraph(dd, size, indent.abs-1, 0)
    text = dt << "\n" << text
  else
    offset = len - indent
    offset = 0 if offset < 0
    text = format_paragraph(dd, size, indent.abs+1, offset)
    text[0..len-1] = dt
  end
  text
end

.format_paragraph(text, size = 80, indent = 0, offset = 0) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rbbt/util/misc/format.rb', line 21

def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
  i = 0
  re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
    text.split(re).collect do |paragraph|
    i += 1
    str = if i % 2 == 1
            words = paragraph.gsub(/\s+/, "\s").split(" ")
            lines = []
            line = " "*offset
            word = words.shift
            while word
              word = word[0..size-indent-offset-4] + '...' if word.length >= size - indent - offset
              while word and Log.uncolor(line).length + Log.uncolor(word).length <= size - indent
                line << word << " "
                word = words.shift
              end
              lines << ((" " * indent) << line[0..-2])
              line = ""
            end
            (lines * "\n")
          else
            paragraph
          end
    offset = 0
    str
    end*""
end

.GET_params2hash(string) ⇒ Object



54
55
56
57
58
59
60
61
# File 'lib/rbbt/util/misc/options.rb', line 54

def self.GET_params2hash(string)
  hash = {}
  string.split('&').collect{|item|
    key, value = item.split("=").values_at 0, 1
    hash[key] = value.nil? ? "" : CGI.unescape(value)
  }
  hash
end

.google_venn(list1, list2, list3, name1 = nil, name2 = nil, name3 = nil, total = nil) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rbbt/util/misc/math.rb', line 60

def self.google_venn(list1, list2, list3, name1 = nil, name2 = nil, name3 = nil, total = nil)
  name1 ||= "list 1"
  name2 ||= "list 2"
  name3 ||= "list 3"

  sizes = [list1, list2, list3, list1 & list2, list1 & list3, list2 & list3, list1 & list2 & list3].collect{|l| l.length}

  total = total.length if Array === total

  label = "#{name1}: #{sizes[0]} (#{name2}: #{sizes[3]}, #{name3}: #{sizes[4]})"
  label << "|#{name2}: #{sizes[1]} (#{name1}: #{sizes[3]}, #{name3}: #{sizes[5]})"
    label << "|#{name3}: #{sizes[2]} (#{name1}: #{sizes[4]}, #{name2}: #{sizes[5]})"
    if total
      label << "| INTERSECTION: #{sizes[6]} TOTAL: #{total}"
    else
      label << "| INTERSECTION: #{sizes[6]}"
    end

  max = total || sizes.max
  sizes = sizes.collect{|v| (v.to_f/max * 100).to_i.to_f / 100}
  url = "https://chart.googleapis.com/chart?cht=v&chs=500x300&chd=t:#{sizes * ","}&chco=FF6342,ADDE63,63C6DE,FFFFFF&chdl=#{label}"
end

.gzip(tarfile) ⇒ Object

gzips the underlying string in the given StringIO, returning a new StringIO representing the compressed file.



66
67
68
69
70
71
72
73
74
75
# File 'lib/rbbt/util/tar.rb', line 66

def self.gzip(tarfile)
  gz = StringIO.new("")
  z = Zlib::GzipWriter.new(gz)
  z.write tarfile.string
  z.close # this is necessary!

  # z was closed to write the gzip footer, so
  # now we need a new StringIO
  StringIO.new gz.string
end

.hash2GET_params(hash) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rbbt/util/misc/options.rb', line 63

def self.hash2GET_params(hash)
  hash.sort_by{|k,v| k.to_s}.collect{|k,v| 
    next unless %w(Symbol String Float Fixnum Integer TrueClass FalseClass Module Class Object Array).include? v.class.to_s
    v = case 
        when Symbol === v
          v.to_s
        when Array === v
          v * ","
        else
          CGI.escape(v.to_s)
        end
    [ Symbol === k ? k.to_s : k,  v] * "="
  }.compact * "&"
end

.hash2md5(hash) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/rbbt/util/misc/inspect.rb', line 114

def self.hash2md5(hash)
  str = ""
  keys = hash.keys
  keys = keys.clean_annotations if keys.respond_to? :clean_annotations
  keys = keys.sort_by{|k| k.to_s}

  if hash.respond_to? :unnamed
    unnamed = hash.unnamed
    hash.unnamed = true 
  end
  keys.each do |k|
    next if k == :monitor or k == "monitor" or k == :in_situ_persistence or k == "in_situ_persistence"
    v = hash[k]
    case
    when TrueClass === v
      str << k.to_s << "=>true" 
    when FalseClass === v
      str << k.to_s << "=>false" 
    when Hash === v
      str << k.to_s << "=>" << hash2md5(v)
    when Symbol === v
      str << k.to_s << "=>" << v.to_s
    when (String === v and v.length > HASH2MD5_MAX_STRING_LENGTH)
      str << k.to_s << "=>" << v[0..HASH2MD5_MAX_STRING_LENGTH] << "; #{ v.length }"
    when String === v
      str << k.to_s << "=>" << v
    when (Array === v and v.length > HASH2MD5_MAX_ARRAY_LENGTH)
      str << k.to_s << "=>[" << v[0..HASH2MD5_MAX_ARRAY_LENGTH] * "," << "; #{ v.length }]"
    when TSV::Parser === v
      str << remove_long_items(v)
    when Array === v
      str << k.to_s << "=>[" << v * "," << "]"
    when File === v
      str << k.to_s << "=>[File:" << v.path << "]"
    else
      v_ins = v.inspect

      case
      when v_ins =~ /:0x0/
        str << k.to_s << "=>" << v_ins.sub(/:0x[a-f0-9]+@/,'')
      else
        str << k.to_s << "=>" << v_ins
      end

    end

    str << "_" << hash2md5(v.info) if defined? Annotated and Annotated === v
  end
  hash.unnamed = unnamed if hash.respond_to? :unnamed

  if str.empty?
    ""
  else
    digest(str)
  end
end

.hash2string(hash) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/rbbt/util/misc/options.rb', line 46

def self.hash2string(hash)
  hash.sort_by{|k,v| k.to_s}.collect{|k,v| 
    next unless %w(Symbol String Float Fixnum Integer TrueClass FalseClass Module Class Object).include? v.class.to_s
    [ Symbol === k ? ":" << k.to_s : k,
      Symbol === v ? ":" << v.to_s : v] * "="
  }.compact * "#"
end

.hash_to_html_tag_attributes(hash) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rbbt/util/misc/options.rb', line 78

def self.hash_to_html_tag_attributes(hash)
  return "" if hash.nil? or hash.empty?
  hash.collect{|k,v| 
    case 
    when (k.nil? or v.nil? or (String === v and v.empty?))
      nil
    when Array === v
      [k,"'" << v * " " << "'"] * "="
    when String === v
      [k,"'" << v << "'"] * "="
    when Symbol === v
      [k,"'" << v.to_s << "'"] * "="
    when TrueClass === v
      [k,"'" << v.to_s << "'"] * "="
    when (Fixnum === v or Float === v)
      [k,"'" << v.to_s << "'"] * "="
    else
      nil
    end
  }.compact * " "
end

.hostnameObject



5
6
7
# File 'lib/rbbt/util/misc/system.rb', line 5

def self.hostname
  @hostanem ||= `hostname`.strip
end

.html_tag(tag, content = nil, params = {}) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rbbt/util/misc/options.rb', line 100

def self.html_tag(tag, content = nil, params = {})
  attr_str = hash_to_html_tag_attributes(params)
  attr_str = " " << attr_str if String === attr_str and attr_str != ""
  html = if content.nil?
    "<#{ tag }#{attr_str}/>"
  else
    "<#{ tag }#{attr_str}>#{ content }</#{ tag }>"
  end

  html
end

.humanize(value, options = {}) ⇒ Object

source: gist.github.com/ekdevdes/2450285 author: Ethan Kramer (github.com/ekdevdes)



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rbbt/util/misc/format.rb', line 101

def self.humanize(value, options = {})
  if options.empty?
    options[:format] = :sentence
  end

  values = []
  values = value.split('_')
  values.each_index do |index|
    # lower case each item in array
    # Miguel Vazquez edit: Except for acronyms
    values[index].downcase! unless values[index].match(/[a-zA-Z][A-Z]/)
  end
  if options[:format] == :allcaps
    values.each do |value|
      value.capitalize!
    end

    if options.empty?
      options[:seperator] = " "
    end

    return values.join " "
  end

  if options[:format] == :class
    values.each do |value|
      value.capitalize!
    end

    return values.join ""
  end

  if options[:format] == :sentence
    values[0].capitalize! unless values[0].match(/[a-zA-Z][A-Z]/)

    return values.join " "
  end

  if options[:format] == :nocaps
    return values.join " "
  end
end

.in_dir(dir) ⇒ Object

WARN: probably not thread safe…



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rbbt/util/misc/system.rb', line 77

def self.in_dir(dir)
  old_pwd = FileUtils.pwd
  res = nil
  begin
    FileUtils.mkdir_p dir unless File.exists? dir
    FileUtils.cd dir
    res = yield
  ensure
    FileUtils.cd old_pwd
  end
  res
end

.insist(times = 3, sleep = nil, msg = nil) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rbbt/util/misc/development.rb', line 119

def self.insist(times = 3, sleep = nil, msg = nil)
  if Array === times
    sleep_array = times
    times = sleep_array.length
    sleep = sleep_array.shift
  end
  try = 0
  begin
    yield
  rescue
    if msg
      Log.warn("Insisting after exception: #{$!.message} -- #{msg}")
    else
      Log.warn("Insisting after exception: #{$!.message}")
    end
    if sleep and try > 0
      sleep sleep
      sleep = sleep_array.shift if sleep_array
    else
      Thread.pass
    end
    try += 1
    retry if try < times
    raise $!
  end
end

.intersect_sorted_arrays(a1, a2) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rbbt/util/misc/manipulation.rb', line 60

def self.intersect_sorted_arrays(a1, a2)
  e1, e2 = a1.shift, a2.shift
  intersect = []
  while true
    break if e1.nil? or e2.nil?
    case e1 <=> e2
    when 0
      intersect << e1
      e1, e2 = a1.shift, a2.shift
    when -1
      e1 = a1.shift while not e1.nil? and e1 < e2
    when 1
      e2 = a2.shift
      e2 = a2.shift while not e2.nil? and e2 < e1
    end
  end
  intersect
end

.is_filename?(string) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
97
98
# File 'lib/rbbt/util/misc/system.rb', line 94

def self.is_filename?(string)
  return true if string.respond_to? :exists
  return true if String === string and string.length < 265 and File.exists? string
  return false
end

.IUPAC_to_base(iupac) ⇒ Object



152
153
154
# File 'lib/rbbt/util/misc/omics.rb', line 152

def self.IUPAC_to_base(iupac)
  IUPAC2BASE[iupac]
end

.lock(file, unlock = true, options = {}) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rbbt/util/misc/lock.rb', line 6

def self.lock(file, unlock = true, options = {})
  return yield if file.nil?
  FileUtils.mkdir_p File.dirname(File.expand_path(file)) unless File.exists?  File.dirname(File.expand_path(file))

  res = nil

  lock_path = File.expand_path(file + '.lock')
  lockfile = Lockfile.new(lock_path, options)

  hostname = Misc.hostname
  LOCK_MUTEX.synchronize do
    Misc.insist 2, 0.1 do
      Misc.insist 3, 0.1 do
        begin
          if File.exists? lock_path
            info = Open.open(lock_path){|f| YAML.load(f) }
            raise "No info" unless info

            if hostname == info["host"] and not Misc.pid_exists?(info["pid"])
              Log.high("Removing lockfile: #{lock_path}. This pid #{Process.pid}. Content: #{info.inspect}")
              FileUtils.rm lock_path
            end
          end
        rescue Exception
          FileUtils.rm lock_path if File.exists? lock_path
          lockfile = Lockfile.new(lock_path, options) unless File.exists? lock_path
          raise $!
        end
      end
    end
    lockfile.lock 
  end

  begin
    res = yield lockfile
  rescue Lockfile::StolenLockError
    unlock = false
  rescue KeepLocked
    unlock = false
    res = $!.payload
  rescue Exception
    lockfile.unlock if lockfile.locked?
    raise $!
  ensure
    if unlock 
      lockfile.unlock if lockfile.locked?
    end
  end

  res
end

.lock_in_repo(repo, key, *args) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rbbt/util/misc/lock.rb', line 60

def self.lock_in_repo(repo, key, *args)
  return yield file, *args if repo.nil? or key.nil?

  lock_key = "lock-" << key

  begin
    if repo[lock_key] and
      Misc.hostname == (info = LOCK_REPO_SERIALIZER.load(repo[lock_key]))["host"] and 
      info["pid"] and not Misc.pid_exists?(info["pid"])

      Log.info("Removing lockfile: #{lock_key}. This pid #{Process.pid}. Content: #{info.inspect}")
      repo.out lock_key 
    end
  rescue
    Log.warn("Error checking lockfile #{lock_key}: #{$!.message}. Removing. Content: #{begin repo[lock_key] rescue "Could not open file" end}")
    repo.out lock_key if repo.include? lock_key
  end

  while repo[lock_key]
    sleep 1
  end
  
  repo[lock_key] = LOCK_REPO_SERIALIZER.dump({:hostname => Misc.hostname, :pid => Process.pid})

  res = yield lock_key, *args

  repo.delete lock_key

  res
end

.log2(x) ⇒ Object



5
6
7
# File 'lib/rbbt/util/misc/math.rb', line 5

def self.log2(x)
  Math.log(x) * Log2Multiplier
end

.max(list) ⇒ Object



9
10
11
12
13
14
15
16
# File 'lib/rbbt/util/misc/math.rb', line 9

def self.max(list)
  max = nil
  list.each do |v|
    next if v.nil?
    max = v if max.nil? or v > max
  end
  max
end

.mean(list) ⇒ Object



22
23
24
# File 'lib/rbbt/util/misc/math.rb', line 22

def self.mean(list)
  sum(list) / list.compact.length
end

.memprofObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rbbt/util/misc/development.rb', line 92

def self.memprof
  require 'memprof'
  Memprof.start
  begin
    res = yield
  rescue Exception
    puts "Profiling aborted"
    raise $!
  ensure
    Memprof.stop
    print Memprof.stats
  end

  res
end

.merge_sorted_arrays(a1, a2) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/rbbt/util/misc/manipulation.rb', line 79

def self.merge_sorted_arrays(a1, a2)
  e1, e2 = a1.shift, a2.shift
  new = []
  while true
    case
    when (e1 and e2)
      case e1 <=> e2
      when 0
        new << e1 
        e1, e2 = a1.shift, a2.shift
      when -1
        new << e1
        e1 = a1.shift
      when 1
        new << e2
        e2 = a2.shift
      end
    when e2
      new << e2
      new.concat a2
      break
    when e1
      new << e1
      new.concat a1
      break
    else
      break
    end
  end
  new
end

.open_pipe(do_fork = false, close = true) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rbbt/util/misc/pipes.rb', line 40

def self.open_pipe(do_fork = false, close = true)
  raise "No block given" unless block_given?

  sout, sin = Misc.pipe

  if do_fork
    parent_pid = Process.pid
    pid = Process.fork {
      purge_pipes(sin)
      sout.close
      begin
        yield sin
        sin.close if close and not sin.closed? 
      rescue
        Log.exception $!
        Process.kill :INT, parent_pid
        Kernel.exit! -1
      end
      Kernel.exit! 0
    }
    sin.close 
    ConcurrentStream.setup sout, :pids => [pid]
  else
    thread = Thread.new(Thread.current) do |parent|
      begin
        yield sin
        sin.close if close and not sin.closed?
      rescue Exception
        Log.warn "Exception in open_pipe: #{$!.message}"
        raise $!
      end
    end
    ConcurrentStream.setup sout, :threads => [thread]
  end
  sout
end

.ordered_divide(array, num) ⇒ Object

Divides the array into chunks of num same size by placing one element in each chunk iteratively.



165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rbbt/util/misc/development.rb', line 165

def self.ordered_divide(array, num)
  last = array.length - 1
  chunks = []
  current = 0
  while current <= last
    next_current = [last, current + num - 1].min
    chunks << array[current..next_current]
    current = next_current + 1
  end
  chunks
end

.parse_cmd_params(str) ⇒ Object



3
4
5
6
7
8
9
# File 'lib/rbbt/util/misc/options.rb', line 3

def self.parse_cmd_params(str)
  return str if Array === str
  str.scan(/
           (?:["']([^"']*?)["']) |
           ([^"'\s]+)
  /x).flatten.compact
end

.paste_streams(streams, lines = nil, sep = "\t", header = nil) ⇒ Object



321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/rbbt/util/misc/pipes.rb', line 321

def self.paste_streams(streams, lines = nil, sep = "\t", header = nil)
  sep ||= "\t"
  num_streams = streams.length
  Misc.open_pipe do |sin|
    sin.puts header if header
    streams = streams.collect do |stream|
      if defined? Step and Step === stream
        stream.get_stream || stream.join.path.open
      else
        stream
      end
    end

    begin
      done_streams = []
      lines ||= streams.collect{|s| s.gets }
      keys = []
      parts = []
      lines.each_with_index do |line,i|
        key, *p = line.strip.split(sep, -1) 
        keys[i] = key
        parts[i] = p
      end
      sizes = parts.collect{|p| p.length }
      last_min = nil
      while lines.compact.any?
        min = keys.compact.sort.first
        str = []
        keys.each_with_index do |key,i|
          case key
          when min
            str << [parts[i] * sep]
            line = lines[i] = streams[i].gets
            if line.nil?
              keys[i] = nil
              parts[i] = nil
            else
              k, *p = line.strip.split(sep, -1)
              keys[i] = k
              parts[i] = p
            end
          else
            str << [sep * (sizes[i]-1)] if sizes[i] > 0
          end
        end

        sin.puts [min, str*sep] * sep
      end
      streams.each do |stream|
        stream.join if stream.respond_to? :join
      end
    rescue 
      Log.exception $!
      streams.each do |stream|
        stream.abort if stream.respond_to? :abort
      end
      raise $!
    end
  end
end

.path_relative_to(basedir, path) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rbbt/util/misc/system.rb', line 48

def self.path_relative_to(basedir, path)
  path = File.expand_path(path) unless path[0] == "/"
  basedir = File.expand_path(basedir) unless basedir[0] == "/"

  if path.index(basedir) == 0
    if basedir[-1] == "/"
      return path[basedir.length..-1]
    else
      return path[basedir.length+1..-1]
    end
  else
    return nil
  end
end

.pid_exists?(pid) ⇒ Boolean

Returns:

  • (Boolean)


9
10
11
12
13
14
15
16
17
# File 'lib/rbbt/util/misc/system.rb', line 9

def self.pid_exists?(pid)
  return false if pid.nil?
  begin
    Process.getpgid(pid.to_i)
    true
  rescue Errno::ESRCH
    false
  end
end

.pipeObject



13
14
15
16
17
18
19
20
21
# File 'lib/rbbt/util/misc/pipes.rb', line 13

def self.pipe
  OPEN_PIPE_IN.delete_if{|pipe| pipe.closed? }
  PIPE_MUTEX.synchronize do
    sout, sin = IO.pipe
    OPEN_PIPE_IN << sin

    [sout, sin]
  end
end

.positional2hash(keys, *values) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/rbbt/util/misc/options.rb', line 11

def self.positional2hash(keys, *values)
  if Hash === values.last
    extra = values.pop
    inputs = Misc.zip2hash(keys, values)
    inputs.delete_if{|k,v| v.nil? or (String === v and v.empty?)}
    inputs = Misc.add_defaults inputs, extra
    inputs.delete_if{|k,v| not keys.include?(k) and not (Symbol === k ? keys.include?(k.to_s) : keys.include?(k.to_sym))}
    inputs
  else
    Misc.zip2hash(keys, values)
  end
end

.prepare_entity(entity, field, options = {}) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/rbbt/util/misc/objects.rb', line 3

def self.prepare_entity(entity, field, options = {})
  return entity unless defined? Entity
  return entity unless String === entity or Array === entity
  options ||= {}

  dup_array = options.delete :dup_array

  if Annotated === field or (Entity.respond_to?(:formats) and Entity.formats.include? field)
    params = options.dup

    params[:format] ||= params.delete "format"
    params.merge!(:format => field) unless params.include?(:format) and not ((f = params[:format]).nil? or (String === f and f.empty?))

    mod = Entity === field ? field : Entity.formats[field]
    entity = mod.setup(
      ((entity.frozen? and not entity.nil?) ? entity.dup : ((Array === entity and dup_array) ? entity.collect{|e| e.nil? ? e : e.dup} : entity) ),
      params
    ) 
  end

  entity
end

.process_options(hash, *keys) ⇒ Object



132
133
134
135
136
137
138
# File 'lib/rbbt/util/misc/options.rb', line 132

def self.process_options(hash, *keys)
  if keys.length == 1
    hash.include?(keys.first.to_sym) ? hash.delete(keys.first.to_sym) : hash.delete(keys.first.to_s) 
  else
    keys.collect do |key| hash.include?(key.to_sym) ? hash.delete(key.to_sym) : hash.delete(key.to_s) end
  end
end

.process_stream(s) ⇒ Object



237
238
239
240
241
242
243
244
245
# File 'lib/rbbt/util/misc/pipes.rb', line 237

def self.process_stream(s)
  begin
    yield s
    s.join if s.respond_to? :join
  rescue
    s.abort if s.respond_to? :abort
    raise $!
  end
end

.process_to_hash(list) ⇒ Object



41
42
43
44
# File 'lib/rbbt/util/misc/options.rb', line 41

def self.process_to_hash(list)
  result = yield list
  zip2hash(list, result)
end

.profile(options = {}) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rbbt/util/misc/development.rb', line 75

def self.profile(options = {})
  require 'ruby-prof'
  RubyProf.start
  begin
    res = yield
  rescue Exception
    puts "Profiling aborted"
    raise $!
  ensure
    result = RubyProf.stop
    printer = RubyProf::FlatPrinter.new(result)
    printer.print(STDOUT, options)
  end

  res
end

.profile_graph(options = {}) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rbbt/util/misc/development.rb', line 57

def self.profile_graph(options = {})
  require 'ruby-prof'
  RubyProf.start
  begin
    res = yield
  rescue Exception
    puts "Profiling aborted"
    raise $!
  ensure
    result = RubyProf.stop
    #result.eliminate_methods!([/annotated_array_clean_/])
    printer = RubyProf::GraphPrinter.new(result)
    printer.print(STDOUT, options)
  end

  res
end

.profile_html(options = {}) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rbbt/util/misc/development.rb', line 36

def self.profile_html(options = {})
  require 'ruby-prof'
  RubyProf.start
  begin
    res = yield
  rescue Exception
    puts "Profiling aborted"
    raise $!
  ensure
    result = RubyProf.stop
    printer = RubyProf::MultiPrinter.new(result)
    TmpFile.with_file do |dir|
      FileUtils.mkdir_p dir unless File.exists? dir
      printer.print(:path => dir, :profile => 'profile')
      CMD.cmd("firefox  -no-remote  '#{ dir }'")
    end
  end

  res
end

.proportions(array) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rbbt/util/misc/math.rb', line 42

def self.proportions(array)
  total = array.length

  proportions = Hash.new 0

  array.each do |e|
    proportions[e] += 1.0 / total
  end

  class << proportions; self;end.class_eval do
    def to_s
      sort{|a,b| a[1] == b[1] ? a[0] <=> b[0] : a[1] <=> b[1]}.collect{|k,c| "%3d\t%s" % [c, k]} * "\n"
    end
  end

  proportions
end

.pull_keys(hash, prefix) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rbbt/util/misc/options.rb', line 140

def self.pull_keys(hash, prefix)
  new = {}
  hash.keys.each do |key|
    if key.to_s =~ /#{ prefix }_(.*)/
      case
      when String === key
        new[$1] = hash.delete key
      when Symbol === key
        new[$1.to_sym] = hash.delete key
      end
    else
      if key.to_s == prefix.to_s
        new[key] = hash.delete key
      end
    end
  end

  new
end

.purge_pipes(*save) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/rbbt/util/misc/pipes.rb', line 31

def self.purge_pipes(*save)
  PIPE_MUTEX.synchronize do
    OPEN_PIPE_IN.each do |pipe|
      next if save.include? pipe
      pipe.close unless pipe.closed?
    end
  end
end

.random_sample_in_range(total, size) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/rbbt/util/misc/development.rb', line 177

def self.random_sample_in_range(total, size)
  p = Set.new

  if size > total / 10
    template = (0..total - 1).to_a
    size.times do |i|
      pos = (rand * (total - i)).floor
      if pos == template.length - 1
        v = template.pop
      else
        v, n = template[pos], template[-1]
        template.pop
        template[pos] = n 
      end
      p << v
    end
  else
    size.times do 
      pos = nil
      while pos.nil? 
        pos = (rand * total).floor
        if p.include? pos
          pos = nil
        end
      end
      p << pos
    end
  end
  p
end

.read_full_stream(io) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rbbt/util/misc/pipes.rb', line 135

def self.read_full_stream(io)
  str = ""
  begin
    while block = io.read(2048)
      str << block
    end
    io.join if io.respond_to? :join
  rescue
    io.abort if io.respond_to? :abort
  end
  str
end

.read_stream(stream, size) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rbbt/util/misc/pipes.rb', line 178

def self.read_stream(stream, size)
  str = nil
  Thread.pass while IO.select([stream],nil,nil,1).nil?
  while not str = stream.read(size)
    IO.select([stream],nil,nil,1) 
    Thread.pass
    raise ClosedStream if stream.eof?
  end

  while str.length < size
    raise ClosedStream if stream.eof?
    IO.select([stream],nil,nil,1)
    if new = stream.read(size-str.length)
      str << new
    end
  end
  str
end

.release_pipes(*pipes) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/rbbt/util/misc/pipes.rb', line 23

def self.release_pipes(*pipes)
  PIPE_MUTEX.synchronize do
    pipes.flatten.each do |pipe|
      pipe.close unless pipe.closed?
    end
  end
end

.remove_long_items(obj) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rbbt/util/misc/inspect.rb', line 79

def self.remove_long_items(obj)
  case
  when IO === obj
    remove_long_items("IO: " + (obj.respond_to?(:filename) ? (obj.filename || obj.inspect) : obj.inspect ))
  when obj.respond_to?(:path)
    remove_long_items("File: " + obj.path)
  when TSV::Parser === obj
    remove_long_items("TSV Stream: " + obj.filename + " -- " << Misc.fingerprint(obj.options))
  when TSV === obj
    remove_long_items((obj.all_fields || []) + obj.keys.sort)
  when (Array === obj and obj.length > ARRAY_MAX_LENGTH)
    remove_long_items(obj[0..ARRAY_MAX_LENGTH-2] << "TRUNCATED at #{ ARRAY_MAX_LENGTH } (#{obj.length})")
  when (Hash === obj and obj.length > ARRAY_MAX_LENGTH)
    remove_long_items(obj.collect.compact[0..ARRAY_MAX_LENGTH-2] << ["TRUNCATED", "at #{ ARRAY_MAX_LENGTH } (#{obj.length})"])
  when (String === obj and obj.length > STRING_MAX_LENGTH)
    obj[0..STRING_MAX_LENGTH-1] << " TRUNCATED at #{STRING_MAX_LENGTH} (#{obj.length})"
  when Hash === obj
    new = {}
    obj.each do |k,v|
      new[k] = remove_long_items(v)
    end
    new
  when Array === obj
    obj.collect do |e| remove_long_items(e) end
  else
    obj
  end
end

.reset_do_onceObject



115
116
117
# File 'lib/rbbt/util/misc/development.rb', line 115

def self.reset_do_once
  $__did_once = false
end

.sample(ary, size, replacement = false) ⇒ Object



208
209
210
211
212
213
214
215
216
# File 'lib/rbbt/util/misc/development.rb', line 208

def self.sample(ary, size, replacement = false)
  if ary.respond_to? :sample
    ary.sample size
  else
    total = ary.length
    p = random_sample_in_range(total, size)
    ary.values_at *p
  end
end

.sanitize_filename(filename, length = 254) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/rbbt/util/misc/inspect.rb', line 5

def self.sanitize_filename(filename, length = 254)
  if filename.length > length
    if filename =~ /(\..{2,9})$/
      extension = $1
    else
      extension = ''
    end

    post_fix = "--#{filename.length}@#{length}_#{Misc.digest(filename)[0..4]}" + extension

    filename = filename[0..(length - post_fix.length - 1)] << post_fix
  else
    filename
  end
  filename
end

.save_stream(file, stream) ⇒ Object



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/rbbt/util/misc/pipes.rb', line 393

def self.save_stream(file, stream)
  out, save = Misc.tee_stream stream

  Thread.new(Thread.current) do |parent|
    begin
      Misc.sensiblewrite(file, save)
    rescue Exception
      save.abort if save.respond_to? :abort
      stream.abort if stream.respond_to? :abort
      stream.join
      Log.warn "Exception in save_stream: #{$!.message}"
      raise $!
    end
  end

  out
end

.sd(list) ⇒ Object



26
27
28
29
30
# File 'lib/rbbt/util/misc/math.rb', line 26

def self.sd(list)
  return nil if list.length < 3
  mean = mean(list)
  Math.sqrt(list.compact.inject(0.0){|acc,e| d = e - mean; acc += d * d}) / (list.compact.length - 1)
end

.send_email(from, to, subject, message, options = {}) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/rbbt/util/misc/system.rb', line 19

def self.send_email(from, to, subject, message, options = {})
  IndiferentHash.setup(options)
  options = Misc.add_defaults options, :from_alias => nil, :to_alias => nil, :server => 'localhost', :port => 25, :user => nil, :pass => nil, :auth => :login

  server, port, user, pass, from_alias, to_alias, auth = Misc.process_options options, :server, :port, :user, :pass, :from_alias, :to_alias, :auth

  msg = <<-END_OF_MESSAGE
From: #{from_alias} <#{from}>
To: #{to_alias} <#{to}>
Subject: #{subject}

#{message}
END_OF_MESSAGE

Net::SMTP.start(server, port, server, user, pass, auth) do |smtp|
smtp.send_message msg, from, to
end
end

.sensiblewrite(path, content = nil, &block) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/rbbt/util/misc/pipes.rb', line 197

def self.sensiblewrite(path, content = nil, &block)

  return if Open.exists? path
  tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
  Misc.lock tmp_path do
    if not Open.exists? path
      FileUtils.rm_f tmp_path if File.exists? tmp_path
      begin
        case
        when block_given?
          File.open(tmp_path, 'w', &block)
        when String === content
          File.open(tmp_path, 'w') do |f| f.write content end
        when (IO === content or StringIO === content or File === content)
          File.open(tmp_path, 'w') do |f|  
            while block = content.read(2048); 
              f.write block
            end  
          end
        else
          File.open(tmp_path, 'w') do |f|  end
        end

        Open.mv tmp_path, path
      rescue Aborted
        Log.warn "Aborted sensiblewrite -- #{ Log.reset << Log.color(:blue, path) }"
        content.abort if content.respond_to? :abort
        Open.rm path if File.exists? path
      rescue Exception
        Log.warn "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
        content.abort if content.respond_to? :abort
        Open.rm path if File.exists? path
        raise $!
      ensure
        FileUtils.rm_f tmp_path if File.exists? tmp_path
      end
    end
  end
end

.snake_case(string) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'lib/rbbt/util/misc/format.rb', line 89

def self.snake_case(string)
  return nil if string.nil?
  string = string.to_s if Symbol === string
  string.
    gsub(/([A-Z]{2,})([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z])([A-Z])/,'\1_\2').
    gsub(/\s/,'_').gsub(/[^\w_]/, '').
    split("_").collect{|p| p.match(/[A-Z]{2,}/) ? p : p.downcase } * "_"
end

.sort_mutations(mutations) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/rbbt/util/misc/omics.rb', line 157

def self.sort_mutations(mutations)
  mutations.collect do |mutation|
    chr,pos,mut = mutation.split ":"
    chr.sub!(/^chr/i,'')
    chr = 22 if chr == "Y"
    chr = 23 if chr == "X"
    chr = 24 if chr == "MT" or chr == "M"
    [chr.to_i, pos.to_i, mut, mutation]
  end.sort do |a,b|
    case a[0] <=> b[0]
    when -1
      -1
    when 1
      1
    when 0
      case a[1] <=> b[1]
      when -1
        -1
      when 1
        1
      when 0
        a[2] <=> b[2]
      end
    end
  end.collect{|p| p.last }
end

.sort_stream(stream, header_hash = "#", cmd_args = nil) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/rbbt/util/misc/pipes.rb', line 247

def self.sort_stream(stream, header_hash = "#", cmd_args = nil)
  Misc.open_pipe do |sin|
    begin
      if defined? Step and Step === stream
        step = stream
        stream = stream.get_stream || stream.path.open
      end

      line = stream.gets
      while line =~ /^#{header_hash}/ do
        sin.puts line
        line = stream.gets
      end

      line_stream = Misc.open_pipe do |line_stream_in|
        begin
          while line
            line_stream_in.puts line
            line = stream.gets
          end
          stream.join if stream.respond_to? :join
        rescue
          stream.abort if stream.respond_to? :abort
          raise $!
        end
      end

      sorted = CMD.cmd("sort #{cmd_args || ""}", :in => line_stream, :pipe => true)

      while block = sorted.read(2048)
        sin.write block
      end
    rescue
      if defined? step and step
        step.abort
      end
    end
  end
end

.sorted_array_hits(a1, a2) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rbbt/util/misc/manipulation.rb', line 36

def self.sorted_array_hits(a1, a2)
  e1, e2 = a1.shift, a2.shift
  counter = 0
  match = []
  while true
    break if e1.nil? or e2.nil?
    case e1 <=> e2
    when 0
      match << counter
      e1, e2 = a1.shift, a2.shift
      counter += 1
    when -1
      while not e1.nil? and e1 < e2
        e1 = a1.shift 
        counter += 1
      end
    when 1
      e2 = a2.shift
      e2 = a2.shift while not e2.nil? and e2 < e1
    end
  end
  match
end

.string2const(string) ⇒ Object



3
4
5
6
7
8
9
10
11
12
# File 'lib/rbbt/util/misc/development.rb', line 3

def self.string2const(string)
  return nil if string.nil?
  mod = Kernel

  string.to_s.split('::').each do |str|
    mod = mod.const_get str
  end

  mod
end

.string2hash(string) ⇒ Object

options end



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/rbbt/util/misc/options.rb', line 206

def self.string2hash(string)
  options = {}

  string.split('#').each do |str|
    key, sep, value = str.partition "="

    key = key[1..-1].to_sym if key[0] == ":"

    options[key] = true and next if value.empty?
    options[key] = value[1..-1].to_sym and next if value[0] == ":"
    options[key] = Regexp.new(/#{value[1..-2]}/) and next if value[0] == "/" and value[-1] == "/"
    options[key] = value[1..-2] and next if value =~ /^['"].*['"]$/
    options[key] = value.to_i and next if value =~ /^\d+$/
    options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
    options[key] = true and next if value == "true"
    options[key] = false and next if value == "false"
    options[key] = value and next 

    options[key] = begin
                     saved_safe = $SAFE
                     $SAFE = 0
                     eval(value)
                   rescue Exception
                     value
                   ensure
                     $SAFE = saved_safe
                   end
  end

  return options

  options = {}
  string.split(/#/).each do |str|
    if str.match(/(.*)=(.*)/)
      option, value = $1, $2
    else
      option, value = str, true
    end

    option = option.sub(":",'').to_sym if option.chars.first == ':'
    value  = value.sub(":",'').to_sym if String === value and value.chars.first == ':'

    if value == true
      options[option] = option.to_s.chars.first != '!' 
    else
      options[option] = Thread.start do
        $SAFE = 0;
        case 
        when value =~ /^(?:true|T)$/i
          true
        when value =~ /^(?:false|F)$/i
          false
        when Symbol === value
          value
        when (String === value and value =~ /^\/(.*)\/$/)
          Regexp.new /#{$1}/
        else
          begin
            Kernel.const_get value
          rescue
            begin  
              raise if value =~ /[a-z]/ and defined? value
              eval(value) 
            rescue Exception
              value 
            end
          end
        end
      end.value
    end
  end

  options
end

.sum(list) ⇒ Object



18
19
20
# File 'lib/rbbt/util/misc/math.rb', line 18

def self.sum(list)
  list.compact.inject(0.0){|acc,e| acc += e}
end

.tar(path, tarfile = nil) ⇒ Object

Creates a tar file in memory recursively from the given path.

Returns a StringIO whose underlying String is the contents of the tar file.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/rbbt/util/tar.rb', line 14

def self.tar(path, tarfile = nil)
  tarfile ||= StringIO.new("")

  Gem::Package::TarWriter.new(tarfile) do |tar|
    Dir[File.join(path, "**/*")].each do |file|
      mode = File.stat(file).mode
      relative_file = file.sub /^#{Regexp::escape path}\/?/, ''

      if File.directory?(file)
        tar.mkdir relative_file, mode
      else
        tar.add_file relative_file, mode do |tf|
          File.open(file, "rb") { |f| tf.write f.read }
        end
      end
    end
  end

  tarfile.rewind

  tarfile
end

.tarize(path) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rbbt/util/tar.rb', line 37

def self.tarize(path, gz = nil)
  gz ||= StringIO.new('wb')

  tar =  Misc.in_dir(path) do self.tar('.') end

  tar.rewind

  string = tar.string

  z = Zlib::GzipWriter.new(gz)
  z.write string
  z.close

  gz.reopen('read')
  gz.rewind


  gz
end

.tee_stream_thread(stream) ⇒ Object Also known as: tee_stream



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rbbt/util/misc/pipes.rb', line 77

def self.tee_stream_thread(stream)
  stream_out1, stream_in1 = Misc.pipe
  stream_out2, stream_in2 = Misc.pipe

  splitter_thread = Thread.new(Thread.current) do |parent|
    begin
      filename = stream.respond_to?(:filename)? stream.filename : nil
      skip1 = skip2 = false
      while block = stream.read(2048)
        begin 
          stream_in1.write block; 
        rescue IOError
          Log.warn("Tee stream 1 #{Misc.fingerprint stream} IOError: #{$!.message}");
          skip1 = true
        end unless skip1 

        begin 
          stream_in2.write block
        rescue IOError
          Log.warn("Tee stream 2 #{Misc.fingerprint stream} IOError: #{$!.message}");
          skip2 = true
        end unless skip2 
      end
      stream_in1.close unless stream_in1.closed?
      stream_in2.close unless stream_in2.closed?
      stream.join if stream.respond_to? :join
    rescue Aborted, Interrupt
      Log.warn "Tee aborting #{Misc.fingerprint stream}"
      stream.abort if stream.respond_to? :abort
      stream_out1.abort if stream_out1.respond_to? :abort
      stream_out2.abort if stream_out2.respond_to? :abort
      Log.warn "tee_stream_thread aborted: #{$!.message}"
    rescue Exception
      stream.abort if stream.respond_to? :abort
      stream_out1.abort if stream_out1.respond_to? :abort
      stream_out2.abort if stream_out2.respond_to? :abort
      stream.join
      Log.warn "Exception in tee_stream_thread: #{$!.message}"
      raise $!
    end
  end

  ConcurrentStream.setup stream_out1, :threads => splitter_thread
  ConcurrentStream.setup stream_out2, :threads => splitter_thread

  stream_out1.callback = stream.callback if stream.respond_to? :callback
  stream_out1.abort_callback = stream.abort_callback if stream.respond_to? :abort_callback

  stream_out2.callback = stream.callback if stream.respond_to? :callback
  stream_out2.abort_callback = stream.abort_callback if stream.respond_to? :abort_callback

  [stream_out1, stream_out2]
end

.to_utf8(string) ⇒ Object



152
153
154
# File 'lib/rbbt/util/misc/format.rb', line 152

def self.to_utf8(string)
  string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
end

.total_length(ranges) ⇒ Object



32
33
34
# File 'lib/rbbt/util/misc/manipulation.rb', line 32

def self.total_length(ranges)
  self.collapse_ranges(ranges).inject(0) do |total,range| total += range.end - range.begin + 1 end
end

.try3times(&block) ⇒ Object



146
147
148
# File 'lib/rbbt/util/misc/development.rb', line 146

def self.try3times(&block)
  insist(3, &block)
end

.zip2hash(list1, list2) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/rbbt/util/misc/options.rb', line 33

def self.zip2hash(list1, list2)
  hash = {}
  list1.each_with_index do |e,i|
    hash[e] = list2[i]
  end
  hash
end

.zip_fields(array) ⇒ Object



53
54
55
56
# File 'lib/rbbt/util/misc/objects.rb', line 53

def self.zip_fields(array)
  return [] if array.empty? or (first = array.first).nil?
  first.zip(*array[1..-1])
end

Instance Method Details

#ungzip(tarfile) ⇒ Object

un-gzips the given IO, returning the decompressed version as a StringIO



79
80
81
82
83
84
# File 'lib/rbbt/util/tar.rb', line 79

def ungzip(tarfile)
  z = Zlib::GzipReader.new(tarfile)
  unzipped = StringIO.new(z.read)
  z.close
  unzipped
end

#untar(io, destination) ⇒ Object

untars the given IO into the specified directory



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rbbt/util/tar.rb', line 88

def untar(io, destination)
  Gem::Package::TarReader.new io do |tar|
    tar.each do |tarfile|
      destination_file = File.join destination, tarfile.full_name

      if tarfile.directory?
        FileUtils.mkdir_p destination_file
      else
        destination_directory = File.dirname(destination_file)
        FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
        File.open destination_file, "wb" do |f|
          f.print tarfile.read
        end
      end
    end
  end
end