rbbt-util 5.11.4 → 5.11.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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