scout-essentials 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.vimproject +78 -0
  4. data/Gemfile +14 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +18 -0
  7. data/Rakefile +47 -0
  8. data/VERSION +1 -0
  9. data/lib/scout/cmd.rb +348 -0
  10. data/lib/scout/concurrent_stream.rb +284 -0
  11. data/lib/scout/config.rb +168 -0
  12. data/lib/scout/exceptions.rb +77 -0
  13. data/lib/scout/indiferent_hash/case_insensitive.rb +30 -0
  14. data/lib/scout/indiferent_hash/options.rb +115 -0
  15. data/lib/scout/indiferent_hash.rb +96 -0
  16. data/lib/scout/log/color.rb +224 -0
  17. data/lib/scout/log/color_class.rb +269 -0
  18. data/lib/scout/log/fingerprint.rb +69 -0
  19. data/lib/scout/log/progress/report.rb +244 -0
  20. data/lib/scout/log/progress/util.rb +173 -0
  21. data/lib/scout/log/progress.rb +106 -0
  22. data/lib/scout/log/trap.rb +107 -0
  23. data/lib/scout/log.rb +441 -0
  24. data/lib/scout/meta_extension.rb +100 -0
  25. data/lib/scout/misc/digest.rb +63 -0
  26. data/lib/scout/misc/filesystem.rb +25 -0
  27. data/lib/scout/misc/format.rb +255 -0
  28. data/lib/scout/misc/helper.rb +31 -0
  29. data/lib/scout/misc/insist.rb +56 -0
  30. data/lib/scout/misc/monitor.rb +66 -0
  31. data/lib/scout/misc/system.rb +73 -0
  32. data/lib/scout/misc.rb +10 -0
  33. data/lib/scout/named_array.rb +138 -0
  34. data/lib/scout/open/lock/lockfile.rb +587 -0
  35. data/lib/scout/open/lock.rb +68 -0
  36. data/lib/scout/open/remote.rb +135 -0
  37. data/lib/scout/open/stream.rb +491 -0
  38. data/lib/scout/open/util.rb +244 -0
  39. data/lib/scout/open.rb +170 -0
  40. data/lib/scout/path/find.rb +204 -0
  41. data/lib/scout/path/tmpfile.rb +8 -0
  42. data/lib/scout/path/util.rb +127 -0
  43. data/lib/scout/path.rb +51 -0
  44. data/lib/scout/persist/open.rb +17 -0
  45. data/lib/scout/persist/path.rb +15 -0
  46. data/lib/scout/persist/serialize.rb +157 -0
  47. data/lib/scout/persist.rb +104 -0
  48. data/lib/scout/resource/open.rb +8 -0
  49. data/lib/scout/resource/path.rb +80 -0
  50. data/lib/scout/resource/produce/rake.rb +69 -0
  51. data/lib/scout/resource/produce.rb +151 -0
  52. data/lib/scout/resource/scout.rb +3 -0
  53. data/lib/scout/resource/software.rb +178 -0
  54. data/lib/scout/resource/util.rb +59 -0
  55. data/lib/scout/resource.rb +40 -0
  56. data/lib/scout/simple_opt/accessor.rb +54 -0
  57. data/lib/scout/simple_opt/doc.rb +126 -0
  58. data/lib/scout/simple_opt/get.rb +57 -0
  59. data/lib/scout/simple_opt/parse.rb +67 -0
  60. data/lib/scout/simple_opt/setup.rb +26 -0
  61. data/lib/scout/simple_opt.rb +5 -0
  62. data/lib/scout/tmpfile.rb +129 -0
  63. data/lib/scout-essentials.rb +10 -0
  64. data/scout-essentials.gemspec +143 -0
  65. data/share/color/color_names +507 -0
  66. data/share/color/diverging_colors.hex +12 -0
  67. data/share/software/install_helpers +523 -0
  68. data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
  69. data/test/scout/indiferent_hash/test_options.rb +46 -0
  70. data/test/scout/log/test_color.rb +0 -0
  71. data/test/scout/log/test_progress.rb +108 -0
  72. data/test/scout/misc/test_digest.rb +30 -0
  73. data/test/scout/misc/test_filesystem.rb +30 -0
  74. data/test/scout/misc/test_insist.rb +13 -0
  75. data/test/scout/misc/test_system.rb +21 -0
  76. data/test/scout/open/test_lock.rb +52 -0
  77. data/test/scout/open/test_remote.rb +25 -0
  78. data/test/scout/open/test_stream.rb +676 -0
  79. data/test/scout/open/test_util.rb +73 -0
  80. data/test/scout/path/test_find.rb +110 -0
  81. data/test/scout/path/test_util.rb +22 -0
  82. data/test/scout/persist/test_open.rb +37 -0
  83. data/test/scout/persist/test_path.rb +37 -0
  84. data/test/scout/persist/test_serialize.rb +114 -0
  85. data/test/scout/resource/test_path.rb +58 -0
  86. data/test/scout/resource/test_produce.rb +94 -0
  87. data/test/scout/resource/test_software.rb +24 -0
  88. data/test/scout/resource/test_util.rb +38 -0
  89. data/test/scout/simple_opt/test_doc.rb +16 -0
  90. data/test/scout/simple_opt/test_get.rb +11 -0
  91. data/test/scout/simple_opt/test_parse.rb +10 -0
  92. data/test/scout/simple_opt/test_setup.rb +77 -0
  93. data/test/scout/test_cmd.rb +85 -0
  94. data/test/scout/test_concurrent_stream.rb +29 -0
  95. data/test/scout/test_config.rb +66 -0
  96. data/test/scout/test_indiferent_hash.rb +26 -0
  97. data/test/scout/test_log.rb +32 -0
  98. data/test/scout/test_meta_extension.rb +80 -0
  99. data/test/scout/test_misc.rb +6 -0
  100. data/test/scout/test_named_array.rb +43 -0
  101. data/test/scout/test_open.rb +146 -0
  102. data/test/scout/test_path.rb +54 -0
  103. data/test/scout/test_persist.rb +186 -0
  104. data/test/scout/test_resource.rb +26 -0
  105. data/test/scout/test_tmpfile.rb +53 -0
  106. data/test/test_helper.rb +50 -0
  107. metadata +247 -0
data/lib/scout/log.rb ADDED
@@ -0,0 +1,441 @@
1
+ require_relative 'log/color'
2
+ require_relative 'log/fingerprint'
3
+ require_relative 'log/progress'
4
+ require_relative 'log/trap'
5
+
6
+ require 'io/console'
7
+
8
+ module Log
9
+ class << self
10
+ attr_accessor :severity
11
+ attr_writer :tty_size, :logfile
12
+ end
13
+
14
+ SEVERITY_NAMES ||= begin
15
+ names = %w(DEBUG LOW MEDIUM HIGH INFO WARN ERROR NONE )
16
+ names.each_with_index do |name,i|
17
+ eval "#{ name } = #{ i }"
18
+ end
19
+ names
20
+ end
21
+ def self.default_severity
22
+ @@default_severity ||= begin
23
+ file = File.join(ENV["HOME"], '.scout/etc/log_severity')
24
+ if File.exist? file
25
+ File.open(file) do |f|
26
+ SEVERITY_NAMES.index f.read.strip
27
+ end
28
+ else
29
+ INFO
30
+ end
31
+ end
32
+ @@default_severity
33
+ end
34
+
35
+ case ENV['SCOUT_LOG']
36
+ when 'DEBUG'
37
+ self.severity = DEBUG
38
+ when 'LOW'
39
+ self.severity = LOW
40
+ when 'MEDIUM'
41
+ self.severity = MEDIUM
42
+ when 'HIGH'
43
+ self.severity = HIGH
44
+ when nil
45
+ self.severity = default_severity
46
+ else
47
+ self.severity = default_severity
48
+ end
49
+
50
+
51
+
52
+ def self.tty_size
53
+ @@tty_size ||= Log.ignore_stderr do
54
+ size = begin
55
+ IO.console.winsize.last
56
+ rescue Exception
57
+ begin
58
+ res = `tput li`
59
+ res = nil if res == ""
60
+ res || ENV["TTY_SIZE"] || 80
61
+ rescue Exception
62
+ ENV["TTY_SIZE"] || 80
63
+ end
64
+ end
65
+ size = size.to_i if String === size
66
+ size
67
+ end
68
+ end
69
+
70
+
71
+ def self.last_caller(stack)
72
+ line = nil
73
+ pos ||= 0
74
+ while line.nil? or line =~ /scout\/log\.rb/ and stack.any?
75
+ line = stack.shift
76
+ end
77
+ line ||= caller.first
78
+ line.gsub('`', "'")
79
+ end
80
+
81
+ def self.get_level(level)
82
+ case level
83
+ when Numeric
84
+ level.to_i
85
+ when String
86
+ begin
87
+ Log.const_get(level.upcase)
88
+ rescue
89
+ Log.exception $!
90
+ end
91
+ when Symbol
92
+ get_level(level.to_s)
93
+ end || 0
94
+ end
95
+
96
+ def self.with_severity(level)
97
+ orig = Log.severity
98
+ begin
99
+ Log.severity = level
100
+ yield
101
+ ensure
102
+ Log.severity = orig
103
+ end
104
+ end
105
+
106
+ def self.logfile(file=nil)
107
+ if file.nil?
108
+ @logfile ||= nil
109
+ else
110
+ case file
111
+ when String
112
+ @logfile = File.open(file, :mode => 'a')
113
+ @logfile.sync = true
114
+ when IO, File
115
+ @logfile = file
116
+ else
117
+ raise "Unkown logfile format: #{file.inspect}"
118
+ end
119
+ end
120
+ end
121
+
122
+ def self.up_lines(num = 1)
123
+ nocolor ? "" : "\033[#{num+1}F\033[2K"
124
+ end
125
+
126
+ def self.down_lines(num = 1)
127
+ nocolor ? "" : "\033[#{num+1}E"
128
+ end
129
+
130
+ def self.return_line
131
+ nocolor ? "" : "\033[1A"
132
+ end
133
+
134
+ def self.clear_line(out = STDOUT)
135
+ out.puts Log.return_line << " " * (Log.tty_size || 80) << Log.return_line unless nocolor
136
+ end
137
+
138
+ MUTEX = Mutex.new
139
+ def self.log_write(str)
140
+ MUTEX.synchronize do
141
+ if logfile.nil?
142
+ begin
143
+ STDERR.write str
144
+ rescue
145
+ end
146
+ else
147
+ logfile.write str
148
+ end
149
+ end
150
+ end
151
+
152
+ def self.log_puts(str)
153
+ MUTEX.synchronize do
154
+ if logfile.nil?
155
+ begin
156
+ STDERR.puts str
157
+ rescue
158
+ end
159
+ else
160
+ logfile.puts str
161
+ end
162
+ end
163
+ end
164
+
165
+ LAST = "log"
166
+ def self.logn(message = nil, severity = MEDIUM, &block)
167
+ return if severity < self.severity
168
+ message ||= block.call if block_given?
169
+ return if message.nil?
170
+
171
+ time = Time.now.strftime("%m/%d/%y-%H:%M:%S.%L")
172
+
173
+ sev_str = severity.to_s
174
+
175
+ if ENV["SCOUT_DEBUG_PID"] == "true"
176
+ prefix = time << "[" << Process.pid.to_s << "]" << color(severity) << "[" << sev_str << "]" << color(0)
177
+ else
178
+ prefix = time << color(severity) << "[" << sev_str << "]" << color(0)
179
+ end
180
+ message = "" << highlight << message << color(0) if severity >= INFO
181
+ str = prefix << " " << message.to_s
182
+
183
+ log_write str
184
+
185
+ Log::LAST.replace "log"
186
+ nil
187
+ end
188
+
189
+ def self.log(message = nil, severity = MEDIUM, &block)
190
+ return if severity < self.severity
191
+ message ||= block.call if block_given?
192
+ return if message.nil?
193
+ message = message + "\n" unless message[-1] == "\n"
194
+ self.logn message, severity, &block
195
+ end
196
+
197
+ def self.log_obj_inspect(obj, level, file = $stdout)
198
+ stack = caller
199
+
200
+ line = Log.last_caller stack
201
+
202
+ level = Log.get_level level
203
+ name = Log::SEVERITY_NAMES[level] + ": "
204
+ Log.log Log.color(level, name, true) << line, level
205
+ Log.log "", level
206
+ Log.log Log.color(level, "=> ", true) << obj.inspect, level
207
+ Log.log "", level
208
+ end
209
+
210
+ def self.log_obj_fingerprint(obj, level, file = $stdout)
211
+ stack = caller
212
+
213
+ line = Log.last_caller stack
214
+
215
+ level = Log.get_level level
216
+ name = Log::SEVERITY_NAMES[level] + ": "
217
+ Log.log Log.color(level, name, true) << line, level
218
+ Log.log "", level
219
+ Log.log Log.color(level, "=> ", true) << Log.fingerprint(obj), level
220
+ Log.log "", level
221
+ end
222
+
223
+ def self.debug(message = nil, &block)
224
+ log(message, DEBUG, &block)
225
+ end
226
+
227
+ def self.low(message = nil, &block)
228
+ log(message, LOW, &block)
229
+ end
230
+
231
+ def self.medium(message = nil, &block)
232
+ log(message, MEDIUM, &block)
233
+ end
234
+
235
+ def self.high(message = nil, &block)
236
+ log(message, HIGH, &block)
237
+ end
238
+
239
+ def self.info(message = nil, &block)
240
+ log(message, INFO, &block)
241
+ end
242
+
243
+ def self.warn(message = nil, &block)
244
+ log(message, WARN, &block)
245
+ end
246
+
247
+ def self.error(message = nil, &block)
248
+ log(message, ERROR, &block)
249
+ end
250
+
251
+ def self.exception(e)
252
+ stack = caller
253
+ backtrace = e.backtrace || []
254
+ if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
255
+ error([e.class.to_s, e.message].compact * ": " )
256
+ error("BACKTRACE [#{Process.pid}]: " << Log.last_caller(stack) << "\n" + color_stack(backtrace)*"\n")
257
+ else
258
+ error("BACKTRACE [#{Process.pid}]: " << Log.last_caller(stack) << "\n" + color_stack(backtrace.reverse)*"\n")
259
+ error([e.class.to_s, e.message].compact * ": " )
260
+ end
261
+ end
262
+
263
+ def self.deprecated(m)
264
+ stack = caller
265
+ warn("DEPRECATED: " << Log.last_caller(stack))
266
+ warn("* " << (m || "").to_s)
267
+ end
268
+
269
+ def self.color_stack(stack)
270
+ stack.collect do |line|
271
+ line = line.sub('`',"'")
272
+ color = :green if line =~ /workflow/
273
+ color = :blue if line =~ /scout-/
274
+ color = :cyan if line =~ /rbbt-/
275
+ if color
276
+ Log.color color, line
277
+ else
278
+ line
279
+ end
280
+ end unless stack.nil?
281
+ end
282
+
283
+ def self.tsv(tsv, example = false)
284
+ log_puts Log.color :magenta, "TSV log: " << Log.last_caller(caller).gsub('`',"'")
285
+ log_puts Log.color(:blue, "=> "<< Log.fingerprint(tsv), true)
286
+ log_puts Log.color(:cyan, "=> " << tsv.summary)
287
+ if example && ! tsv.empty?
288
+ key = case example
289
+ when TrueClass, :first, "first"
290
+ tsv.keys.first
291
+ when :random, "random"
292
+ tsv.keys.shuffle.first
293
+ else
294
+ example
295
+ end
296
+
297
+ values = tsv[key]
298
+ values = [values] if tsv.type == :flat || tsv.type == :single
299
+ if values.nil?
300
+ log_puts Log.color(:blue, "Key (#{tsv.key_field}) not present: ") + key
301
+ else
302
+ log_puts Log.color(:blue, "Key (#{tsv.key_field}): ") + key
303
+ tsv.fields.zip(values).each do |field,value|
304
+ log_puts Log.color(:magenta, field + ": ") + (Array === value ? value * ", " : value.to_s)
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ def self.stack(stack)
311
+ if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
312
+ log_puts Log.color :magenta, "Stack trace [#{Process.pid}]: " << Log.last_caller(caller)
313
+ color_stack(stack).each do |line|
314
+ log_puts line
315
+ end
316
+ else
317
+ log_puts Log.color :magenta, "Stack trace [#{Process.pid}]: " << Log.last_caller(caller)
318
+ color_stack(stack.reverse).each do |line|
319
+ log_puts line
320
+ end
321
+ end
322
+ end
323
+
324
+ def self.count_stack
325
+ if ! $count_stacks
326
+ Log.debug "Counting stacks at: " << caller.first
327
+ return
328
+ end
329
+ $stack_counts ||= {}
330
+ head = $count_stacks_head
331
+ stack = caller[1..head+1]
332
+ stack.reverse.each do |line,i|
333
+ $stack_counts[line] ||= 0
334
+ $stack_counts[line] += 1
335
+ end
336
+ end
337
+
338
+ def self.with_stack_counts(head = 10, total = 100)
339
+ $count_stacks_head = head
340
+ $count_stacks = true
341
+ $stack_counts = {}
342
+ res = yield
343
+ $count_stacks = false
344
+ Log.debug "STACK_COUNTS:\n" + $stack_counts.sort_by{|line,c| c}.reverse.collect{|line,c| [c, line] * " - "}[0..total] * "\n"
345
+ $stack_counts = {}
346
+ res
347
+ end
348
+ end
349
+
350
+ def ppp(message)
351
+ stack = caller
352
+ puts "#{Log.color :cyan, "PRINT:"} " << stack.first
353
+ puts ""
354
+ if message.length > 200 or message.include? "\n"
355
+ puts Log.color(:cyan, "=>|") << "\n" << message.to_s
356
+ else
357
+ puts Log.color(:cyan, "=> ") << message.to_s
358
+ end
359
+ puts ""
360
+ end
361
+
362
+ def fff(object)
363
+ stack = caller
364
+ Log.debug{"#{Log.color :cyan, "FINGERPRINT:"} " << stack.first}
365
+ Log.debug{""}
366
+ Log.debug{require 'scout/util/misc'; "=> " << Log.fingerprint(object) }
367
+ Log.debug{""}
368
+ end
369
+
370
+ def ddd(obj, file = $stdout)
371
+ Log.log_obj_inspect(obj, :debug, file)
372
+ end
373
+
374
+ def lll(obj, file = $stdout)
375
+ Log.log_obj_inspect(obj, :low, file)
376
+ end
377
+
378
+ def mmm(obj, file = $stdout)
379
+ Log.log_obj_inspect(obj, :medium, file)
380
+ end
381
+
382
+ def iii(obj=nil, file = $stdout)
383
+ Log.log_obj_inspect(obj, :info, file)
384
+ end
385
+
386
+ def wwww(obj=nil, file = $stdout)
387
+ Log.log_obj_inspect(obj, :warn, file)
388
+ end
389
+
390
+ def eee(obj=nil, file = $stdout)
391
+ Log.log_obj_inspect(obj, :error, file)
392
+ end
393
+
394
+ def ddf(obj=nil, file = $stdout)
395
+ Log.log_obj_fingerprint(obj, :debug, file)
396
+ end
397
+
398
+ def llf(obj=nil, file = $stdout)
399
+ Log.log_obj_fingerprint(obj, :low, file)
400
+ end
401
+
402
+ def mmf(obj=nil, file = $stdout)
403
+ Log.log_obj_fingerprint(obj, :medium, file)
404
+ end
405
+
406
+ def iif(obj=nil, file = $stdout)
407
+ Log.log_obj_fingerprint(obj, :info, file)
408
+ end
409
+
410
+ def wwwf(obj=nil, file = $stdout)
411
+ Log.log_obj_fingerprint(obj, :warn, file)
412
+ end
413
+
414
+ def eef(obj=nil, file = $stdout)
415
+ Log.log_obj_fingerprint(obj, :error, file)
416
+ end
417
+
418
+ def sss(level, &block)
419
+ if block_given?
420
+ Log.with_severity level, &block
421
+ else
422
+ Log.severity = level
423
+ end
424
+ end
425
+
426
+ $scout_debug_log = false
427
+ def ccc(obj=nil, file = $stdout)
428
+ if block_given?
429
+ old_scout_debug_log = $scout_debug_log
430
+ $scout_debug_log = 'true'
431
+ begin
432
+ yield
433
+ ensure
434
+ $scout_debug_log = old_scout_debug_log
435
+ end
436
+ else
437
+ Log.log_obj_inspect(obj, :info, file) if $scout_debug_log
438
+ end
439
+ end
440
+
441
+
@@ -0,0 +1,100 @@
1
+ module MetaExtension
2
+ def self.extended(base)
3
+ meta = class << base; self; end
4
+
5
+ base.class_variable_set("@@extension_attrs", []) unless base.class_variables.include?("@@extension_attrs")
6
+
7
+ meta.define_method(:extension_attr) do |*attrs|
8
+ self.class_variable_get("@@extension_attrs").concat attrs
9
+ attrs.each do |a|
10
+ self.attr_accessor a
11
+ end
12
+ end
13
+
14
+ meta.define_method(:extended) do |obj|
15
+ attrs = self.class_variable_get("@@extension_attrs")
16
+
17
+ obj.instance_variable_set(:@extension_attrs, []) unless obj.instance_variables.include?(:@extension_attrs)
18
+ extension_attrs = obj.instance_variable_get(:@extension_attrs)
19
+ extension_attrs.concat attrs
20
+ end
21
+
22
+ meta.define_method(:setup) do |*args,&block|
23
+ if block_given?
24
+ obj, rest = block, args
25
+ else
26
+ obj, *rest = args
27
+ end
28
+ obj = block if obj.nil?
29
+ obj.extend base unless base === obj
30
+
31
+ attrs = self.class_variable_get("@@extension_attrs")
32
+
33
+ return if attrs.nil? || attrs.empty?
34
+
35
+ if rest.length == 1 && Hash === (rlast = rest.last) &&
36
+ ((! (rlkey = rlast.keys.first).nil? && attrs.include?(rlkey.to_sym)) ||
37
+ (! attrs.length != 1 ))
38
+
39
+ pairs = rlast
40
+ else
41
+ pairs = attrs.zip(rest)
42
+ end
43
+
44
+ pairs.each do |name,value|
45
+ obj.instance_variable_set("@#{name}", value)
46
+ end
47
+
48
+ obj
49
+ end
50
+
51
+ base.define_method(:extension_attr_hash) do
52
+ attr_hash = {}
53
+ @extension_attrs.each do |name|
54
+ attr_hash[name] = self.instance_variable_get("@#{name}")
55
+ end
56
+ attr_hash
57
+ end
58
+
59
+ base.define_method(:annotate) do |other|
60
+ attr_values = @extension_attrs.collect do |a|
61
+ self.instance_variable_get("@#{a}")
62
+ end
63
+ base.setup(other, *attr_values)
64
+ end
65
+
66
+ base.define_method(:purge) do
67
+ new = self.dup
68
+
69
+ if new.instance_variables.include?(:@extension_attrs)
70
+ new.instance_variable_get(:@extension_attrs).each do |a|
71
+ new.remove_instance_variable("@#{a}")
72
+ end
73
+ new.remove_instance_variable("@extension_attrs")
74
+ end
75
+
76
+ new
77
+ end
78
+ end
79
+
80
+ def self.is_extended?(obj)
81
+ obj.respond_to?(:extension_attr_hash)
82
+ end
83
+
84
+ def self.purge(obj)
85
+ case obj
86
+ when nil
87
+ nil
88
+ when Array
89
+ obj.collect{|e| purge(e) }
90
+ when Hash
91
+ new = {}
92
+ obj.each do |k,v|
93
+ new[k] = purge(v)
94
+ end
95
+ new
96
+ else
97
+ is_extended?(obj) ? obj.purge : obj
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,63 @@
1
+ module Misc
2
+ MAX_ARRAY_DIGEST_LENGTH = 100_000
3
+ def self.digest_str(obj)
4
+ if obj.respond_to?(:digest_str)
5
+ obj.digest_str
6
+ else
7
+ case obj
8
+ when String
9
+ #'\'' << obj << '\''
10
+ if Path === obj || ! Open.exists?(obj)
11
+ '\'' << obj << '\''
12
+ else
13
+ "File MD5: #{Misc.file_md5(obj)}"
14
+ end
15
+ when Integer, Symbol
16
+ obj.to_s
17
+ when Array
18
+ if obj.length > MAX_ARRAY_DIGEST_LENGTH
19
+ length = obj.length
20
+ mid = length/2
21
+ sample_pos = [1, 2, mid, length-2, length-1]
22
+ "[#{length}:" << obj.values_at(*sample_pos).inject(""){|acc,o| acc.empty? ? Misc.digest_str(o) : acc << ', ' << Misc.digest_str(o) } << ']'
23
+ else
24
+ '[' << obj.inject(""){|acc,o| acc.empty? ? Misc.digest_str(o) : acc << ', ' << Misc.digest_str(o) } << ']'
25
+ end
26
+ when Hash
27
+ '{' << obj.inject(""){|acc,p| s = Misc.digest_str(p.first) << "=" << Misc.digest_str(p.last); acc.empty? ? s : acc << ', ' << s } << '}'
28
+ when Integer
29
+ obj.to_s
30
+ when Float
31
+ if obj % 1 == 0
32
+ obj.to_i.to_s
33
+ elsif obj.abs > 10
34
+ "%.1f" % obj
35
+ elsif obj.abs > 1
36
+ "%.3f" % obj
37
+ else
38
+ "%.6f" % obj
39
+ end
40
+ when TrueClass
41
+ "true"
42
+ when FalseClass
43
+ "false"
44
+ else
45
+ obj.inspect
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.digest(obj)
51
+ str = String === obj ? obj : Misc.digest_str(obj)
52
+ Digest::MD5.hexdigest(str)
53
+ end
54
+
55
+ def self.file_md5(file)
56
+ file = file.find if Path === file
57
+ file = File.expand_path(file)
58
+ #md5file = file + '.md5'
59
+ Persist.persist("MD5:#{file}", :string) do
60
+ Digest::MD5.file(file).hexdigest
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,25 @@
1
+ module Misc
2
+ def self.in_dir(dir)
3
+ old_pwd = FileUtils.pwd
4
+ begin
5
+ FileUtils.mkdir_p dir unless File.exist?(dir)
6
+ FileUtils.cd dir
7
+ yield
8
+ ensure
9
+ FileUtils.cd old_pwd
10
+ end
11
+ end
12
+
13
+ def self.path_relative_to(basedir, path)
14
+ path = File.expand_path(path) unless path.slice(0,1) == "/"
15
+ basedir = File.expand_path(basedir) unless basedir.slice(0,1) == "/"
16
+
17
+ basedir += "/" unless basedir.slice(-2,-1) == "/"
18
+
19
+ if path.start_with?(basedir)
20
+ return path.slice(basedir.length, basedir.length)
21
+ else
22
+ return nil
23
+ end
24
+ end
25
+ end