scout-gear 7.3.0 → 8.0.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +20 -9
  3. data/VERSION +1 -1
  4. data/bin/scout +6 -3
  5. data/lib/rbbt-scout.rb +1 -0
  6. data/lib/scout/cmd.rb +1 -1
  7. data/lib/scout/concurrent_stream.rb +26 -23
  8. data/lib/scout/config.rb +1 -1
  9. data/lib/scout/log/color.rb +4 -1
  10. data/lib/scout/log/progress/report.rb +1 -1
  11. data/lib/scout/log/progress/util.rb +58 -54
  12. data/lib/scout/log/progress.rb +1 -1
  13. data/lib/scout/log/trap.rb +107 -0
  14. data/lib/scout/log.rb +56 -21
  15. data/lib/scout/meta_extension.rb +13 -6
  16. data/lib/scout/misc/digest.rb +1 -1
  17. data/lib/scout/misc/format.rb +12 -0
  18. data/lib/scout/misc/insist.rb +1 -1
  19. data/lib/scout/misc/monitor.rb +11 -0
  20. data/lib/scout/misc/system.rb +10 -0
  21. data/lib/scout/named_array.rb +65 -3
  22. data/lib/scout/open/lock/lockfile.rb +587 -0
  23. data/lib/scout/open/lock.rb +28 -2
  24. data/lib/scout/open/remote.rb +4 -0
  25. data/lib/scout/open/stream.rb +90 -15
  26. data/lib/scout/open/util.rb +13 -3
  27. data/lib/scout/path/find.rb +9 -1
  28. data/lib/scout/path/util.rb +35 -0
  29. data/lib/scout/persist/serialize.rb +18 -5
  30. data/lib/scout/persist.rb +28 -12
  31. data/lib/scout/resource/path.rb +53 -0
  32. data/lib/scout/resource/produce.rb +0 -8
  33. data/lib/scout/resource/util.rb +2 -1
  34. data/lib/scout/tmpfile.rb +7 -8
  35. data/lib/scout/tsv/attach.rb +177 -0
  36. data/lib/scout/tsv/change_id.rb +40 -0
  37. data/lib/scout/tsv/dumper.rb +72 -46
  38. data/lib/scout/tsv/index.rb +69 -13
  39. data/lib/scout/tsv/open.rb +138 -84
  40. data/lib/scout/tsv/parser.rb +135 -80
  41. data/lib/scout/tsv/path.rb +1 -2
  42. data/lib/scout/tsv/persist/adapter.rb +15 -45
  43. data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
  44. data/lib/scout/tsv/persist/tokyocabinet.rb +4 -1
  45. data/lib/scout/tsv/persist.rb +4 -0
  46. data/lib/scout/tsv/transformer.rb +141 -0
  47. data/lib/scout/tsv/traverse.rb +96 -92
  48. data/lib/scout/tsv/util/filter.rb +9 -0
  49. data/lib/scout/tsv/util/reorder.rb +81 -0
  50. data/lib/scout/tsv/util/select.rb +78 -33
  51. data/lib/scout/tsv/util/unzip.rb +86 -0
  52. data/lib/scout/tsv/util.rb +60 -11
  53. data/lib/scout/tsv.rb +26 -3
  54. data/lib/scout/work_queue/socket.rb +6 -1
  55. data/lib/scout/work_queue/worker.rb +5 -2
  56. data/lib/scout/work_queue.rb +15 -8
  57. data/lib/scout/workflow/definition.rb +21 -2
  58. data/lib/scout/workflow/step/dependencies.rb +24 -4
  59. data/lib/scout/workflow/step/info.rb +36 -5
  60. data/lib/scout/workflow/step/provenance.rb +8 -7
  61. data/lib/scout/workflow/step/status.rb +45 -0
  62. data/lib/scout/workflow/step.rb +100 -34
  63. data/lib/scout/workflow/task/inputs.rb +14 -20
  64. data/lib/scout/workflow/task.rb +81 -46
  65. data/lib/scout/workflow/usage.rb +8 -6
  66. data/scout-gear.gemspec +24 -20
  67. data/scout_commands/workflow/task +34 -7
  68. data/test/scout/open/test_stream.rb +60 -58
  69. data/test/scout/path/test_find.rb +10 -1
  70. data/test/scout/resource/test_produce.rb +15 -0
  71. data/test/scout/test_meta_extension.rb +25 -0
  72. data/test/scout/test_named_array.rb +18 -0
  73. data/test/scout/test_persist.rb +6 -0
  74. data/test/scout/test_tsv.rb +212 -2
  75. data/test/scout/test_work_queue.rb +21 -19
  76. data/test/scout/tsv/persist/test_adapter.rb +1 -1
  77. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  78. data/test/scout/tsv/test_attach.rb +227 -0
  79. data/test/scout/tsv/test_change_id.rb +98 -0
  80. data/test/scout/tsv/test_dumper.rb +1 -1
  81. data/test/scout/tsv/test_index.rb +35 -3
  82. data/test/scout/tsv/test_open.rb +160 -2
  83. data/test/scout/tsv/test_parser.rb +19 -2
  84. data/test/scout/tsv/test_persist.rb +2 -0
  85. data/test/scout/tsv/test_transformer.rb +108 -0
  86. data/test/scout/tsv/test_traverse.rb +88 -3
  87. data/test/scout/tsv/test_util.rb +1 -0
  88. data/test/scout/tsv/util/test_reorder.rb +94 -0
  89. data/test/scout/tsv/util/test_select.rb +25 -11
  90. data/test/scout/tsv/util/test_unzip.rb +112 -0
  91. data/test/scout/work_queue/test_socket.rb +0 -1
  92. data/test/scout/workflow/step/test_status.rb +31 -0
  93. data/test/scout/workflow/task/test_inputs.rb +14 -14
  94. data/test/scout/workflow/test_step.rb +3 -3
  95. data/test/scout/workflow/test_task.rb +168 -32
  96. data/test/scout/workflow/test_usage.rb +33 -6
  97. metadata +20 -6
@@ -1,61 +1,56 @@
1
1
  require_relative '../open'
2
+ require_relative '../work_queue'
3
+
4
+ module MultipleResult
5
+ def self.setup(obj)
6
+ obj.extend MultipleResult
7
+ obj
8
+ end
9
+ end
10
+
2
11
  module Open
3
12
  def self.traverse_add(into, res)
4
- case into
5
- when TSV::Dumper
6
- into.add *res
7
- when TSV, Hash
8
- key, value = res
9
- into[key] = value
13
+ if Array === res && MultipleResult === res
14
+ res.each do |_res|
15
+ traverse_add into, _res
16
+ end
17
+ else
18
+ case into
19
+ when defined?(TSV::Dumper) && TSV::Dumper
20
+ into.add *res
21
+ when TSV, Hash
22
+ key, value = res
23
+ if into.type == :double
24
+ into.zip_new key, value, insitu: false
25
+ else
26
+ into[key] = value
27
+ end
28
+ when Array, Set
29
+ into << res
30
+ when IO, StringIO
31
+ into.puts res
32
+ end
10
33
  end
11
34
  end
12
35
 
13
- #def self.traverse(obj, into: nil, cpus: nil, bar: nil, **options, &block)
14
- # case obj
15
- # when TSV
16
- # obj.traverse options[:key_field], options[:fields], **options do |k,v|
17
- # res = yield k, v
18
- # end
19
- # when String
20
- # f = Open.open(obj)
21
- # self.traverse(f, into: into, cpus: cpus, bar: bar, **options, &block)
22
- # when Step
23
- # self.traverse(obj.stream, into: into, cpus: cpus, bar: bar, **options, &block)
24
- # when IO
25
- # if into && (IO === into || into.respond_to?(:stream) )
26
- # into_thread = Thread.new do
27
- # Thread.current.report_on_exception = false
28
- # Thread.current["name"] = "Traverse into"
29
- # TSV.parse obj, **options do |k,v|
30
- # begin
31
- # res = block.call k, v
32
- # traverse_add into, res
33
- # rescue
34
- # into.abort $!
35
- # end
36
- # nil
37
- # end
38
- # into.close if into.respond_to?(:close)
39
- # end
40
- # Thread.pass until into_thread
41
- # into
42
- # else
43
- # TSV.parse obj, **options do |k,v|
44
- # block.call k, v
45
- # nil
46
- # end
47
- # end
48
- # end
49
- #end
50
-
51
- def self.traverse(obj, into: nil, cpus: nil, bar: nil, callback: nil, unnamed: true, **options, &block)
36
+ def self.traverse(obj, into: nil, cpus: nil, bar: nil, callback: nil, unnamed: true, keep_open: false, **options, &block)
37
+ cpus = nil if cpus == 1
38
+
39
+ if into == :stream
40
+ sout, sin = Open.pipe
41
+ ConcurrentStream.setup(sout, :pair => sin)
42
+ ConcurrentStream.setup(sin, :pair => sout)
43
+ self.traverse(obj, into: sin, cpus: cpus, bar: bar, callback: callback, unnamed: unnamed, **options, &block)
44
+ return sout
45
+ end
52
46
 
53
47
  if into || bar
54
48
  orig_callback = callback if callback
55
- bar = Log::ProgressBar.get_obj_bar(bar, obj)
49
+ bar = Log::ProgressBar.get_obj_bar(obj, bar) if bar
50
+ bar.init if bar
56
51
  callback = proc do |res|
57
52
  bar.tick if bar
58
- traverse_add into, res if into
53
+ traverse_add into, res if into && ! res.nil?
59
54
  orig_callback.call res if orig_callback
60
55
  end
61
56
 
@@ -65,59 +60,94 @@ module Open
65
60
  Thread.current["name"] = "Traverse into"
66
61
  error = false
67
62
  begin
68
- self.traverse(obj, callback: callback, **options, &block)
69
- into.close if into.respond_to?(:close)
63
+ self.traverse(obj, callback: callback, cpus: cpus, unnamed: unnamed, **options, &block)
64
+ into.close if ! keep_open && into.respond_to?(:close)
70
65
  bar.remove if bar
71
66
  rescue Exception
72
67
  into.abort($!) if into.respond_to?(:abort)
73
68
  bar.remove($!) if bar
74
69
  end
75
70
  end
76
- Thread.pass until into_thread
71
+ Thread.pass until into_thread["name"]
77
72
  return into
78
73
  end
79
74
  end
80
75
 
81
- begin
82
- case obj
83
- when TSV
84
- obj.traverse options[:key_field], options[:fields], unnamed: unnamed, **options do |k,v|
85
- res = block.call(k, v)
86
- callback.call res if callback
87
- nil
88
- end
89
- when Array
90
- obj.each do |line|
91
- res = block.call(line)
92
- callback.call res if callback
93
- nil
94
- end
95
- when String
96
- f = Open.open(obj)
97
- self.traverse(f, cpus: cpus, callback: callback, **options, &block)
98
- when Step
99
- raise obj.exception if obj.error?
100
- self.traverse(obj.stream, cpus: cpus, callback: callback, **options, &block)
101
- when IO
102
- TSV.parse obj, **options do |k,v|
103
- res = block.call k, v
104
- callback.call res if callback
105
- nil
106
- end
107
- else
108
- TSV.parse obj, **options do |k,v|
109
- res = block.call k, v
110
- callback.call res if callback
111
- nil
112
- end
76
+ if cpus
77
+ queue = WorkQueue.new cpus do |args|
78
+ block.call *args
79
+ end
80
+
81
+ queue.process do |res|
82
+ callback.call res
83
+ end
84
+
85
+ self.traverse(obj, **options) do |*args|
86
+ queue.write args
87
+ end
88
+
89
+ begin
90
+ queue.close
91
+
92
+ queue.join
93
+
94
+ bar.remove if bar
95
+ return into
96
+ rescue Exception
97
+ bar.remove($!) if bar
98
+ raise $!
113
99
  end
100
+ end
101
+
102
+ begin
103
+ res = case obj
104
+ when TSV
105
+ #obj.traverse options[:key_field], options[:fields], unnamed: unnamed, **options do |k,v,f|
106
+ obj.traverse unnamed: unnamed, **options do |k,v,f|
107
+ res = block.call(k, v, f)
108
+ callback.call res if callback
109
+ nil
110
+ end
111
+ when Array
112
+ obj.each do |line|
113
+ res = block.call(line)
114
+ callback.call res if callback
115
+ nil
116
+ end
117
+ when String
118
+ obj = obj.produce_and_find if Path === obj
119
+ f = Open.open(obj)
120
+ self.traverse(f, cpus: cpus, callback: callback, **options, &block)
121
+ when Step
122
+ raise obj.exception if obj.error?
123
+ self.traverse(obj.stream, cpus: cpus, callback: callback, **options, &block)
124
+ when IO
125
+ parser = TSV::Parser.new obj
126
+ parser.traverse **options do |k,v,f|
127
+ res = block.call k,v,f
128
+ callback.call res if callback
129
+ nil
130
+ end
131
+ when TSV::Parser
132
+ obj.traverse **options do |k,v,f|
133
+ res = block.call k, v, f
134
+ callback.call res if callback
135
+ nil
136
+ end
137
+ else
138
+ TSV.parse obj, **options do |k,v|
139
+ res = block.call k, v
140
+ callback.call res if callback
141
+ nil
142
+ end
143
+ end
114
144
  bar.remove if bar
115
145
  rescue
116
- bar.abort($!) if bar
146
+ bar.error if bar
117
147
  raise $!
118
148
  end
119
149
 
120
- into
150
+ into || res
121
151
  end
122
152
  end
123
153
 
@@ -125,4 +155,28 @@ module TSV
125
155
  def self.traverse(*args, **kwargs, &block)
126
156
  Open.traverse(*args, **kwargs, &block)
127
157
  end
158
+
159
+ def self.process_stream(stream, header_hash: "#", &block)
160
+ sout = Open.open_pipe do |sin|
161
+ while line = stream.gets
162
+ break unless line.start_with?(header_hash)
163
+ sin.puts line
164
+ end
165
+ yield sin, line
166
+ end
167
+ end
168
+
169
+ def self.collapse_stream(stream, *args, **kwargs, &block)
170
+ stream = stream.stream if stream.respond_to?(:stream)
171
+ self.process_stream(stream) do |sin, line|
172
+ collapsed = Open.collapse_stream(stream, line: line)
173
+ Open.consume_stream(collapsed, false, sin)
174
+ end
175
+ end
176
+
177
+ def collapse_stream(*args, **kwargs, &block)
178
+ TSV.collapse_stream(self.dumper_stream, *args, **kwargs, &block)
179
+ end
180
+
181
+
128
182
  end
@@ -12,17 +12,24 @@ module TSV
12
12
  end
13
13
  end
14
14
 
15
- def self.parse_line(line, type: :list, key: 0, positions: nil, sep: "\t", sep2: "|", cast: nil)
15
+ def self.parse_line(line, type: :list, key: 0, positions: nil, sep: "\t", sep2: "|", cast: nil, select: nil, field_names: nil)
16
16
  items = line.split(sep, -1)
17
17
 
18
+ return nil if select && ! TSV.select(items[0], items[1..-1], select, fields: field_names, type: type, sep: sep2)
19
+
18
20
  if positions.nil? && key == 0
19
21
  key = items.shift
20
- elsif positions.nil?
21
- key = items.delete_at(key)
22
+ elsif positions.nil?
23
+ if type == :flat
24
+ key = items[1..-1].collect{|e| e.split(sep2, -1) }.flatten
25
+ items = items.slice(0,1)
26
+ else
27
+ key = items.delete_at(key)
28
+ end
22
29
  key = key.split(sep2) if type == :double
23
30
  else
24
31
  key, items = items[key], items.values_at(*positions)
25
- key = key.split(sep2) if type == :double
32
+ key = key.split(sep2) if type == :double || type == :flat
26
33
  end
27
34
 
28
35
  items = case type
@@ -31,9 +38,9 @@ module TSV
31
38
  when :single
32
39
  items.first
33
40
  when :flat
34
- [items]
41
+ items.collect{|i| i.split(sep2, -1) }.flatten
35
42
  when :double
36
- items.collect{|i| i.split(sep2, -1) }
43
+ items.collect{|i| i.nil? ? [] : i.split(sep2, -1) }
37
44
  end
38
45
 
39
46
 
@@ -44,21 +51,34 @@ module TSV
44
51
  [key, items]
45
52
  end
46
53
 
47
- def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, **kargs, &block)
54
+ def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, field_names: nil, **kargs, &block)
48
55
  begin
49
- bar = Log::ProgressBar.new_bar(bar) if bar
56
+ bar = "Parsing #{Log.fingerprint stream}" if TrueClass === bar
57
+ bar = Log::ProgressBar.get_obj_bar(stream, bar) if bar
58
+ bar.init if bar
50
59
 
51
60
  source_type = type if source_type.nil?
52
61
 
53
62
  data = {} if data.nil?
54
- merge = false if type != :double
63
+ merge = false if type != :double && type != :flat
55
64
  line = first_line || stream.gets
56
65
  while line
57
66
  begin
58
- line.strip!
59
- line = Misc.fixutf8(line) if fix
67
+ line.chomp!
68
+ if Proc === fix
69
+ line = fix.call line
70
+ elsif fix
71
+ line = Misc.fixutf8(line)
72
+ end
60
73
  bar.tick if bar
61
- key, items = parse_line(line, type: source_type, **kargs)
74
+ if type == :array || type == :line
75
+ block.call line
76
+ next
77
+ end
78
+
79
+ key, items = parse_line(line, type: source_type, field_names: field_names, **kargs)
80
+
81
+ next if key.nil?
62
82
 
63
83
  if Array === key
64
84
  keys = key
@@ -116,44 +136,63 @@ module TSV
116
136
  end
117
137
 
118
138
  if block_given?
119
- res = block.call(key, these_items)
139
+ res = block.call(key, these_items, field_names)
120
140
  data[key] = res unless res.nil? || FalseClass === data
121
141
  next
122
142
  end
123
143
 
124
144
  if ! merge || ! data.include?(key)
125
145
  data[key] = these_items
126
- else
146
+ elsif type == :double
127
147
  current = data[key]
128
148
  if merge == :concat
129
149
  these_items.each_with_index do |new,i|
130
- next if new.empty?
150
+ new = [nil] if new.empty?
131
151
  current[i].concat(new)
132
152
  end
133
153
  else
134
154
  merged = []
135
155
  these_items.each_with_index do |new,i|
136
- next if new.empty?
156
+ new = [nil] if new.empty?
137
157
  merged[i] = current[i] + new
138
158
  end
139
159
  data[key] = merged
140
160
  end
161
+ elsif type == :flat
162
+ current = data[key]
163
+ if merge == :concat
164
+ current[i].concat these_items
165
+ else
166
+ data[key] = current + these_items
167
+ end
141
168
  end
142
169
  end
170
+ rescue Exception
171
+ stream.abort($!) if stream.respond_to?(:abort)
172
+ raise $!
143
173
  ensure
144
- line = stream.gets
174
+ if stream.closed?
175
+ line = nil
176
+ else
177
+ line = stream.gets
178
+ end
145
179
  end
146
180
  end
147
181
  data
148
182
  ensure
149
- Log::ProgressBar.remove_bar(bar) if bar
183
+ if stream.stream_exception
184
+ bar.remove(stream.stream_exception)
185
+ else
186
+ bar.remove
187
+ end if bar
188
+ stream.join if stream.respond_to?(:join)
150
189
  end
151
190
  end
152
191
 
153
192
  def self.parse_header(stream, fix: true, header_hash: '#', sep: "\t")
154
193
  raise "Closed stream" if IO === stream && stream.closed?
155
194
 
156
- options = {}
195
+ opts = {}
157
196
  preamble = []
158
197
 
159
198
  # Get line
@@ -165,13 +204,19 @@ module TSV
165
204
 
166
205
  # Process options line
167
206
  if line and (String === header_hash && m = line.match(/^#{header_hash}: (.*)/))
168
- options = IndiferentHash.string2hash m.captures.first.chomp
207
+ opts = IndiferentHash.string2hash m.captures.first.chomp
169
208
  line = stream.gets
170
- line = Misc.fixutf8 line.chomp if line && fix
209
+ if line && fix
210
+ if Proc === fix
211
+ line = fix.call line
212
+ else
213
+ line = Misc.fixutf8 line.chomp if line && fix
214
+ end
215
+ end
171
216
  end
172
217
 
173
218
  # Determine separator
174
- sep = options[:sep] if options[:sep]
219
+ sep = opts[:sep] if opts[:sep]
175
220
 
176
221
  # Process fields line
177
222
  preamble << line if line
@@ -192,7 +237,10 @@ module TSV
192
237
 
193
238
  first_line = line
194
239
 
195
- [options, key_field, fields, first_line, preamble]
240
+ opts[:type] = opts[:type].to_sym if opts[:type]
241
+ opts[:cast] = opts[:cast].to_sym if opts[:cast]
242
+
243
+ [opts, key_field, fields, first_line, preamble]
196
244
  end
197
245
 
198
246
  KEY_PARAMETERS = begin
@@ -204,43 +252,79 @@ module TSV
204
252
  end
205
253
 
206
254
  class Parser
207
- attr_accessor :stream, :options, :key_field, :fields, :first_line, :preamble
208
- def initialize(file, fix: true, header_hash: "#", sep: "\t")
255
+ attr_accessor :stream, :options, :key_field, :fields, :type, :first_line, :preamble
256
+ def initialize(file, fix: true, header_hash: "#", sep: "\t", type: :double)
209
257
  if IO === file
210
258
  @stream = file
211
259
  else
212
260
  @stream = Open.open(file)
213
261
  end
262
+ @fix = fix
214
263
  @options, @key_field, @fields, @first_line, @preamble = TSV.parse_header(@stream, fix:fix, header_hash:header_hash, sep:sep)
215
264
  @options[:sep] = sep if @options[:sep].nil?
265
+ @options.merge!(:key_field => @key_field, :fields => @fields)
266
+ @type = type
216
267
  end
217
268
 
218
269
  def all_fields
270
+ return nil if @fields.nil?
219
271
  [@key_field] + @fields
220
272
  end
221
273
 
274
+ def key_field=(key_field)
275
+ @options[:key_field] = @key_field = key_field
276
+ end
277
+
278
+ def fields=(fields)
279
+ @options[:fields] = @fields = fields
280
+ end
281
+
282
+ def identify_field(name)
283
+ TSV.identify_field(@key_field, @fields, name)
284
+ end
285
+
222
286
  def traverse(key_field: nil, fields: nil, filename: nil, namespace: nil, **kwargs, &block)
287
+ kwargs[:type] ||= self.options[:type] ||= @type
288
+ kwargs[:type] = kwargs[:type].to_sym if kwargs[:type]
289
+
223
290
  if fields
224
- all_field_names ||= [@key_field] + @fields
225
- positions = NamedArray.identify_name(all_field_names, fields)
226
- kwargs[:positions] = positions
227
- field_names = all_field_names.values_at *positions
291
+ if @fields
292
+ all_field_names ||= [@key_field] + @fields
293
+ fields = all_field_names if fields == :all
294
+ positions = NamedArray.identify_name(all_field_names, fields)
295
+ kwargs[:positions] = positions
296
+ field_names = all_field_names.values_at *positions
297
+ elsif fields.reject{|f| Numeric === f}.empty?
298
+ positions = fields
299
+ kwargs[:positions] = positions
300
+ else
301
+ raise "Non-numeric fields specified, but no field names available"
302
+ end
228
303
  else
229
304
  field_names = @fields
230
305
  end
231
306
 
232
307
  if key_field
233
- all_field_names ||= [@key_field] + @fields
234
- key = NamedArray.identify_name(all_field_names, key_field)
235
- kwargs[:key] = key == :key ? 0 : key
236
- key_field_name = key === :key ? @key_field : all_field_names[key]
237
- if fields.nil?
238
- field_names = all_field_names - [@key_field]
308
+ if @fields
309
+ all_field_names ||= [@key_field] + @fields
310
+ key = NamedArray.identify_name(all_field_names, key_field)
311
+ kwargs[:key] = key == :key ? 0 : key
312
+ key_field_name = key === :key ? @key_field : all_field_names[key]
313
+ if fields.nil?
314
+ field_names = all_field_names - [key_field_name]
315
+ end
316
+ else
317
+ kwargs[:key] = key_field == :key ? 0 : key_field
318
+ key = key_field
239
319
  end
240
320
  else
241
321
  key_field_name = @key_field
242
322
  end
243
323
 
324
+ if field_names && (kwargs[:type] == :single || kwargs[:type] == :flat)
325
+ field_names = field_names.slice(0,1)
326
+ end
327
+
244
328
  @options.each do |option,value|
245
329
  option = option.to_sym
246
330
  next unless KEY_PARAMETERS.include? option
@@ -250,21 +334,33 @@ module TSV
250
334
  kwargs[:source_type] = @options[:type]
251
335
  kwargs[:data] = false if kwargs[:data].nil?
252
336
 
253
- data = TSV.parse_stream(@stream, first_line: @first_line, **kwargs, &block)
337
+ data = TSV.parse_stream(@stream, first_line: @first_line, fix: @fix, field_names: @fields, **kwargs, &block)
254
338
 
255
339
  if data
256
340
  TSV.setup(data, :key_field => key_field_name, :fields => field_names, :type => @type)
257
341
  else
258
- self
342
+ [self.key_field, self.fields]
259
343
  end
260
344
  end
261
345
 
346
+ def fingerprint
347
+ "Parser:{"<< Log.fingerprint(self.all_fields|| []) << "}"
348
+ end
349
+
350
+ def digest_str
351
+ fingerprint
352
+ end
353
+
354
+ def inspect
355
+ fingerprint
356
+ end
262
357
  end
263
358
 
264
359
  def self.parse(stream, fix: true, header_hash: "#", sep: "\t", filename: nil, namespace: nil, unnamed: false, serializer: nil, **kwargs, &block)
265
360
  parser = TSV::Parser.new stream, fix: fix, header_hash: header_hash, sep: sep
266
361
 
267
- cast = parser.options[:cast] || kwargs[:cast]
362
+ cast = kwargs[:cast]
363
+ cast = parser.options[:cast] if cast.nil?
268
364
  type = kwargs[:type] ||= parser.options[:type] ||= :double
269
365
  if (data = kwargs[:data]) && data.respond_to?(:persistence_class)
270
366
  TSV.setup(data, type: type)
@@ -297,48 +393,7 @@ module TSV
297
393
  data.filename = filename
298
394
  data.namespace = namespace
299
395
  data.unnamed = unnamed
396
+ data.save_extension_attr_hash if data.respond_to?(:save_extension_attr_hash)
300
397
  data
301
398
  end
302
-
303
- #def self.parse_alt(stream, key_field: nil, fields: nil, filename: nil, namespace: nil, **kwargs, &block)
304
- # options, key_field_name, field_names, first_line, preamble = parse_header(stream)
305
-
306
- # if fields
307
- # all_field_names ||= [key_field_name] + field_names
308
- # positions = NamedArray.identify_name(all_field_names, fields)
309
- # kwargs[:positions] = positions
310
- # field_names = all_field_names.values_at *positions
311
- # end
312
-
313
- # if key_field
314
- # all_field_names ||= [key_field_name] + field_names
315
- # key = NamedArray.identify_name(all_field_names, key_field)
316
- # kwargs[:key] = key
317
- # key_field_name = all_field_names[key]
318
- # if fields.nil?
319
- # field_names = all_field_names - [key_field_name]
320
- # end
321
- # end
322
-
323
- # options.each do |option,value|
324
- # option = option.to_sym
325
- # next unless KEY_PARAMETERS.include? option
326
- # kwargs[option] = value unless kwargs.include?(option)
327
- # end
328
-
329
- # kwargs[:source_type] = options[:type]
330
-
331
- # type = kwargs[:type] ||= :double
332
- # if (data = kwargs[:data]) && data.respond_to?(:persistence_class)
333
- # TSV.setup(data, type: type, key_field: key_field_name, fields: field_names)
334
- # data.extend TSVAdapter
335
- # end
336
-
337
- # data = parse_stream(stream, first_line: first_line, **kwargs, &block)
338
-
339
- # TSV.setup(data, :key_field => key_field_name, :fields => field_names, :type => type, filename: filename, namespace: namespace)
340
-
341
- # data
342
- #end
343
-
344
399
  end
@@ -1,7 +1,6 @@
1
1
  module Path
2
2
  def tsv(*args, **kwargs, &block)
3
- found = self.find
4
- found = self.set_extension('tsv').find unless found.exists?
3
+ found = produce_and_find('tsv')
5
4
  TSV.open(found, *args, **kwargs, &block)
6
5
  end
7
6