scout-gear 7.3.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +44 -16
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +21 -7
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/rbbt-scout.rb +1 -0
  9. data/lib/scout/cmd.rb +24 -25
  10. data/lib/scout/concurrent_stream.rb +59 -39
  11. data/lib/scout/config.rb +1 -1
  12. data/lib/scout/exceptions.rb +10 -0
  13. data/lib/scout/log/color.rb +15 -12
  14. data/lib/scout/log/progress/report.rb +8 -6
  15. data/lib/scout/log/progress/util.rb +61 -54
  16. data/lib/scout/log/progress.rb +1 -1
  17. data/lib/scout/log/trap.rb +107 -0
  18. data/lib/scout/log.rb +115 -52
  19. data/lib/scout/meta_extension.rb +47 -6
  20. data/lib/scout/misc/digest.rb +12 -3
  21. data/lib/scout/misc/format.rb +24 -7
  22. data/lib/scout/misc/insist.rb +1 -1
  23. data/lib/scout/misc/monitor.rb +22 -0
  24. data/lib/scout/misc/system.rb +58 -0
  25. data/lib/scout/named_array.rb +73 -3
  26. data/lib/scout/offsite/ssh.rb +171 -0
  27. data/lib/scout/offsite/step.rb +83 -0
  28. data/lib/scout/offsite/sync.rb +55 -0
  29. data/lib/scout/offsite.rb +3 -0
  30. data/lib/scout/open/lock/lockfile.rb +587 -0
  31. data/lib/scout/open/lock.rb +9 -2
  32. data/lib/scout/open/remote.rb +16 -1
  33. data/lib/scout/open/stream.rb +146 -83
  34. data/lib/scout/open/util.rb +22 -3
  35. data/lib/scout/open.rb +5 -4
  36. data/lib/scout/path/find.rb +24 -11
  37. data/lib/scout/path/util.rb +40 -0
  38. data/lib/scout/persist/serialize.rb +19 -6
  39. data/lib/scout/persist.rb +29 -13
  40. data/lib/scout/resource/path.rb +57 -0
  41. data/lib/scout/resource/produce.rb +0 -8
  42. data/lib/scout/resource/util.rb +12 -5
  43. data/lib/scout/tmpfile.rb +7 -8
  44. data/lib/scout/tsv/attach.rb +177 -0
  45. data/lib/scout/tsv/change_id.rb +40 -0
  46. data/lib/scout/tsv/dumper.rb +74 -46
  47. data/lib/scout/tsv/index.rb +85 -87
  48. data/lib/scout/tsv/open.rb +160 -85
  49. data/lib/scout/tsv/parser.rb +142 -80
  50. data/lib/scout/tsv/path.rb +1 -2
  51. data/lib/scout/tsv/persist/adapter.rb +15 -45
  52. data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
  53. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -1
  54. data/lib/scout/tsv/persist.rb +4 -0
  55. data/lib/scout/tsv/stream.rb +204 -0
  56. data/lib/scout/tsv/transformer.rb +152 -0
  57. data/lib/scout/tsv/traverse.rb +96 -92
  58. data/lib/scout/tsv/util/filter.rb +9 -0
  59. data/lib/scout/tsv/util/reorder.rb +81 -0
  60. data/lib/scout/tsv/util/select.rb +78 -33
  61. data/lib/scout/tsv/util/unzip.rb +86 -0
  62. data/lib/scout/tsv/util.rb +60 -11
  63. data/lib/scout/tsv.rb +34 -4
  64. data/lib/scout/work_queue/socket.rb +6 -1
  65. data/lib/scout/work_queue/worker.rb +5 -2
  66. data/lib/scout/work_queue.rb +51 -20
  67. data/lib/scout/workflow/definition.rb +23 -3
  68. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  69. data/lib/scout/workflow/deployment.rb +1 -0
  70. data/lib/scout/workflow/step/dependencies.rb +56 -10
  71. data/lib/scout/workflow/step/file.rb +5 -0
  72. data/lib/scout/workflow/step/info.rb +40 -7
  73. data/lib/scout/workflow/step/load.rb +1 -1
  74. data/lib/scout/workflow/step/provenance.rb +9 -7
  75. data/lib/scout/workflow/step/status.rb +43 -0
  76. data/lib/scout/workflow/step.rb +160 -49
  77. data/lib/scout/workflow/task/dependencies.rb +114 -0
  78. data/lib/scout/workflow/task/inputs.rb +40 -32
  79. data/lib/scout/workflow/task.rb +38 -102
  80. data/lib/scout/workflow/usage.rb +48 -18
  81. data/lib/scout/workflow.rb +4 -2
  82. data/lib/scout-gear.rb +2 -0
  83. data/lib/scout.rb +6 -0
  84. data/scout-gear.gemspec +52 -23
  85. data/scout_commands/doc +37 -0
  86. data/scout_commands/find +1 -0
  87. data/scout_commands/offsite +30 -0
  88. data/scout_commands/update +29 -0
  89. data/scout_commands/workflow/info +15 -3
  90. data/scout_commands/workflow/install +102 -0
  91. data/scout_commands/workflow/task +57 -9
  92. data/test/scout/offsite/test_ssh.rb +15 -0
  93. data/test/scout/offsite/test_step.rb +33 -0
  94. data/test/scout/offsite/test_sync.rb +36 -0
  95. data/test/scout/offsite/test_task.rb +0 -0
  96. data/test/scout/open/test_stream.rb +60 -58
  97. data/test/scout/path/test_find.rb +10 -1
  98. data/test/scout/resource/test_path.rb +6 -0
  99. data/test/scout/resource/test_produce.rb +15 -0
  100. data/test/scout/test_meta_extension.rb +25 -0
  101. data/test/scout/test_named_array.rb +24 -0
  102. data/test/scout/test_persist.rb +9 -2
  103. data/test/scout/test_tsv.rb +229 -2
  104. data/test/scout/test_work_queue.rb +65 -41
  105. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  106. data/test/scout/tsv/test_attach.rb +227 -0
  107. data/test/scout/tsv/test_change_id.rb +98 -0
  108. data/test/scout/tsv/test_dumper.rb +1 -1
  109. data/test/scout/tsv/test_index.rb +49 -3
  110. data/test/scout/tsv/test_open.rb +160 -2
  111. data/test/scout/tsv/test_parser.rb +33 -2
  112. data/test/scout/tsv/test_persist.rb +2 -0
  113. data/test/scout/tsv/test_stream.rb +200 -0
  114. data/test/scout/tsv/test_transformer.rb +120 -0
  115. data/test/scout/tsv/test_traverse.rb +88 -3
  116. data/test/scout/tsv/test_util.rb +1 -0
  117. data/test/scout/tsv/util/test_reorder.rb +94 -0
  118. data/test/scout/tsv/util/test_select.rb +25 -11
  119. data/test/scout/tsv/util/test_unzip.rb +112 -0
  120. data/test/scout/work_queue/test_socket.rb +0 -1
  121. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  122. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  123. data/test/scout/workflow/step/test_info.rb +18 -0
  124. data/test/scout/workflow/step/test_status.rb +30 -0
  125. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  126. data/test/scout/workflow/task/test_inputs.rb +67 -14
  127. data/test/scout/workflow/test_definition.rb +18 -0
  128. data/test/scout/workflow/test_documentation.rb +24 -0
  129. data/test/scout/workflow/test_step.rb +112 -3
  130. data/test/scout/workflow/test_task.rb +0 -151
  131. data/test/scout/workflow/test_usage.rb +33 -6
  132. data/test/test_scout.rb +9 -0
  133. metadata +100 -8
  134. data/scout_commands/workflow/task_old +0 -706
@@ -22,7 +22,7 @@ row4 a a id3
22
22
  tsv = TmpFile.with_file(content) do |filename|
23
23
  TSV.open(filename, :persist => false)
24
24
  end
25
-
25
+
26
26
  TmpFile.with_file(content2) do |filename|
27
27
  TSV.open(filename, :data => tsv)
28
28
  end
@@ -41,9 +41,14 @@ row2 a a id3
41
41
  EOF
42
42
 
43
43
  tsv = TmpFile.with_file(content) do |filename|
44
+ tsv = TSV.open(filename, :persist => true)
45
+ tsv.close
46
+ Persist::CONNECTIONS.clear
44
47
  TSV.open(filename, :persist => true)
45
48
  end
46
49
 
50
+ assert_equal "Id", tsv.key_field
51
+
47
52
  assert tsv.respond_to?(:persistence_class)
48
53
  assert_equal TokyoCabinet::HDB, tsv.persistence_class
49
54
 
@@ -79,5 +84,227 @@ row2 a a id3
79
84
  assert_include tsv.keys, 'row2'
80
85
  assert_equal %w(A a), tsv["row2"][0]
81
86
  end
82
- end
83
87
 
88
+ def test_headerless_fields
89
+ content =<<-EOF
90
+ row1 a|aa|aaa b Id1|Id2
91
+ row2 A B Id3
92
+ EOF
93
+
94
+ TmpFile.with_file(content) do |filename|
95
+ tsv = TSV.open(filename, :sep => /\s+/, :fields => [1])
96
+ assert_equal ["a", "aa", "aaa"], tsv["row1"][0]
97
+ assert_equal :double, tsv.type
98
+ assert_equal [%w(a aa aaa)], tsv["row1"]
99
+ end
100
+ end
101
+
102
+ def test_tsv_field_selection
103
+ content =<<-EOF
104
+ #Id ValueA ValueB OtherID
105
+ row1 a|aa|aaa b Id1|Id2
106
+ row2 A B Id3
107
+ EOF
108
+
109
+ TmpFile.with_file(content) do |filename|
110
+ tsv = TSV.open(filename, :sep => /\s+/, :type => :single)
111
+ assert_equal ["ValueA"], tsv.fields
112
+ end
113
+ end
114
+
115
+ def test_tsv_single_from_flat
116
+ content =<<-EOF
117
+ #: :type=:flat
118
+ #Id Value
119
+ row1 1 2
120
+ row2 4
121
+ EOF
122
+
123
+ TmpFile.with_file(content) do |filename|
124
+ tsv = TSV.open(filename, :sep => /\s+/, :type => :single, :key_field => "Value", :fields => ["Id"])
125
+ assert_equal "row1", tsv["1"]
126
+ end
127
+ end
128
+
129
+ def test_key_field
130
+ content =<<-EOF
131
+ #: :sep=/\\s+/#:type=:single
132
+ #Id Value
133
+ a 1
134
+ b 2
135
+ EOF
136
+
137
+ TmpFile.with_file(content) do |filename|
138
+ tsv = TSV.open(filename, :key_field => "Value")
139
+ assert_equal %w(Id), tsv.fields
140
+ assert_equal "Value", tsv.key_field
141
+ assert_equal "a", tsv["1"]
142
+ end
143
+ end
144
+
145
+ def test_fix
146
+ content =<<-EOF
147
+ #: :sep=/\\s+/#:type=:single
148
+ #Id Value
149
+ a 1
150
+ b 2
151
+ EOF
152
+
153
+ TmpFile.with_file(content) do |filename|
154
+ tsv = TSV.open(filename, :key_field => "Value", :fix => Proc.new{|l| if l =~ /1/;then "a 3" else l end})
155
+ assert_equal "a", tsv["3"]
156
+ end
157
+ end
158
+
159
+ def test_flat
160
+ content =<<-EOF
161
+ #: :type=:flat
162
+ #Id Value
163
+ row1 a|aa|aaa
164
+ row2 A|AA|AAA
165
+ EOF
166
+
167
+ TmpFile.with_file(content) do |filename|
168
+ assert TSV.open(filename, :sep => /\s+/, :type => :flat).include? "row1"
169
+ assert TSV.open(filename, :sep => /\s+/, :type => :flat)["row1"].include? "a"
170
+ assert TSV.open(filename, :sep => /\s+/, :type => :flat, :key_field => "Id")["row1"].include? "a"
171
+ assert TSV.open(filename, :sep => /\s+/, :type => :flat, :key_field => "Id", :fields => ["Value"])["row1"].include? "a"
172
+ end
173
+ end
174
+
175
+ def test_tsv_flat_double
176
+ content =<<-EOF
177
+ #Id ValueA ValueB OtherID
178
+ row1 a|aa|aaa b Id1|Id2
179
+ row2 A B Id3
180
+ EOF
181
+
182
+ TmpFile.with_file(content) do |filename|
183
+ tsv = TSV.open(filename, :sep => /\s+/, :type => :flat, :key_field => "ValueA", :fields => ["OtherID"], :merge => true)
184
+ assert tsv["aaa"].include? "Id1"
185
+ assert tsv["aaa"].include? "Id2"
186
+ end
187
+ end
188
+
189
+ def test_flat2single
190
+ content =<<-EOF
191
+ #: :type=:flat
192
+ #Id Value
193
+ row1 a aa aaa
194
+ row2 A AA AAA
195
+ EOF
196
+
197
+ TmpFile.with_file(content) do |filename|
198
+ tsv = TSV.open(filename, :sep => /\s+/, :type => :single, :key_field => "Value")
199
+ assert tsv.include? "aaa"
200
+ end
201
+ end
202
+
203
+ def test_flat_key
204
+ content =<<-EOF
205
+ #Id ValueA
206
+ row1 a aa aaa
207
+ row2 b bbb bbbb bb aa
208
+ EOF
209
+
210
+ TmpFile.with_file(content) do |filename|
211
+ tsv = TSV.open(filename, :sep => /\s+/, :merge => true, :type => :flat, :key_field => "ValueA")
212
+ assert_equal ["row1"], tsv["a"]
213
+ assert_equal ["row1", "row2"], tsv["aa"]
214
+ end
215
+ end
216
+
217
+ def test_unnamed_key
218
+ content =<<-EOF
219
+ row1 a|aa|aaa b Id1|Id2
220
+ row2 A B Id3
221
+ EOF
222
+
223
+ TmpFile.with_file(content) do |filename|
224
+ tsv = TSV.open(filename, :sep => /\s+/, :key_field => 1)
225
+ assert tsv.keys.include? "a"
226
+ end
227
+ end
228
+
229
+ def test_grep
230
+ content =<<-EOF
231
+ #: :sep=/\\s+/#:type=:single
232
+ #Id Value
233
+ a 1
234
+ b 2
235
+ c 3
236
+ EOF
237
+
238
+ TmpFile.with_file(content) do |filename|
239
+ tsv = TSV.open(filename, :key_field => "Value", :grep => "#\\|2")
240
+ assert_includes tsv, "2"
241
+ refute_includes tsv, "3"
242
+ end
243
+ end
244
+
245
+ def TODO_test_tsv_grep
246
+ content =<<-EOF
247
+ #: :sep=/\\s+/#:type=:single
248
+ #Id Value
249
+ a 1
250
+ b 2
251
+ b 3
252
+ d 22
253
+ EOF
254
+
255
+ TmpFile.with_file(content) do |filename|
256
+ tsv = TSV.open(filename, :key_field => "Value", :tsv_grep => "2")
257
+ assert_includes tsv, "2"
258
+ refute_includes tsv, "3"
259
+ assert(tsv.include?("2"))
260
+ assert(! tsv.include?("3"))
261
+ end
262
+ end
263
+
264
+ def test_flat_with_field_header
265
+ content =<<-EOF
266
+ #: :type=:flat
267
+ #Id ValueA
268
+ row1 a aa aaa
269
+ row2 b bbb bbbb bb
270
+ EOF
271
+
272
+ TmpFile.with_file(content) do |filename|
273
+ tsv = TSV.open(filename, :sep => /\s+/, :merge => false)
274
+ assert_equal ["a", "aa", "aaa"], tsv["row1"]
275
+ end
276
+ end
277
+
278
+ def test_alt_args
279
+ content =<<-EOF
280
+ #Id ValueA
281
+ row1 a aa aaa
282
+ row2 b bbb bbbb bb
283
+ EOF
284
+
285
+ TmpFile.with_file(content) do |filename|
286
+ tsv = TSV.open(filename, type: :flat, :sep => /\s+/, :merge => false)
287
+ assert_equal ["a", "aa", "aaa"], tsv["row1"]
288
+ end
289
+
290
+ tsv = TSV.str_setup("ID~ValueA,ValueB#:type=:flat", {})
291
+ assert_equal "ID", tsv.key_field
292
+ end
293
+
294
+ def test_cast_in_header
295
+ content =<<-EOF
296
+ #: :sep=/\\s+/#:type=:single
297
+ #Id Value
298
+ a 1
299
+ b 2
300
+ c 3
301
+ EOF
302
+
303
+ TmpFile.with_file(content) do |filename|
304
+ tsv = TSV.open(filename, :key_field => "Value", :grep => "#\\|2")
305
+ refute tsv.to_s.include?(":cast=:to_f")
306
+ tsv.cast = :to_f
307
+ assert_include tsv.to_s, ":cast=:to_f"
308
+ end
309
+ end
310
+ end
@@ -90,59 +90,83 @@ class TestWorkQueue < Test::Unit::TestCase
90
90
  end
91
91
 
92
92
  def test_queue_error
93
- num = 100
94
- reps = 10_000
95
-
96
- sss 0
97
- q = WorkQueue.new num do |obj|
98
- raise ScoutException if rand < 0.1
99
- [Process.pid.to_s, obj.to_s] * " "
100
- end
101
-
102
- res = []
103
- q.process do |out|
104
- res << out
105
- end
93
+ 5.times do |i|
94
+ num = 100
95
+ reps = 10_000
106
96
 
107
- pid = Process.fork do
108
- reps.times do |i|
109
- q.write i
97
+ q = WorkQueue.new num do |obj|
98
+ raise ScoutException if rand < 0.1
99
+ [Process.pid.to_s, obj.to_s] * " "
110
100
  end
111
- end
112
101
 
113
- Process.waitpid pid
114
- q.close
102
+ res = []
103
+ q.process do |out|
104
+ res << out
105
+ end
115
106
 
116
- assert_raise ScoutException do
117
- q.join
118
- t.join
107
+ Log.with_severity 7 do
108
+ t = Thread.new do
109
+ Thread.current["name"] = "queue writer"
110
+ Thread.current.report_on_exception = false
111
+ reps.times do |i|
112
+ q.write i
113
+ end
114
+ q.close
115
+ end
116
+ Thread.pass until t["name"]
117
+
118
+ assert_raise ScoutException do
119
+ begin
120
+ q.join(false)
121
+ rescue
122
+ t.raise($!)
123
+ raise $!
124
+ ensure
125
+ t.join
126
+ end
127
+ end
128
+ end
119
129
  end
120
130
  end
121
131
 
122
132
  def test_queue_error_in_input
123
- num = 100
124
- reps = 10_000
125
-
126
- q = WorkQueue.new num do |obj|
127
- [Process.pid.to_s, obj.to_s] * " "
128
- end
133
+ 5.times do |i|
134
+ num = 100
135
+ reps = 10_000
129
136
 
130
- res = []
131
- q.process do |out|
132
- raise ScoutException if rand < 0.01
133
- res << out
134
- end
137
+ q = WorkQueue.new num do |obj|
138
+ [Process.pid.to_s, obj.to_s] * " "
139
+ end
135
140
 
136
- pid = Process.fork do
137
- reps.times do |i|
138
- q.write i
141
+ res = []
142
+ q.process do |out|
143
+ raise ScoutException
144
+ res << out
139
145
  end
140
- q.close
141
- end
142
146
 
143
- assert_raise ScoutException do
144
- q.join
145
- t.join
147
+ Log.with_severity 7 do
148
+ t = Thread.new do
149
+ Thread.current.report_on_exception = false
150
+ Thread.current["name"] = "queue writer"
151
+ reps.times do |i|
152
+ q.write i
153
+ end
154
+ q.close
155
+ end
156
+ Thread.pass until t["name"]
157
+
158
+ assert_raise ScoutException do
159
+ begin
160
+ q.join(false)
161
+ rescue Exception
162
+ t.raise($!)
163
+ raise $!
164
+ ensure
165
+ t.join
166
+ q.clean
167
+ end
168
+ end
169
+ end
146
170
  end
147
171
  end
148
172
  end
@@ -21,6 +21,11 @@ row2 a a id3
21
21
 
22
22
  assert_equal %w(a aa aaa), tsv["row1"][0]
23
23
 
24
+ assert TSVAdapter === tsv
25
+ assert TSV === tsv
26
+ assert_include tsv.instance_variable_get(:@extension_attrs), :key_field
27
+ assert_include tsv.instance_variable_get(:@extension_attrs), :serializer
28
+
24
29
  tsv_loaded = assert_nothing_raised do
25
30
  TmpFile.with_file(content) do |filename|
26
31
  Persist.persist(__method__, :HDB) do
@@ -29,6 +34,7 @@ row2 a a id3
29
34
  end
30
35
  end
31
36
 
37
+
32
38
  assert_equal %w(a aa aaa), tsv_loaded["row1"][0]
33
39
  end
34
40
 
@@ -54,7 +60,7 @@ row2 a a id3
54
60
  end
55
61
  end
56
62
 
57
- def test_speed
63
+ def __test_speed
58
64
  tsv = TSV.setup({}, :type => :double, :key_field => "Key", :fields => %w(Field1 Field2))
59
65
 
60
66
  size = 100_000
@@ -88,5 +94,27 @@ row2 a a id3
88
94
  assert_equal tc["key-#{i}"], tsv["key-#{i}"]
89
95
  end
90
96
  end
97
+
98
+ def test_float_array
99
+ content =<<-EOF
100
+ #Id ValueA ValueB OtherID
101
+ row1 0.2 0.3 0
102
+ row2 0.1 4.5 0
103
+ EOF
104
+
105
+ TmpFile.with_file(content) do |filename|
106
+ tsv = TSV.open(filename, :sep => /\s+/, :persist => true, :type => :list, :cast => :to_f)
107
+ tsv.save_extension_attr_hash
108
+ assert_equal [0.2, 0.3, 0], tsv["row1"]
109
+ assert_equal TSVAdapter::FloatArraySerializer, tsv.serializer
110
+ Open.cp tsv.persistence_path, tmpdir.persistence.foo
111
+ tsv2 = ScoutCabinet.open(tmpdir.persistence.foo, false)
112
+ tsv2.extend TSVAdapter
113
+ assert_equal [0.2, 0.3, 0], tsv2["row1"]
114
+ assert_equal TSVAdapter::FloatArraySerializer, tsv2.serializer
115
+ end
116
+
117
+ end
118
+
91
119
  end
92
120
 
@@ -0,0 +1,227 @@
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
+
6
+ class TestTSVAttach < Test::Unit::TestCase
7
+ def test_attach_simple
8
+ content1 =<<-EOF
9
+ #: :sep=" "
10
+ #ID ValueA ValueB
11
+ row1 a|aa|aaa b
12
+ row2 A B
13
+ EOF
14
+
15
+ content2 =<<-EOF
16
+ #: :sep=" "
17
+ #ID ValueB OtherID
18
+ row1 b Id1|Id2
19
+ row3 B Id3
20
+ EOF
21
+
22
+ TmpFile.with_file(content1) do |filename1|
23
+ TmpFile.with_file(content2) do |filename2|
24
+ tsv = TSV.open(filename1)
25
+ other = TSV.open(filename2)
26
+ tsv.attach other, :complete => true
27
+ assert_equal %w(Id1 Id2), tsv["row1"]["OtherID"]
28
+ assert_equal %w(Id3), tsv["row3"]["OtherID"]
29
+ assert_equal %w(B), tsv["row3"]["ValueB"]
30
+ end
31
+ end
32
+ end
33
+
34
+ def test_attach_by_key
35
+ content1 =<<-EOF
36
+ #: :sep=" "
37
+ #ID ValueA ValueB
38
+ row1 A1|A11 B1|B11
39
+ row2 A2|A22 B2|B22
40
+ EOF
41
+
42
+ content2 =<<-EOF
43
+ #: :sep=" "
44
+ #ID ValueB OtherID
45
+ row1 B1|B11 Id1|Id11
46
+ row2.2 B2|B22|B222 Id2.2|Id22.2|Id222.2
47
+ row3 B3 Id3
48
+ EOF
49
+
50
+ TmpFile.with_file(content1) do |filename1|
51
+ TmpFile.with_file(content2) do |filename2|
52
+ tsv = TSV.open(filename1)
53
+ other = TSV.open(filename2)
54
+ tsv.attach other, complete: true, match_key: "ValueB"
55
+ assert_equal %w(A1 A11), tsv["row1"]["ValueA"]
56
+ assert_equal %w(B1 B11), tsv["row1"]["ValueB"]
57
+ assert_equal %w(Id1 Id11), tsv["row1"]["OtherID"]
58
+ assert_equal %w(Id2.2 Id22.2), tsv["row2"]["OtherID"]
59
+ end
60
+ end
61
+ end
62
+
63
+ def test_attach_by_reorder
64
+ content1 =<<-EOF
65
+ #: :sep=" "
66
+ #ID ValueA ValueB
67
+ row1 A1|A11 B1|B11
68
+ row2 A2|A22 B2|B22
69
+ EOF
70
+
71
+ content2 =<<-EOF
72
+ #: :sep=" "
73
+ #ValueB ID OtherID
74
+ B1 row1|row1.1 Id1|Id11
75
+ B2 row2 Id2.2|Id22.2|Id222.2
76
+ B3 row3 Id3
77
+ EOF
78
+
79
+ TmpFile.with_file(content1) do |filename1|
80
+ TmpFile.with_file(content2) do |filename2|
81
+ tsv = TSV.open(filename1)
82
+ other = TSV.open(filename2)
83
+ tsv.attach other, match_key: "ID", one2one: false
84
+ assert_equal %w(A1 A11), tsv["row1"]["ValueA"]
85
+ assert_equal %w(B1 B11), tsv["row1"]["ValueB"]
86
+ assert_equal %w(Id1 Id11), tsv["row1"]["OtherID"]
87
+ assert_equal %w(Id2.2 Id22.2 Id222.2), tsv["row2"]["OtherID"]
88
+ end
89
+ end
90
+ end
91
+
92
+
93
+ def test_attach_same_key
94
+ content1 =<<-EOF
95
+ #ID ValueA ValueB
96
+ row1 a|aa|aaa b
97
+ row2 A B
98
+ EOF
99
+
100
+ content2 =<<-EOF
101
+ #ID ValueB OtherID
102
+ row1 b Id1|Id2
103
+ row3 B Id3
104
+ EOF
105
+
106
+ tsv1 = tsv2 = nil
107
+ TmpFile.with_file(content1) do |filename|
108
+ tsv1 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
109
+ end
110
+
111
+ TmpFile.with_file(content2) do |filename|
112
+ tsv2 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
113
+ end
114
+
115
+ tsv1.attach tsv2, fields: "OtherID"
116
+
117
+ assert_equal %w(ValueA ValueB OtherID), tsv1.fields
118
+ assert_equal %w(Id1 Id2), tsv1["row1"]["OtherID"]
119
+
120
+ TmpFile.with_file(content1) do |filename|
121
+ tsv1 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
122
+ end
123
+
124
+ tsv1.attach tsv2
125
+
126
+ assert_equal %w(ValueA ValueB OtherID), tsv1.fields
127
+
128
+ tsv1 = tsv2 = nil
129
+ TmpFile.with_file(content1) do |filename|
130
+ tsv1 = TSV.open(File.open(filename), type: :list, :sep => /\s+/)
131
+ end
132
+
133
+ TmpFile.with_file(content2) do |filename|
134
+ tsv2 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
135
+ end
136
+
137
+ tsv1.attach tsv2, fields: "OtherID"
138
+
139
+ assert_equal %w(ValueA ValueB OtherID), tsv1.fields
140
+ assert_equal "Id1", tsv1["row1"]["OtherID"]
141
+ end
142
+
143
+ def test_attach_source_field
144
+ content1 =<<-EOF
145
+ #Id ValueA ValueB
146
+ row1 a|aa|aaa b
147
+ row2 A B
148
+ EOF
149
+
150
+ content2 =<<-EOF
151
+ #ValueB OtherID
152
+ b Id1|Id2
153
+ B Id3
154
+ EOF
155
+
156
+ tsv1 = tsv2 = nil
157
+ TmpFile.with_file(content1) do |filename|
158
+ tsv1 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
159
+ end
160
+
161
+ TmpFile.with_file(content2) do |filename|
162
+ tsv2 = TSV.open(File.open(filename), type: :double, :sep => /\s+/)
163
+ end
164
+
165
+ tsv1.attach tsv2, bar: true
166
+
167
+ assert_equal %w(ValueA ValueB OtherID), tsv1.fields
168
+ assert_equal %w(Id1 Id2), tsv1["row1"]["OtherID"]
169
+
170
+ TmpFile.with_file(content1) do |filename|
171
+ tsv1 = TSV.open(File.open(filename), type: :list, :sep => /\s+/)
172
+ end
173
+
174
+ tsv1.attach tsv2
175
+
176
+ assert_equal %w(ValueA ValueB OtherID), tsv1.fields
177
+ assert_equal "Id1", tsv1["row1"]["OtherID"]
178
+ end
179
+
180
+ def test_attach_transformer
181
+ content1 =<<-EOF
182
+ #: :sep=" "
183
+ #ID ValueA ValueB
184
+ row1 a|aa|aaa b
185
+ row2 A B
186
+ EOF
187
+
188
+ content2 =<<-EOF
189
+ #: :sep=" "
190
+ #ID ValueB OtherID
191
+ row1 b Id1|Id2
192
+ row3 B Id3
193
+ EOF
194
+
195
+ TmpFile.with_file(content1) do |filename1|
196
+ TmpFile.with_file(content2) do |filename2|
197
+ out = TSV.attach filename1, filename2, target: :stream, bar: false
198
+ tsv = out.tsv
199
+ assert_equal %w(Id1 Id2), tsv["row1"]["OtherID"]
200
+ end
201
+ end
202
+ end
203
+
204
+ def test_attach_flexible_names
205
+ content1 =<<-EOF
206
+ #: :sep=" "
207
+ #ID ValueA ValueB
208
+ row1 a|aa|aaa b
209
+ row2 A B
210
+ EOF
211
+
212
+ content2 =<<-EOF
213
+ #: :sep=" "
214
+ #Identifiers(ID) OtherID
215
+ row1 Id1|Id2
216
+ row3 Id3
217
+ EOF
218
+
219
+ TmpFile.with_file(content1) do |filename1|
220
+ TmpFile.with_file(content2) do |filename2|
221
+ out = TSV.attach filename1, filename2, target: :stream, bar: false
222
+ tsv = out.tsv
223
+ assert_equal %w(Id1 Id2), tsv["row1"]["OtherID"]
224
+ end
225
+ end
226
+ end
227
+ end