rbbt-util 5.11.4 → 5.11.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ module ConcurrentStream
2
+ attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined
3
+
4
+ def joined?
5
+ @joined
6
+ end
7
+
8
+ def join
9
+
10
+ if @threads and @threads.any?
11
+ @threads.each do |t|
12
+ t.join unless t == Thread.current
13
+ end
14
+ @threads = []
15
+ end
16
+
17
+ if @pids and @pids.any?
18
+ @pids.each do |pid|
19
+ begin
20
+ Process.waitpid(pid, Process::WUNTRACED)
21
+ raise "Error joining process #{pid} in #{self.inspect}" unless $?.success?
22
+ rescue Errno::ECHILD
23
+ end
24
+ end
25
+ @pids = []
26
+ end
27
+
28
+ if @callback and not joined?
29
+ @callback.call
30
+ @callback = nil
31
+ end
32
+
33
+ @joined = true
34
+ end
35
+
36
+ def abort
37
+ @threads.each{|t| t.raise Aborted.new unless t = Thread.current } if @threads
38
+ @threads.each{|t| t.join unless t = Thread.current } if @threads
39
+ @pids.each{|pid| Process.kill :INT, pid } if @pids
40
+ @pids.each{|pid| Process.waitpid pid } if @pids
41
+ @abort_callback.call if @abort_callback
42
+ @abort_callback = nil
43
+ end
44
+
45
+ def self.setup(stream, options = {}, &block)
46
+ threads, pids, callback, filename = Misc.process_options options, :threads, :pids, :callback, :filename
47
+ stream.extend ConcurrentStream unless ConcurrentStream === stream
48
+
49
+ stream.threads ||= []
50
+ stream.pids ||= []
51
+ stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
52
+ stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
53
+
54
+ callback = block if block_given?
55
+ if stream.callback and callback
56
+ old_callback = stream.callback
57
+ stream.callback = Proc.new do
58
+ old_callback.call
59
+ callback.call
60
+ end
61
+ else
62
+ stream.callback = callback
63
+ end
64
+
65
+ stream.filename = filename unless filename.nil?
66
+
67
+ stream
68
+ end
69
+ end
@@ -0,0 +1,95 @@
1
+ module Misc
2
+ def self.benchmark(repeats = 1, message = nil)
3
+ require 'benchmark'
4
+ res = nil
5
+ begin
6
+ measure = Benchmark.measure do
7
+ repeats.times do
8
+ res = yield
9
+ end
10
+ end
11
+ if message
12
+ puts "#{message }: #{ repeats } repeats"
13
+ else
14
+ puts "Benchmark for #{ repeats } repeats"
15
+ end
16
+ puts measure
17
+ rescue Exception
18
+ puts "Benchmark aborted"
19
+ raise $!
20
+ end
21
+ res
22
+ end
23
+
24
+ def self.profile_html(options = {})
25
+ require 'ruby-prof'
26
+ RubyProf.start
27
+ begin
28
+ res = yield
29
+ rescue Exception
30
+ puts "Profiling aborted"
31
+ raise $!
32
+ ensure
33
+ result = RubyProf.stop
34
+ printer = RubyProf::MultiPrinter.new(result)
35
+ TmpFile.with_file do |dir|
36
+ FileUtils.mkdir_p dir unless File.exists? dir
37
+ printer.print(:path => dir, :profile => 'profile')
38
+ CMD.cmd("firefox -no-remote '#{ dir }'")
39
+ end
40
+ end
41
+
42
+ res
43
+ end
44
+
45
+ def self.profile_graph(options = {})
46
+ require 'ruby-prof'
47
+ RubyProf.start
48
+ begin
49
+ res = yield
50
+ rescue Exception
51
+ puts "Profiling aborted"
52
+ raise $!
53
+ ensure
54
+ result = RubyProf.stop
55
+ #result.eliminate_methods!([/annotated_array_clean_/])
56
+ printer = RubyProf::GraphPrinter.new(result)
57
+ printer.print(STDOUT, options)
58
+ end
59
+
60
+ res
61
+ end
62
+
63
+ def self.profile(options = {})
64
+ require 'ruby-prof'
65
+ RubyProf.start
66
+ begin
67
+ res = yield
68
+ rescue Exception
69
+ puts "Profiling aborted"
70
+ raise $!
71
+ ensure
72
+ result = RubyProf.stop
73
+ printer = RubyProf::FlatPrinter.new(result)
74
+ printer.print(STDOUT, options)
75
+ end
76
+
77
+ res
78
+ end
79
+
80
+ def self.memprof
81
+ require 'memprof'
82
+ Memprof.start
83
+ begin
84
+ res = yield
85
+ rescue Exception
86
+ puts "Profiling aborted"
87
+ raise $!
88
+ ensure
89
+ Memprof.stop
90
+ print Memprof.stats
91
+ end
92
+
93
+ res
94
+ end
95
+ end
@@ -0,0 +1,11 @@
1
+ class ParameterException < Exception; end
2
+ class FieldNotFoundError < Exception;end
3
+ class Aborted < Exception; end
4
+ class TryAgain < Exception; end
5
+ class ClosedStream < Exception; end
6
+ class KeepLocked < Exception
7
+ attr_accessor :payload
8
+ def initialize(payload)
9
+ @payload = payload
10
+ end
11
+ end
@@ -0,0 +1,170 @@
1
+ module Misc
2
+ COLOR_LIST = %w(#BC80BD #CCEBC5 #FFED6F #8DD3C7 #FFFFB3 #BEBADA #FB8072 #80B1D3 #FDB462 #B3DE69 #FCCDE5 #D9D9D9)
3
+
4
+ def self.colors_for(list)
5
+ unused = COLOR_LIST.dup
6
+
7
+ used = {}
8
+ colors = list.collect do |elem|
9
+ if used.include? elem
10
+ used[elem]
11
+ else
12
+ color = unused.shift
13
+ used[elem]=color
14
+ color
15
+ end
16
+ end
17
+
18
+ [colors, used]
19
+ end
20
+
21
+ def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
22
+ i = 0
23
+ re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
24
+ text.split(re).collect do |paragraph|
25
+ i += 1
26
+ str = if i % 2 == 1
27
+ words = paragraph.gsub(/\s+/, "\s").split(" ")
28
+ lines = []
29
+ line = " "*offset
30
+ word = words.shift
31
+ while word
32
+ word = word[0..size-indent-offset-4] + '...' if word.length >= size - indent - offset
33
+ while word and Log.uncolor(line).length + Log.uncolor(word).length <= size - indent
34
+ line << word << " "
35
+ word = words.shift
36
+ end
37
+ lines << ((" " * indent) << line[0..-2])
38
+ line = ""
39
+ end
40
+ (lines * "\n")
41
+ else
42
+ paragraph
43
+ end
44
+ offset = 0
45
+ str
46
+ end*""
47
+ end
48
+
49
+ def self.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow)
50
+ dd = "" if dd.nil?
51
+ dt = dt.to_s + ":" unless dd.empty?
52
+ dt = Log.color color, dt if color
53
+ len = Log.uncolor(dt).length
54
+
55
+ if indent < 0
56
+ text = format_paragraph(dd, size, indent.abs+1, 0)
57
+ text = dt << "\n" << text
58
+ else
59
+ offset = len - indent
60
+ offset = 0 if offset < 0
61
+ text = format_paragraph(dd, size, indent.abs+1, offset)
62
+ text[0..len-1] = dt
63
+ end
64
+ text
65
+ end
66
+
67
+ def self.format_definition_list(defs, size = 80, indent = 20, color = :yellow)
68
+ entries = []
69
+ defs.each do |dt,dd|
70
+ text = format_definition_list_item(dt,dd,size,indent,color)
71
+ entries << text
72
+ end
73
+ entries * "\n\n"
74
+ end
75
+
76
+ def self.camel_case(string)
77
+ return string if string !~ /_/ && string =~ /[A-Z]+.*/
78
+ string.split(/_|(\d+)/).map{|e|
79
+ (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize)
80
+ }.join
81
+ end
82
+
83
+ def self.camel_case_lower(string)
84
+ string.split('_').inject([]){ |buffer,e|
85
+ buffer.push(buffer.empty? ? e.downcase : (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize))
86
+ }.join
87
+ end
88
+
89
+ def self.snake_case(string)
90
+ return nil if string.nil?
91
+ string = string.to_s if Symbol === string
92
+ string.
93
+ gsub(/([A-Z]{2,})([A-Z][a-z])/,'\1_\2').
94
+ gsub(/([a-z])([A-Z])/,'\1_\2').
95
+ gsub(/\s/,'_').gsub(/[^\w_]/, '').
96
+ split("_").collect{|p| p.match(/[A-Z]{2,}/) ? p : p.downcase } * "_"
97
+ end
98
+
99
+ # source: https://gist.github.com/ekdevdes/2450285
100
+ # author: Ethan Kramer (https://github.com/ekdevdes)
101
+ def self.humanize(value, options = {})
102
+ if options.empty?
103
+ options[:format] = :sentence
104
+ end
105
+
106
+ values = []
107
+ values = value.split('_')
108
+ values.each_index do |index|
109
+ # lower case each item in array
110
+ # Miguel Vazquez edit: Except for acronyms
111
+ values[index].downcase! unless values[index].match(/[a-zA-Z][A-Z]/)
112
+ end
113
+ if options[:format] == :allcaps
114
+ values.each do |value|
115
+ value.capitalize!
116
+ end
117
+
118
+ if options.empty?
119
+ options[:seperator] = " "
120
+ end
121
+
122
+ return values.join " "
123
+ end
124
+
125
+ if options[:format] == :class
126
+ values.each do |value|
127
+ value.capitalize!
128
+ end
129
+
130
+ return values.join ""
131
+ end
132
+
133
+ if options[:format] == :sentence
134
+ values[0].capitalize! unless values[0].match(/[a-zA-Z][A-Z]/)
135
+
136
+ return values.join " "
137
+ end
138
+
139
+ if options[:format] == :nocaps
140
+ return values.join " "
141
+ end
142
+ end
143
+
144
+ def self.fixascii(string)
145
+ if string.respond_to?(:encode)
146
+ self.fixutf8(string).encode("ASCII-8BIT")
147
+ else
148
+ string
149
+ end
150
+ end
151
+
152
+ def self.to_utf8(string)
153
+ string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
154
+ end
155
+
156
+ def self.fixutf8(string)
157
+ return nil if string.nil?
158
+ return string if (string.respond_to? :valid_encoding? and string.valid_encoding?) or
159
+ (string.respond_to? :valid_encoding and string.valid_encoding)
160
+
161
+ if string.respond_to?(:encode)
162
+ string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
163
+ else
164
+ require 'iconv'
165
+ @@ic ||= Iconv.new('UTF-8//IGNORE', 'UTF-8')
166
+ @@ic.iconv(string)
167
+ end
168
+ end
169
+
170
+ end
@@ -0,0 +1,56 @@
1
+ module IndiferentHash
2
+
3
+ def self.setup(hash)
4
+ hash.extend IndiferentHash
5
+ end
6
+
7
+ def merge(other)
8
+ new = self.dup
9
+ IndiferentHash.setup(new)
10
+ other.each do |k,value|
11
+ new.delete k
12
+ new[k] = value
13
+ end
14
+ new
15
+ end
16
+
17
+ def [](key)
18
+ res = super(key)
19
+ return res unless res.nil?
20
+
21
+ case key
22
+ when Symbol, Module
23
+ super(key.to_s)
24
+ when String
25
+ super(key.to_sym)
26
+ else
27
+ super(key)
28
+ end
29
+ end
30
+
31
+ def values_at(*key_list)
32
+ key_list.inject([]){|acc,key| acc << self[key]}
33
+ end
34
+
35
+ def include?(key)
36
+ case key
37
+ when Symbol, Module
38
+ super(key) || super(key.to_s)
39
+ when String
40
+ super(key) || super(key.to_sym)
41
+ else
42
+ super(key)
43
+ end
44
+ end
45
+
46
+ def delete(key)
47
+ case key
48
+ when Symbol, Module
49
+ super(key) || super(key.to_s)
50
+ when String
51
+ super(key) || super(key.to_sym)
52
+ else
53
+ super(key)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,181 @@
1
+ module Misc
2
+ ARRAY_MAX_LENGTH = 1000
3
+ STRING_MAX_LENGTH = ARRAY_MAX_LENGTH * 10
4
+
5
+ def self.sanitize_filename(filename, length = 254)
6
+ if filename.length > length
7
+ if filename =~ /(\..{2,9})$/
8
+ extension = $1
9
+ else
10
+ extension = ''
11
+ end
12
+
13
+ post_fix = "--#{filename.length}@#{length}_#{Misc.digest(filename)[0..4]}" + extension
14
+
15
+ filename = filename[0..(length - post_fix.length - 1)] << post_fix
16
+ else
17
+ filename
18
+ end
19
+ filename
20
+ end
21
+
22
+ def self.fingerprint(obj)
23
+ case obj
24
+ when nil
25
+ "nil"
26
+ when (defined? Step and Step)
27
+ obj.path || Misc.fingerprint([obj.task.name, obj.inputs])
28
+ when TrueClass
29
+ "true"
30
+ when FalseClass
31
+ "false"
32
+ when Symbol
33
+ ":" << obj.to_s
34
+ when String
35
+ if obj.length > 100
36
+ "'" << obj.slice(0,20) << "<...#{obj.length}...>" << obj.slice(-10,10) << " " << "'"
37
+ else
38
+ "'" << obj << "'"
39
+ end
40
+ when (defined? AnnotatedArray and AnnotatedArray)
41
+ "<A: #{fingerprint Annotated.purge(obj)} #{fingerprint obj.info}>"
42
+ when (defined? TSV and TSV::Parser)
43
+ "<TSVStream:" + obj.filename + "--" << Misc.fingerprint(obj.options) << ">"
44
+ when IO
45
+ "<IO:" + (obj.respond_to?(:filename) ? obj.filename : obj.inspect) + ">"
46
+ when File
47
+ "<File:" + obj.path + ">"
48
+ when Array
49
+ if (length = obj.length) > 10
50
+ "[#{length}--" << (obj.values_at(0,1, length / 2, -2, -1).collect{|e| fingerprint(e)} * ",") << "]"
51
+ else
52
+ "[" << (obj.collect{|e| fingerprint(e) } * ",") << "]"
53
+ end
54
+ when (defined? TSV and TSV)
55
+ obj.with_unnamed do
56
+ "TSV:{"<< fingerprint(obj.all_fields|| []).inspect << ";" << fingerprint(obj.keys).inspect << "}"
57
+ end
58
+ when Hash
59
+ if obj.length > 10
60
+ "H:{"<< fingerprint(obj.keys) << ";" << fingerprint(obj.values) << "}"
61
+ else
62
+ new = "{"
63
+ obj.each do |k,v|
64
+ new << k.to_s << '=>' << fingerprint(v) << ' '
65
+ end
66
+ if new.length > 1
67
+ new[-1] = "}"
68
+ else
69
+ new << '}'
70
+ end
71
+ new
72
+ end
73
+ else
74
+ obj.to_s
75
+ end
76
+ end
77
+
78
+
79
+ def self.remove_long_items(obj)
80
+ case
81
+ when IO === obj
82
+ remove_long_items("IO: " + obj.filename)
83
+ when obj.respond_to?(:path)
84
+ remove_long_items("File: " + obj.path)
85
+ when TSV::Parser === obj
86
+ remove_long_items("TSV Stream: " + obj.filename + " -- " << Misc.fingerprint(obj.options))
87
+ when TSV === obj
88
+ remove_long_items((obj.all_fields || []) + obj.keys.sort)
89
+ when (Array === obj and obj.length > ARRAY_MAX_LENGTH)
90
+ remove_long_items(obj[0..ARRAY_MAX_LENGTH-2] << "TRUNCATED at #{ ARRAY_MAX_LENGTH } (#{obj.length})")
91
+ when (Hash === obj and obj.length > ARRAY_MAX_LENGTH)
92
+ remove_long_items(obj.collect.compact[0..ARRAY_MAX_LENGTH-2] << ["TRUNCATED", "at #{ ARRAY_MAX_LENGTH } (#{obj.length})"])
93
+ when (String === obj and obj.length > STRING_MAX_LENGTH)
94
+ obj[0..STRING_MAX_LENGTH-1] << " TRUNCATED at #{STRING_MAX_LENGTH} (#{obj.length})"
95
+ when Hash === obj
96
+ new = {}
97
+ obj.each do |k,v|
98
+ new[k] = remove_long_items(v)
99
+ end
100
+ new
101
+ when Array === obj
102
+ obj.collect do |e| remove_long_items(e) end
103
+ else
104
+ obj
105
+ end
106
+ end
107
+
108
+ def self.filename?(string)
109
+ String === string and string.length > 0 and string.length < 250 and File.exists?(string)
110
+ end
111
+
112
+ def self.is_filename?(string)
113
+ return true if string.respond_to? :exists
114
+ return true if String === string and string.length < 265 and File.exists? string
115
+ return false
116
+ end
117
+
118
+ def self.digest(text)
119
+ Digest::MD5.hexdigest(text)
120
+ end
121
+
122
+ HASH2MD5_MAX_STRING_LENGTH = 1000
123
+ HASH2MD5_MAX_ARRAY_LENGTH = 100
124
+ def self.hash2md5(hash)
125
+ str = ""
126
+ keys = hash.keys
127
+ keys = keys.clean_annotations if keys.respond_to? :clean_annotations
128
+ keys = keys.sort_by{|k| k.to_s}
129
+
130
+ if hash.respond_to? :unnamed
131
+ unnamed = hash.unnamed
132
+ hash.unnamed = true
133
+ end
134
+ keys.each do |k|
135
+ next if k == :monitor or k == "monitor" or k == :in_situ_persistence or k == "in_situ_persistence"
136
+ v = hash[k]
137
+ case
138
+ when TrueClass === v
139
+ str << k.to_s << "=>true"
140
+ when FalseClass === v
141
+ str << k.to_s << "=>false"
142
+ when Hash === v
143
+ str << k.to_s << "=>" << hash2md5(v)
144
+ when Symbol === v
145
+ str << k.to_s << "=>" << v.to_s
146
+ when (String === v and v.length > HASH2MD5_MAX_STRING_LENGTH)
147
+ str << k.to_s << "=>" << v[0..HASH2MD5_MAX_STRING_LENGTH] << "; #{ v.length }"
148
+ when String === v
149
+ str << k.to_s << "=>" << v
150
+ when (Array === v and v.length > HASH2MD5_MAX_ARRAY_LENGTH)
151
+ str << k.to_s << "=>[" << v[0..HASH2MD5_MAX_ARRAY_LENGTH] * "," << "; #{ v.length }]"
152
+ when TSV::Parser === v
153
+ str << remove_long_items(v)
154
+ when Array === v
155
+ str << k.to_s << "=>[" << v * "," << "]"
156
+ when File === v
157
+ str << k.to_s << "=>[File:" << v.path << "]"
158
+ else
159
+ v_ins = v.inspect
160
+
161
+ case
162
+ when v_ins =~ /:0x0/
163
+ str << k.to_s << "=>" << v_ins.sub(/:0x[a-f0-9]+@/,'')
164
+ else
165
+ str << k.to_s << "=>" << v_ins
166
+ end
167
+
168
+ end
169
+
170
+ str << "_" << hash2md5(v.info) if defined? Annotated and Annotated === v
171
+ end
172
+ hash.unnamed = unnamed if hash.respond_to? :unnamed
173
+
174
+ if str.empty?
175
+ ""
176
+ else
177
+ digest(str)
178
+ end
179
+ end
180
+
181
+ end