scout-essentials 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +33 -1
  3. data/VERSION +1 -1
  4. data/lib/scout/annotation/annotated_object.rb +69 -0
  5. data/lib/scout/annotation/annotation_module.rb +59 -0
  6. data/lib/scout/annotation/array.rb +74 -0
  7. data/lib/scout/annotation.rb +45 -0
  8. data/lib/scout/concurrent_stream.rb +4 -1
  9. data/lib/scout/config.rb +3 -3
  10. data/lib/scout/exceptions.rb +2 -1
  11. data/lib/scout/indiferent_hash/options.rb +2 -1
  12. data/lib/scout/log/color.rb +1 -1
  13. data/lib/scout/log.rb +11 -11
  14. data/lib/scout/misc/digest.rb +39 -8
  15. data/lib/scout/misc/filesystem.rb +23 -0
  16. data/lib/scout/misc/format.rb +32 -0
  17. data/lib/scout/misc/helper.rb +37 -0
  18. data/lib/scout/misc/math.rb +109 -0
  19. data/lib/scout/misc/system.rb +2 -2
  20. data/lib/scout/misc.rb +1 -0
  21. data/lib/scout/named_array.rb +8 -6
  22. data/lib/scout/open/remote.rb +8 -3
  23. data/lib/scout/open/stream.rb +5 -1
  24. data/lib/scout/open/util.rb +1 -1
  25. data/lib/scout/path/find.rb +18 -6
  26. data/lib/scout/path/util.rb +1 -1
  27. data/lib/scout/path.rb +10 -4
  28. data/lib/scout/persist/open.rb +1 -1
  29. data/lib/scout/persist/serialize.rb +5 -1
  30. data/lib/scout/persist.rb +49 -20
  31. data/lib/scout/resource/path.rb +1 -1
  32. data/lib/scout/resource/scout.rb +2 -0
  33. data/lib/scout/resource/util.rb +8 -3
  34. data/lib/scout/resource.rb +15 -3
  35. data/scout-essentials.gemspec +21 -13
  36. data/test/scout/annotation/test_annotated_object.rb +0 -0
  37. data/test/scout/annotation/test_array.rb +119 -0
  38. data/test/scout/misc/test_digest.rb +54 -0
  39. data/test/scout/misc/test_filesystem.rb +28 -0
  40. data/test/scout/misc/test_helper.rb +14 -0
  41. data/test/scout/misc/test_math.rb +9 -0
  42. data/test/scout/path/test_find.rb +32 -0
  43. data/test/scout/test_annotation.rb +169 -0
  44. data/test/scout/test_persist.rb +17 -1
  45. data/test/scout/test_resource.rb +8 -8
  46. metadata +13 -5
  47. data/lib/scout/meta_extension.rb +0 -101
  48. data/test/scout/test_meta_extension.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7045a24f9341c66514b014a48e5c6f01ce8eba30a951703e9fdf290842ca7119
4
- data.tar.gz: 043c2b5778256fae3b26e6029b16b1c35a52c18e6e0be3377456c1a163f1bc5b
3
+ metadata.gz: 01ebe0cbbfda369f1d1b3de5009566eed0749cdb0a418c19c663a21ec68214c1
4
+ data.tar.gz: 2303029301ea7b4ef1f9d7cf44bd906cb8db637b31a5147ae2950e4eb1c6e37e
5
5
  SHA512:
6
- metadata.gz: 03a1c74fd678942a99725952479db7de5d0696c30f406070c89cffa50ca3a8bf967ed46b192e3f006569d08478bf7d3141aad7045a837eebc31fb38272edfa89
7
- data.tar.gz: 4f0797aac22d7a5609bcd21f21a1fae1d0db8a5208ccab4431475c1e963f2e42ef7da19226bddb52b6ec8ca09b9270d21eb434629f0541c7a60eab17b2ca4a69
6
+ metadata.gz: 707278b8bdd09658049035622021bd822d8b53ecef993f4136b550f2acb47be30cf515a460b07f5c45ed51769d782639b06e128947dab80832a4de3b6b66f574
7
+ data.tar.gz: d8a5ce01ca753d159734871447f961a39d48992af934f7ad69a0f95ff708794d00962cd36fbabbcd535a721611f5d0fa9194f87d5662cd8ab66ed80d8abeed38
data/.vimproject CHANGED
@@ -5,7 +5,12 @@ scout-essentials=/$PWD filter="*.rb *.txt *.md *.conf *.yaml" {
5
5
  scout-essentials.rb
6
6
  scout=scout{
7
7
  exceptions.rb
8
- meta_extension.rb
8
+ annotation.rb
9
+ annotation=annotation{
10
+ array.rb
11
+ annotated_object.rb
12
+ annotation_module.rb
13
+ }
9
14
  misc.rb
10
15
  misc=misc{
11
16
  digest.rb
@@ -15,6 +20,7 @@ scout-essentials=/$PWD filter="*.rb *.txt *.md *.conf *.yaml" {
15
20
  insist.rb
16
21
  monitor.rb
17
22
  system.rb
23
+ math.rb
18
24
  }
19
25
  named_array.rb
20
26
  indiferent_hash.rb
@@ -74,5 +80,31 @@ scout-essentials=/$PWD filter="*.rb *.txt *.md *.conf *.yaml" {
74
80
  }
75
81
  test=test{
76
82
  test_helper.rb
83
+ scout=scout{
84
+ test_annotation.rb
85
+ annotation=annotation{
86
+ test_annotated_object.rb
87
+ test_array.rb
88
+ }
89
+ test_cmd.rb
90
+ test_concurrent_stream.rb
91
+ test_config.rb
92
+ test_indiferent_hash.rb
93
+ test_log.rb
94
+ test_misc.rb
95
+ test_named_array.rb
96
+ test_open.rb
97
+ test_path.rb
98
+ test_persist.rb
99
+ test_resource.rb
100
+ test_tmpfile.rb
101
+ misc=misc{
102
+ test_digest.rb
103
+ test_filesystem.rb
104
+ test_helper.rb
105
+ test_insist.rb
106
+ test_system.rb
107
+ }
108
+ }
77
109
  }
78
110
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.1
1
+ 1.4.0
@@ -0,0 +1,69 @@
1
+ module Annotation
2
+ module AnnotatedObject
3
+ def annotations
4
+ @annotations ||= []
5
+ end
6
+
7
+ def annotation_types
8
+ @annotation_types ||= []
9
+ end
10
+
11
+ def annotation_hash
12
+ attr_hash = {}
13
+ @annotations.each do |name|
14
+ attr_hash[name] = self.instance_variable_get("@#{name}")
15
+ end if @annotations
16
+ attr_hash
17
+ end
18
+
19
+ def annotation_info
20
+ annotation_hash.merge(annotation_types: annotation_types, annotated_array: (AnnotatedArray === self))
21
+ end
22
+
23
+ def self.serialize(obj)
24
+ Annotation.purge(obj.annotation_info.merge(literal: obj))
25
+ end
26
+
27
+ def serialize
28
+ AnnotatedObject.serialize(self)
29
+ end
30
+
31
+ def annotation_id
32
+ Misc.digest([self, annotation_info])
33
+ end
34
+
35
+ alias id annotation_id
36
+
37
+ def annotate(other)
38
+ annotation_types.each do |type|
39
+ type.setup(other, annotation_hash)
40
+ end
41
+ other
42
+ end
43
+
44
+ def purge
45
+ new = self.dup
46
+
47
+ if new.instance_variables.include?(:@annotations)
48
+ new.instance_variable_get(:@annotations).each do |a|
49
+ var_name = "@#{a}".to_sym
50
+ new.remove_instance_variable(var_name) if new.instance_variables.include? var_name
51
+ end
52
+ new.remove_instance_variable(:@annotations)
53
+ end
54
+
55
+ if new.instance_variables.include?(:@annotation_types)
56
+ new.remove_instance_variable(:@annotation_types)
57
+ end
58
+
59
+ new
60
+ end
61
+
62
+ def make_array
63
+ new = [self]
64
+ self.annotate(new)
65
+ new.extend AnnotatedArray
66
+ new
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,59 @@
1
+ module Annotation
2
+ module AnnotationModule
3
+ def annotation(*attrs)
4
+ self.instance_variable_get("@annotations").concat attrs
5
+ attrs.each do |a|
6
+ self.attr_accessor a
7
+ end
8
+ end
9
+
10
+ def annotations
11
+ @annotations ||= []
12
+ end
13
+
14
+ def included(mod)
15
+ mod.instance_variable_set(:@annotations, []) unless mod.instance_variables.include?(:@annotations)
16
+ mod.instance_variable_get(:@annotations).concat self.instance_variable_get(:@annotations)
17
+ end
18
+
19
+ def extended(obj)
20
+ attrs = self.instance_variable_get("@annotations")
21
+
22
+ obj.instance_variable_set(:@annotations, []) unless obj.instance_variables.include?(:@annotations)
23
+ obj.annotation_types << self
24
+
25
+ annotations = obj.instance_variable_get(:@annotations)
26
+ annotations.concat attrs
27
+ end
28
+
29
+ def setup(*args,&block)
30
+ if block_given?
31
+ obj, rest = block, args
32
+ else
33
+ obj, *rest = args
34
+ end
35
+ obj = block if obj.nil?
36
+ return nil if obj.nil?
37
+ obj.extend self unless self === obj
38
+ attrs = self.instance_variable_get("@annotations")
39
+
40
+ return obj if attrs.nil? || attrs.empty?
41
+
42
+ if rest.length == 1 && Hash === (rlast = rest.last) &&
43
+ ((! (rlkey = rlast.keys.first).nil? && attrs.include?(rlkey.to_sym)) ||
44
+ (! attrs.length != 1 ))
45
+
46
+ pairs = rlast
47
+ else
48
+ pairs = attrs.zip(rest)
49
+ end
50
+
51
+ pairs.each do |name,value|
52
+ next if name.to_sym === :annotation_types
53
+ obj.instance_variable_set("@#{name}", value) unless value.nil?
54
+ end
55
+
56
+ obj
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,74 @@
1
+ module AnnotatedArray
2
+
3
+ module AnnotatedArrayItem
4
+ attr_accessor :container, :container_index
5
+ end
6
+
7
+ def self.is_contained?(obj)
8
+ AnnotatedArrayItem === obj
9
+ end
10
+
11
+ def annotate_item(obj, position = nil)
12
+ obj = obj.dup if obj.frozen?
13
+ obj.extend AnnotatedArray if Array === obj
14
+ obj.extend AnnotatedArrayItem
15
+ obj.container = self
16
+ obj.container_index = position
17
+ self.annotate(obj)
18
+ end
19
+
20
+ def [](pos, clean = false)
21
+ item = super(pos)
22
+ return item if item.nil? or clean
23
+ annotate_item(item, pos)
24
+ end
25
+
26
+ def first
27
+ annotate_item(super, 0)
28
+ end
29
+
30
+ def last
31
+ annotate_item(super, self.length - 1)
32
+ end
33
+
34
+ def each_with_index(&block)
35
+ super do |item,i|
36
+ block.call annotate_item(item, i)
37
+ end
38
+ end
39
+
40
+ def each(&block)
41
+ i = 0
42
+ super do |item|
43
+ block.call annotate_item(item, i)
44
+ i += 1
45
+ end
46
+ end
47
+
48
+ def inject(acc, &block)
49
+ each do |item|
50
+ acc = block.call acc, item
51
+ end
52
+ acc
53
+ end
54
+
55
+ def collect(&block)
56
+ if block_given?
57
+ inject([]){|acc,item| acc.push(block.call(item)); acc }
58
+ else
59
+ inject([]){|acc,item| acc.push(item); acc }
60
+ end
61
+ end
62
+
63
+ %w(compact uniq flatten reverse sort_by).each do |method|
64
+
65
+ self.define_method(method) do |*args|
66
+ res = super(*args)
67
+
68
+ annotate(res)
69
+ res.extend AnnotatedArray
70
+
71
+ res
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'annotation/array'
2
+ require_relative 'annotation/annotated_object'
3
+ require_relative 'annotation/annotation_module'
4
+
5
+ module Annotation
6
+
7
+ def self.setup(obj, annotation_types, annotation_hash)
8
+ return nil if obj.nil?
9
+ annotation_types = annotation_types.split("|") if String === annotation_types
10
+ annotation_types = [annotation_types] unless Array === annotation_types
11
+ annotation_types.each do |type|
12
+ type = Kernel.const_get(type) if String === type
13
+ type.setup(obj, annotation_hash)
14
+ end
15
+ obj
16
+ end
17
+
18
+ def self.extended(base)
19
+ base.instance_variable_set(:@annotations, []) unless base.instance_variables.include?(:@annotations)
20
+ base.include Annotation::AnnotatedObject
21
+ base.extend Annotation::AnnotationModule
22
+ end
23
+
24
+ def self.is_annotated?(obj)
25
+ obj.instance_variables.include?(:@annotation_types)
26
+ end
27
+
28
+ def self.purge(obj)
29
+ case obj
30
+ when nil
31
+ nil
32
+ when Array
33
+ obj = obj.purge if is_annotated?(obj)
34
+ obj.collect{|e| purge(e) }
35
+ when Hash
36
+ new = {}
37
+ obj.each do |k,v|
38
+ new[purge(k)] = purge(v)
39
+ end
40
+ new
41
+ else
42
+ is_annotated?(obj) ? obj.purge : obj
43
+ end
44
+ end
45
+ end
@@ -223,7 +223,10 @@ module ConcurrentStream
223
223
  self.join if ! @stream_exception && (self.closed? || self.eof?)
224
224
  end
225
225
  else
226
- super(*args)
226
+ begin
227
+ super(*args)
228
+ rescue IOError
229
+ end unless self.closed?
227
230
  end
228
231
  end
229
232
 
data/lib/scout/config.rb CHANGED
@@ -17,16 +17,16 @@ module Scout::Config
17
17
 
18
18
  def self.load_file(file)
19
19
  Log.debug "Loading config file: #{ file }"
20
- TSV.traverse file, :type => :array do |line|
20
+ Open.read(file).split("\n").each do |line|
21
21
  next if line =~ /^#/
22
- key, value, *tokens = line.strip.split(/\s/)
22
+ key, value, *tokens = line.strip.split(/\s+/)
23
23
 
24
24
  self.add_entry(key, value, tokens) if key
25
25
  end
26
26
  end
27
27
 
28
28
  def self.load_config
29
- Scout.etc.config.find_all.reverse.each do |file|
29
+ Path.setup("etc").config.find_all.reverse.each do |file|
30
30
  self.load_file(file)
31
31
  end
32
32
  end
@@ -54,8 +54,9 @@ class DontClose < Exception
54
54
  end
55
55
  end
56
56
 
57
+ class DontPersist < Exception; end
57
58
 
58
- class KeepLocked < Exception
59
+ class KeepLocked < DontPersist
59
60
  attr_accessor :payload
60
61
  def initialize(payload)
61
62
  @payload = payload
@@ -28,7 +28,8 @@ module IndiferentHash
28
28
  end
29
29
 
30
30
  def self.pull_keys(hash, prefix)
31
- new = {}
31
+ IndiferentHash.setup(hash)
32
+ new = hash.include?("#{prefix}_options") ? hash.delete("#{prefix}_options") : {}
32
33
  prefix = prefix.to_s
33
34
  hash.keys.each do |key|
34
35
  if key.to_s =~ /#{ prefix }_(.*)/
@@ -203,7 +203,7 @@ module Log
203
203
  str = str.to_s unless str.nil?
204
204
  return str if Symbol === color
205
205
  color_str = reset ? Term::ANSIColor.reset : ""
206
- color_str << color
206
+ color_str << color if color
207
207
  if str.nil?
208
208
  color_str
209
209
  else
data/lib/scout/log.rb CHANGED
@@ -109,20 +109,19 @@ module Log
109
109
 
110
110
  def self.logfile(file=nil)
111
111
  if file.nil?
112
- @logfile ||= nil
112
+ @@logfile = nil
113
113
  else
114
114
  case file
115
115
  when String
116
- @logfile = File.open(file, :mode => 'a')
117
- @logfile.sync = true
116
+ @@logfile = File.open(file, :mode => 'a')
117
+ @@logfile.sync = true
118
118
  when IO, File
119
- @logfile = file
119
+ @@logfile = file
120
120
  else
121
121
  raise "Unkown logfile format: #{file.inspect}"
122
122
  end
123
123
  end
124
124
  end
125
-
126
125
  def self.up_lines(num = 1)
127
126
  nocolor ? "" : "\033[#{num+1}F\033[2K"
128
127
  end
@@ -142,26 +141,26 @@ module Log
142
141
  MUTEX = Mutex.new
143
142
  def self.log_write(str)
144
143
  MUTEX.synchronize do
145
- if logfile.nil?
144
+ if defined?(@@logfile) && @@logfile
145
+ @@logfile.write str
146
+ else
146
147
  begin
147
148
  STDERR.write str
148
149
  rescue
149
150
  end
150
- else
151
- logfile.write str
152
151
  end
153
152
  end
154
153
  end
155
154
 
156
155
  def self.log_puts(str)
157
156
  MUTEX.synchronize do
158
- if logfile.nil?
157
+ if defined?(@@logfile) && @@logfile
158
+ @@logfile.puts str
159
+ else
159
160
  begin
160
161
  STDERR.puts str
161
162
  rescue
162
163
  end
163
- else
164
- logfile.puts str
165
164
  end
166
165
  end
167
166
  end
@@ -309,6 +308,7 @@ module Log
309
308
  end
310
309
  end
311
310
  end
311
+ Log::LAST.replace "log"
312
312
  end
313
313
 
314
314
  def self.stack(stack)
@@ -5,14 +5,24 @@ module Misc
5
5
  obj.digest_str
6
6
  else
7
7
  case obj
8
- when String
9
- #'\'' << obj << '\''
10
- if Path === obj || ! Open.exists?(obj)
11
- '\'' << obj << '\''
12
- elsif File.directory?(obj)
8
+ when Path
9
+ case
10
+ when File.directory?(obj)
13
11
  "Directory MD5: #{digest_str(Dir.glob(File.join(obj, "*")))}"
12
+ when obj.located? && File.exist?(obj)
13
+ "File MD5: #{Misc.digest_file(obj)}"
14
14
  else
15
- "File MD5: #{Misc.file_md5(obj)}"
15
+ '\'' << obj << '\''
16
+ end
17
+ when String
18
+ if Path.is_filename?(obj) && Open.exists?(obj)
19
+ if File.directory?(obj)
20
+ "Directory MD5: #{digest_str(Dir.glob(File.join(obj, "*")))}"
21
+ else
22
+ "File MD5: #{Misc.digest_file(obj)}"
23
+ end
24
+ else
25
+ obj.dup
16
26
  end
17
27
  when Integer, Symbol
18
28
  obj.to_s
@@ -57,8 +67,29 @@ module Misc
57
67
  def self.file_md5(file)
58
68
  file = file.find if Path === file
59
69
  file = File.expand_path(file)
60
- Persist.persist("MD5:#{file}", :string) do
61
- Digest::MD5.file(file).hexdigest
70
+ Digest::MD5.file(file).hexdigest
71
+ end
72
+
73
+ def self.fast_file_md5(file, sample = 3_000_000)
74
+ size = File.size(file)
75
+ sample_txt = size.to_s << ":"
76
+ File.open(file) do |f|
77
+ sample_txt << f.read(sample)
78
+ f.seek(size/2)
79
+ sample_txt << f.read(sample)
80
+ f.seek(size - sample - 1)
81
+ sample_txt << f.read(sample)
82
+ end
83
+ Digest::MD5.hexdigest(sample_txt)
84
+ end
85
+
86
+ def self.digest_file(file)
87
+ file = file.find if Path === file
88
+ file = File.expand_path(file)
89
+ if File.size(file) > 10_000_000
90
+ fast_file_md5(file)
91
+ else
92
+ file_md5(file)
62
93
  end
63
94
  end
64
95
  end
@@ -22,4 +22,27 @@ module Misc
22
22
  return nil
23
23
  end
24
24
  end
25
+
26
+ def self.tarize(path, dest = nil)
27
+ Misc.in_dir(path) do
28
+ if dest
29
+ CMD.cmd("tar cvfz '#{dest}' '.'")
30
+ else
31
+ CMD.cmd("tar cvfz - '.'", :pipe => true)
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.untar(file, target = '.')
37
+ target = target.find if Path === target
38
+ file = file.find if Path === file
39
+ Misc.in_dir target do
40
+ if IO === file
41
+ CMD.cmd("tar xvfz -", in: file)
42
+ else
43
+ CMD.cmd("tar xvfz '#{file}'")
44
+ end
45
+ end
46
+ end
47
+
25
48
  end
@@ -252,4 +252,36 @@ module Misc
252
252
  end
253
253
  values
254
254
  end
255
+
256
+ def self.timespan(str, default = "s")
257
+
258
+ return - timespan(str[1..-1], default) if str[0] == "-"
259
+
260
+ if str.include?(":")
261
+ seconds, minutes, hours = str.split(":").reverse
262
+ return seconds.to_i + minutes.to_i * 60 + hours.to_i * 60 * 60
263
+ end
264
+
265
+ tokens = {
266
+ "s" => (1),
267
+ "sec" => (1),
268
+ "m" => (60),
269
+ "min" => (60),
270
+ "''" => (1),
271
+ "'" => (60),
272
+ "h" => (60 * 60),
273
+ "d" => (60 * 60 * 24),
274
+ "w" => (60 * 60 * 24 * 7),
275
+ "mo" => (60 * 60 * 24 * 31),
276
+ "y" => (60 * 60 * 24 * 365),
277
+ }
278
+
279
+ tokens[nil] = tokens[default]
280
+ tokens[""] = tokens[default]
281
+ time = 0
282
+ str.scan(/(\d+)(\w*)/).each do |amount, measure|
283
+ time += amount.to_i * tokens[measure]
284
+ end
285
+ time
286
+ end
255
287
  end
@@ -28,4 +28,41 @@ module Misc
28
28
  counts
29
29
  end
30
30
 
31
+ def self.chunk(array, num)
32
+ total = array.length
33
+ current = 0
34
+ while current < total
35
+ last = current + num - 1
36
+ yield array[current..last]
37
+ current = last + 1
38
+ end
39
+ end
40
+
41
+ # Divides the array into +num+ chunks of the same size by placing one
42
+ # element in each chunk iteratively.
43
+ def self.divide(array, num)
44
+ num = 1 if num == 0
45
+ chunks = []
46
+ num.to_i.times do chunks << [] end
47
+ array.each_with_index{|e, i|
48
+ c = i % num
49
+ chunks[c] << e
50
+ }
51
+ chunks
52
+ end
53
+
54
+ # Divides the array into chunks of +num+ same size by placing one
55
+ # element in each chunk iteratively.
56
+ def self.ordered_divide(array, num)
57
+ last = array.length - 1
58
+ chunks = []
59
+ current = 0
60
+ while current <= last
61
+ next_current = [last, current + num - 1].min
62
+ chunks << array[current..next_current]
63
+ current = next_current + 1
64
+ end
65
+ chunks
66
+ end
67
+
31
68
  end