scout-gear 7.2.0 → 7.3.0

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +37 -3
  3. data/VERSION +1 -1
  4. data/lib/scout/concurrent_stream.rb +9 -8
  5. data/lib/scout/exceptions.rb +1 -0
  6. data/lib/scout/log/color.rb +0 -1
  7. data/lib/scout/log/progress/util.rb +65 -0
  8. data/lib/scout/misc/helper.rb +31 -0
  9. data/lib/scout/misc/monitor.rb +1 -1
  10. data/lib/scout/misc.rb +1 -0
  11. data/lib/scout/open/stream.rb +21 -27
  12. data/lib/scout/persist.rb +42 -28
  13. data/lib/scout/semaphore.rb +8 -1
  14. data/lib/scout/tsv/dumper.rb +13 -8
  15. data/lib/scout/tsv/index.rb +127 -15
  16. data/lib/scout/tsv/open.rb +128 -0
  17. data/lib/scout/tsv/parser.rb +70 -43
  18. data/lib/scout/tsv/path.rb +4 -4
  19. data/lib/scout/tsv/persist/adapter.rb +52 -33
  20. data/lib/scout/tsv/persist/fix_width_table.rb +324 -0
  21. data/lib/scout/tsv/persist/serialize.rb +117 -0
  22. data/lib/scout/tsv/persist/tokyocabinet.rb +3 -3
  23. data/lib/scout/tsv/persist.rb +0 -2
  24. data/lib/scout/tsv/traverse.rb +130 -35
  25. data/lib/scout/tsv/util/filter.rb +303 -0
  26. data/lib/scout/tsv/util/process.rb +73 -0
  27. data/lib/scout/tsv/util/select.rb +220 -0
  28. data/lib/scout/tsv/util.rb +77 -19
  29. data/lib/scout/tsv.rb +2 -2
  30. data/lib/scout/work_queue/worker.rb +1 -1
  31. data/lib/scout/workflow/definition.rb +8 -0
  32. data/lib/scout/workflow/step/info.rb +4 -0
  33. data/lib/scout/workflow/step/progress.rb +14 -0
  34. data/lib/scout/workflow/step.rb +10 -5
  35. data/lib/scout/workflow/task.rb +8 -4
  36. data/lib/scout/workflow/usage.rb +2 -0
  37. data/scout-gear.gemspec +33 -10
  38. data/scout_commands/workflow/task +3 -2
  39. data/scout_commands/workflow/task_old +2 -2
  40. data/test/scout/open/test_stream.rb +1 -1
  41. data/test/scout/test_persist.rb +61 -0
  42. data/test/scout/test_tmpfile.rb +1 -1
  43. data/test/scout/test_tsv.rb +10 -1
  44. data/test/scout/test_work_queue.rb +1 -0
  45. data/test/scout/tsv/persist/test_adapter.rb +10 -0
  46. data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
  47. data/test/scout/tsv/test_index.rb +94 -2
  48. data/test/scout/tsv/test_open.rb +9 -0
  49. data/test/scout/tsv/test_parser.rb +28 -3
  50. data/test/scout/tsv/test_persist.rb +7 -0
  51. data/test/scout/tsv/test_traverse.rb +110 -3
  52. data/test/scout/tsv/test_util.rb +23 -0
  53. data/test/scout/tsv/util/test_filter.rb +188 -0
  54. data/test/scout/tsv/util/test_process.rb +47 -0
  55. data/test/scout/tsv/util/test_select.rb +44 -0
  56. data/test/scout/work_queue/test_worker.rb +63 -6
  57. data/test/scout/workflow/step/test_load.rb +3 -3
  58. data/test/scout/workflow/test_step.rb +10 -10
  59. data/test/test_helper.rb +3 -1
  60. metadata +19 -6
@@ -27,7 +27,7 @@ class WorkQueue
27
27
  rescue Interrupt
28
28
  rescue Exception
29
29
  output.write WorkerException.new($!, Process.pid)
30
- exit -1
30
+ Kernel.exit -1
31
31
  end
32
32
  end
33
33
  end
@@ -164,4 +164,12 @@ module Workflow
164
164
  end
165
165
 
166
166
  alias dep_task task_alias
167
+
168
+ def export(*args)
169
+ end
170
+
171
+ alias export_synchronous export
172
+ alias export_asynchronous export
173
+ alias export_exec export
174
+ alias export_stream export
167
175
  end
@@ -101,4 +101,8 @@ class Step
101
101
  def running?
102
102
  ! done? && (info[:pid] && Misc.pid_alive?(info[:pid]))
103
103
  end
104
+
105
+ def exception
106
+ info[:exception]
107
+ end
104
108
  end
@@ -0,0 +1,14 @@
1
+ class Step
2
+ def progress_bar(msg = "Progress", options = nil)
3
+ if Hash === msg and options.nil?
4
+ options = msg
5
+ msg = nil
6
+ end
7
+ options = {} if options.nil?
8
+
9
+ max = options[:max]
10
+ Open.mkdir files_dir
11
+ Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
12
+ end
13
+ end
14
+
@@ -6,6 +6,7 @@ require_relative 'step/file'
6
6
  require_relative 'step/dependencies'
7
7
  require_relative 'step/provenance'
8
8
  require_relative 'step/config'
9
+ require_relative 'step/progress'
9
10
 
10
11
  class Step
11
12
 
@@ -78,7 +79,9 @@ class Step
78
79
  :inputs => inputs, :type => type,
79
80
  :dependencies => dependencies.collect{|d| d.path }
80
81
 
81
- exec
82
+ @result = exec
83
+ @result = @result.respond_to?(:stream) ? @result.stream : @result
84
+ @result
82
85
  rescue Exception => e
83
86
  merge_info :status => :error, :exception => e
84
87
  raise e
@@ -104,6 +107,7 @@ class Step
104
107
  end
105
108
  end
106
109
  end
110
+ @result
107
111
  end
108
112
 
109
113
  def done?
@@ -111,10 +115,10 @@ class Step
111
115
  end
112
116
 
113
117
  def streaming?
114
- @take_stream || IO === @result || StringIO === @result
118
+ @take_stream || IO === @result || StringIO === @result
115
119
  end
116
120
 
117
- def get_stream
121
+ def stream
118
122
  synchronize do
119
123
  if streaming? && ! @result.nil?
120
124
  if @result.next
@@ -137,8 +141,9 @@ class Step
137
141
  end
138
142
 
139
143
  def join
140
- stream = get_stream if streaming?
141
- Open.consume_stream(stream, false) if stream
144
+ io = self.stream if streaming?
145
+ Open.consume_stream(io, false) if io
146
+ self
142
147
  end
143
148
 
144
149
  def produce
@@ -1,4 +1,5 @@
1
1
  require_relative '../meta_extension'
2
+ require_relative '../named_array'
2
3
  require_relative 'step'
3
4
  require_relative 'task/inputs'
4
5
 
@@ -24,7 +25,7 @@ module Task
24
25
  return inputs if deps.nil?
25
26
  deps.inject(inputs) do |acc,dep|
26
27
  workflow, task = dep
27
- next if workflow.nil?
28
+ next acc if workflow.nil? || task.nil?
28
29
  acc += workflow.tasks[task].recursive_inputs
29
30
  end
30
31
  end
@@ -144,13 +145,16 @@ module Task
144
145
 
145
146
  if non_default_inputs.any?
146
147
  hash = Misc.digest(:inputs => input_hash, :dependencies => dependencies)
147
- Log.debug "Hash #{name} - #{hash}: #{Misc.digest_str(:inputs => inputs, :non_default_inputs => non_default_inputs, :dependencies => dependencies)}"
148
+ Log.debug "Hash #{name} - #{hash}: #{Log.fingerprint(:inputs => inputs, :non_default_inputs => non_default_inputs, :dependencies => dependencies)}"
148
149
  id = [id, hash] * "_"
149
150
  end
150
151
 
151
152
  path = directory[id]
152
153
 
153
- NamedArray.setup(inputs, @inputs.collect{|i| i[0] }) if @inputs
154
- Step.new path.find, inputs, dependencies, &self
154
+ Persist.memory(path) do
155
+ Log.debug "Creating job #{path} #{Log.fingerprint inputs} #{Log.fingerprint dependencies}"
156
+ NamedArray.setup(inputs, @inputs.collect{|i| i[0] }) if @inputs
157
+ Step.new path.find, inputs, dependencies, &self
158
+ end
155
159
  end
156
160
  end
@@ -20,6 +20,7 @@ module Task
20
20
  seen = inputs.collect{|name,_| name }
21
21
  dep_inputs = {}
22
22
  deps.each do |dep_workflow,task_name|
23
+ next if task_name.nil?
23
24
  task = dep_workflow.tasks[task_name]
24
25
  next if task.inputs.nil?
25
26
  inputs = task.inputs.reject{|name, _| seen.include? name }
@@ -122,6 +123,7 @@ module Workflow
122
123
  next if seen.include? dep
123
124
  seen << dep
124
125
  workflow, task, *rest = dep
126
+ next if task.nil?
125
127
 
126
128
  key = [workflow, task]
127
129
 
data/scout-gear.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: scout-gear 7.2.0 ruby lib
5
+ # stub: scout-gear 7.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-gear".freeze
9
- s.version = "7.2.0"
9
+ s.version = "7.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Miguel Vazquez".freeze]
14
- s.date = "2023-05-09"
14
+ s.date = "2023-05-12"
15
15
  s.description = "Temporary files, logs, etc.".freeze
16
16
  s.email = "mikisvaz@gmail.com".freeze
17
17
  s.executables = ["scout".freeze]
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  "lib/scout/misc/digest.rb",
51
51
  "lib/scout/misc/filesystem.rb",
52
52
  "lib/scout/misc/format.rb",
53
+ "lib/scout/misc/helper.rb",
53
54
  "lib/scout/misc/insist.rb",
54
55
  "lib/scout/misc/monitor.rb",
55
56
  "lib/scout/misc/system.rb",
@@ -85,13 +86,19 @@ Gem::Specification.new do |s|
85
86
  "lib/scout/tsv.rb",
86
87
  "lib/scout/tsv/dumper.rb",
87
88
  "lib/scout/tsv/index.rb",
89
+ "lib/scout/tsv/open.rb",
88
90
  "lib/scout/tsv/parser.rb",
89
91
  "lib/scout/tsv/path.rb",
90
92
  "lib/scout/tsv/persist.rb",
91
93
  "lib/scout/tsv/persist/adapter.rb",
94
+ "lib/scout/tsv/persist/fix_width_table.rb",
95
+ "lib/scout/tsv/persist/serialize.rb",
92
96
  "lib/scout/tsv/persist/tokyocabinet.rb",
93
97
  "lib/scout/tsv/traverse.rb",
94
98
  "lib/scout/tsv/util.rb",
99
+ "lib/scout/tsv/util/filter.rb",
100
+ "lib/scout/tsv/util/process.rb",
101
+ "lib/scout/tsv/util/select.rb",
95
102
  "lib/scout/work_queue.rb",
96
103
  "lib/scout/work_queue/socket.rb",
97
104
  "lib/scout/work_queue/worker.rb",
@@ -104,6 +111,7 @@ Gem::Specification.new do |s|
104
111
  "lib/scout/workflow/step/file.rb",
105
112
  "lib/scout/workflow/step/info.rb",
106
113
  "lib/scout/workflow/step/load.rb",
114
+ "lib/scout/workflow/step/progress.rb",
107
115
  "lib/scout/workflow/step/provenance.rb",
108
116
  "lib/scout/workflow/task.rb",
109
117
  "lib/scout/workflow/task/inputs.rb",
@@ -165,13 +173,18 @@ Gem::Specification.new do |s|
165
173
  "test/scout/test_work_queue.rb",
166
174
  "test/scout/test_workflow.rb",
167
175
  "test/scout/tsv/persist/test_adapter.rb",
176
+ "test/scout/tsv/persist/test_fix_width_table.rb",
168
177
  "test/scout/tsv/persist/test_tokyocabinet.rb",
169
178
  "test/scout/tsv/test_dumper.rb",
170
179
  "test/scout/tsv/test_index.rb",
180
+ "test/scout/tsv/test_open.rb",
171
181
  "test/scout/tsv/test_parser.rb",
172
182
  "test/scout/tsv/test_persist.rb",
173
183
  "test/scout/tsv/test_traverse.rb",
174
184
  "test/scout/tsv/test_util.rb",
185
+ "test/scout/tsv/util/test_filter.rb",
186
+ "test/scout/tsv/util/test_process.rb",
187
+ "test/scout/tsv/util/test_select.rb",
175
188
  "test/scout/work_queue/test_socket.rb",
176
189
  "test/scout/work_queue/test_worker.rb",
177
190
  "test/scout/workflow/step/test_dependencies.rb",
@@ -190,15 +203,25 @@ Gem::Specification.new do |s|
190
203
  ]
191
204
  s.homepage = "http://github.com/mikisvaz/scout-gear".freeze
192
205
  s.licenses = ["MIT".freeze]
193
- s.rubygems_version = "3.4.11".freeze
206
+ s.rubygems_version = "3.2.15".freeze
194
207
  s.summary = "basic gear for scouts".freeze
195
208
 
196
- s.specification_version = 4
209
+ if s.respond_to? :specification_version then
210
+ s.specification_version = 4
211
+ end
197
212
 
198
- s.add_runtime_dependency(%q<term-ansicolor>.freeze, [">= 0"])
199
- s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
200
- s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
201
- s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
202
- s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
213
+ if s.respond_to? :add_runtime_dependency then
214
+ s.add_runtime_dependency(%q<term-ansicolor>.freeze, [">= 0"])
215
+ s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
216
+ s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
217
+ s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
218
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
219
+ else
220
+ s.add_dependency(%q<term-ansicolor>.freeze, [">= 0"])
221
+ s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
222
+ s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
223
+ s.add_dependency(%q<juwelier>.freeze, ["~> 2.1.0"])
224
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
225
+ end
203
226
  end
204
227
 
@@ -24,7 +24,7 @@ raise MissingParameterException.new :workflow if workflow_name.nil?
24
24
 
25
25
  workflow = Workflow.require_workflow workflow_name
26
26
  task_name = task_name.to_sym if task_name
27
- task = workflow.tasks[task_name.to_sym]
27
+ task = workflow.tasks[task_name.to_sym] if task_name
28
28
 
29
29
  options[:help] = true if task.nil?
30
30
 
@@ -51,11 +51,12 @@ else
51
51
  job.run unless job.done?
52
52
 
53
53
  if options[:print_filepath]
54
+ job.join
54
55
  path = job.path
55
56
  path = path.find if Path === path
56
57
  puts path
57
58
  else
58
- if ! ((c = Open.consume_stream(job.get_stream, false, STDOUT, false)) && c.end_with?("\n"))
59
+ if ! ((c = Open.consume_stream(job.stream, false, STDOUT, false)) && c.end_with?("\n"))
59
60
  puts
60
61
  end
61
62
  end
@@ -656,12 +656,12 @@ when (defined?(RemoteStep) and RemoteStep)
656
656
  end
657
657
  when Step
658
658
  if res.streaming?
659
- io = TSV.get_stream res
659
+ io = TSV.stream res
660
660
  Misc.consume_stream(io, false, out)
661
661
  io.join if io.respond_to? :join
662
662
  elsif IO === res.result
663
663
  begin
664
- io = res.get_stream
664
+ io = res.stream
665
665
  Misc.consume_stream(io, false, out)
666
666
  io.join if io.respond_to? :join
667
667
  rescue Aborted, Interrupt
@@ -5,7 +5,7 @@ require 'scout/path'
5
5
  require 'scout/open'
6
6
 
7
7
  class TestOpenStream < Test::Unit::TestCase
8
- def test_consume_stream
8
+ def test_stream
9
9
  content =<<-EOF
10
10
  1
11
11
  2
@@ -95,6 +95,67 @@ class TestPersist < Test::Unit::TestCase
95
95
  end
96
96
  end
97
97
 
98
+ def test_concurrent
99
+ num = 10
100
+
101
+ s = 0.01
102
+ 10.times do
103
+ TmpFile.with_file do |file|
104
+ output1 = file + '.output1'
105
+ output2 = file + '.output2'
106
+ pid1 = Process.fork do
107
+ Open.purge_pipes
108
+ sleep rand/10.0
109
+ io = Persist.persist("test", :string, :path => file) do
110
+ Open.open_pipe do |sin|
111
+ num.times do |i|
112
+ sin.puts "line-#{i}-#{Process.pid}"
113
+ sleep s
114
+ end
115
+ end
116
+ end
117
+ if IO === io
118
+ Open.consume_stream(io, false)
119
+ else
120
+ Open.write(output1, io)
121
+ end
122
+ end
123
+ pid2 = Process.fork do
124
+ Open.purge_pipes
125
+ sleep rand/10.0
126
+ io = Persist.persist("test", :string, :path => file) do
127
+ Open.open_pipe do |sin|
128
+ num.times do |i|
129
+ sin.puts "line-#{i}-#{Process.pid}"
130
+ sleep s
131
+ end
132
+ end
133
+ end
134
+ if IO === io
135
+ Open.consume_stream(io, false)
136
+ else
137
+ Open.write(output2, io)
138
+ end
139
+ end
140
+ Process.wait
141
+ Process.wait
142
+
143
+ assert File.exist?(output1) || File.exist?(output2)
144
+ [pid1, pid2].zip([output2, output1]).each do |pid, found|
145
+ next unless File.exist?(found)
146
+ assert Open.read(found).include? "-#{pid}\n"
147
+ end
148
+ [pid1, pid2].zip([output1, output2]).each do |pid, found|
149
+ next unless File.exist?(found)
150
+ refute Open.read(found).include? "-#{pid}\n"
151
+ end
152
+ Open.rm file
153
+ Open.rm output1
154
+ Open.rm output2
155
+ end
156
+ end
157
+ end
158
+
98
159
  def __test_speed
99
160
  times = 100_000
100
161
  TmpFile.with_file do |tmpfile|
@@ -10,7 +10,7 @@ class TestTmpFile < Test::Unit::TestCase
10
10
  def test_do_tmp_file
11
11
  content = "Hello World!"
12
12
  TmpFile.with_file(content) do |file|
13
- assert_equal_path content, File.open(file).read
13
+ assert_equal content, File.open(file).read
14
14
  end
15
15
  end
16
16
 
@@ -61,7 +61,15 @@ row2 a a id3
61
61
  EOF
62
62
 
63
63
  tsv = TmpFile.with_file(content) do |filename|
64
- TSV.open(filename, :persist => true)
64
+ TSV.open(filename, :persist => false)
65
+ end
66
+
67
+ assert_include tsv.keys, 'row1'
68
+ assert_include tsv.keys, 'row2'
69
+ assert_equal %w(A a), tsv["row2"][0]
70
+
71
+ tsv = TmpFile.with_file(content) do |filename|
72
+ TSV.open(filename, :persist => true, :merge => true)
65
73
  end
66
74
 
67
75
  assert tsv.respond_to?(:persistence_class)
@@ -69,6 +77,7 @@ row2 a a id3
69
77
 
70
78
  assert_include tsv.keys, 'row1'
71
79
  assert_include tsv.keys, 'row2'
80
+ assert_equal %w(A a), tsv["row2"][0]
72
81
  end
73
82
  end
74
83
 
@@ -93,6 +93,7 @@ class TestWorkQueue < Test::Unit::TestCase
93
93
  num = 100
94
94
  reps = 10_000
95
95
 
96
+ sss 0
96
97
  q = WorkQueue.new num do |obj|
97
98
  raise ScoutException if rand < 0.1
98
99
  [Process.pid.to_s, obj.to_s] * " "
@@ -30,5 +30,15 @@ class TestTSVAdapter < Test::Unit::TestCase
30
30
  assert_equal [["a", %w(1 2 3)], ["b", %w(11 22 33)]], tsv.sort
31
31
  assert_equal [["b", %w(11 22 33)], ["a", %w(1 2 3)]], tsv.sort_by{|k,v| -v[0].to_i }
32
32
  end
33
+
34
+ def test_serializer
35
+ tsv = TSV.setup({}, :type => :list, :key_field => "Key", :fields => %w(one two three))
36
+ tsv.type = :list
37
+ tsv.extend TSVAdapter
38
+ tsv.serializer = :integer_array
39
+ tsv["a"] = [1, 2, 3]
40
+
41
+ assert_equal [1, 2, 3], tsv["a"]
42
+ end
33
43
  end
34
44
 
@@ -0,0 +1,134 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ require 'scout/tsv'
5
+ class TestFixWidthTable < Test::Unit::TestCase
6
+ def load_data(data)
7
+ tsv = TSV.open(data, type: :list, :sep=>":", :cast => proc{|e| e =~ /(\s*)(_*)/; ($1.length..($1.length + $2.length - 1))})
8
+ tsv.add_field "Start" do |key, values|
9
+ values["Range"].first
10
+ end
11
+ tsv.add_field "End" do |key, values|
12
+ values["Range"].last
13
+ end
14
+
15
+ tsv = tsv.slice ["Start", "End"]
16
+
17
+ tsv
18
+ end
19
+
20
+ def test_options
21
+ TmpFile.with_file do |filename|
22
+ f = FixWidthTable.new filename, 100, true
23
+ f.close
24
+
25
+ f1 = FixWidthTable.new filename, 100, false
26
+
27
+ assert_equal true, f1.range
28
+ end
29
+ end
30
+
31
+ def test_add
32
+ TmpFile.with_file do |filename|
33
+ f = FixWidthTable.new filename, 100, true
34
+ f.add [1,2,0], "test1"
35
+ f.add [3,4,0], "test2"
36
+ f.read
37
+
38
+ assert_equal 1, f.idx_pos(0)
39
+ assert_equal 3, f.idx_pos(1)
40
+ assert_equal 2, f.idx_pos_end(0)
41
+ assert_equal 4, f.idx_pos_end(1)
42
+ assert_equal 0, f.idx_overlap(0)
43
+ assert_equal 0, f.idx_overlap(1)
44
+ assert_equal "test1", f.idx_value(0)
45
+ assert_equal "test2", f.idx_value(1)
46
+
47
+ end
48
+
49
+ end
50
+
51
+ def test_point
52
+ data =<<-EOF
53
+ #: :sep=/\\s+/#:type=:single#:cast=:to_i
54
+ #ID Pos
55
+ a 1
56
+ b 10
57
+ c 20
58
+ d 12
59
+ e 26
60
+ f 11
61
+ g 25
62
+ EOF
63
+ TmpFile.with_file(data) do |datafile|
64
+ tsv = TSV.open datafile
65
+ TmpFile.with_file do |filename|
66
+ f = FixWidthTable.new filename, 100, false
67
+ f.add_point tsv
68
+ f.read
69
+
70
+ assert_equal %w(), f[0].sort
71
+ assert_equal %w(b), f[10].sort
72
+ assert_equal %w(a b c d f), f[(0..20)].sort
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_range
78
+ data =<<-EOF
79
+ ##012345678901234567890
80
+ #ID:Range
81
+ a: ______
82
+ b: ______
83
+ c: _______
84
+ d: ____
85
+ e: ______
86
+ f: ___
87
+ g: ____
88
+ EOF
89
+ TmpFile.with_file(data) do |datafile|
90
+ tsv = load_data(datafile)
91
+ TmpFile.with_file do |filename|
92
+ f = FixWidthTable.new filename, 100, true
93
+ f.add_range tsv
94
+ f.read
95
+
96
+ assert_equal %w(), f[0].sort
97
+ assert_equal %w(b), f[1].sort
98
+ assert_equal %w(), f[20].sort
99
+ assert_equal %w(), f[(20..100)].sort
100
+ assert_equal %w(a b d), f[3].sort
101
+ assert_equal %w(a b c d e), f[(3..4)].sort
102
+ assert_equal %w(a c e), f[7].sort
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+ def test_range_pos
109
+ data =<<-EOF
110
+ ##012345678901234567890
111
+ #ID:Range
112
+ a: ______
113
+ b: ______
114
+ c: _______
115
+ d: ____
116
+ e: ______
117
+ f: ___
118
+ g: ____
119
+ EOF
120
+ TmpFile.with_file(data) do |datafile|
121
+ tsv = load_data(datafile)
122
+ TmpFile.with_file do |filename|
123
+ f = FixWidthTable.new filename, 100, true
124
+ f.add_range tsv
125
+ f.read
126
+
127
+ assert_equal %w(), f.overlaps(0).sort
128
+ assert_equal %w(1:6), f.overlaps(1).sort
129
+ assert_equal %w(1:6:b), f.overlaps(1, true).sort
130
+ end
131
+ end
132
+ end
133
+ end
134
+