rbbt-util 5.14.33 → 5.14.34
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rbbt +2 -0
- data/lib/rbbt/association/database.rb +153 -0
- data/lib/rbbt/association/index.rb +89 -20
- data/lib/rbbt/association/open.rb +37 -0
- data/lib/rbbt/association/util.rb +133 -0
- data/lib/rbbt/association.rb +1 -380
- data/lib/rbbt/entity/identifiers.rb +106 -0
- data/lib/rbbt/entity.rb +1 -0
- data/lib/rbbt/knowledge_base/entity.rb +107 -0
- data/lib/rbbt/knowledge_base/query.rb +83 -0
- data/lib/rbbt/knowledge_base/registry.rb +106 -0
- data/lib/rbbt/knowledge_base/syndicate.rb +22 -0
- data/lib/rbbt/knowledge_base.rb +6 -359
- data/lib/rbbt/tsv/accessor.rb +4 -0
- data/lib/rbbt/tsv/change_id.rb +119 -0
- data/lib/rbbt/tsv/index.rb +6 -2
- data/lib/rbbt/tsv/parser.rb +7 -5
- data/lib/rbbt/tsv/util.rb +1 -1
- data/lib/rbbt/tsv.rb +2 -1
- data/lib/rbbt/util/R/model.rb +1 -1
- data/lib/rbbt/util/log.rb +2 -2
- data/lib/rbbt/util/misc/bgzf.rb +2 -0
- data/lib/rbbt/util/misc/inspect.rb +1 -1
- data/lib/rbbt-util.rb +11 -7
- data/lib/rbbt.rb +0 -1
- data/share/rbbt_commands/app/start +1 -1
- data/share/rbbt_commands/tsv/change_id +2 -2
- data/test/rbbt/association/test_database.rb +61 -0
- data/test/rbbt/association/test_index.rb +67 -22
- data/test/rbbt/association/test_open.rb +68 -0
- data/test/rbbt/association/test_util.rb +108 -0
- data/test/rbbt/entity/test_identifiers.rb +40 -0
- data/test/rbbt/knowledge_base/test_entity.rb +0 -0
- data/test/rbbt/knowledge_base/test_query.rb +45 -0
- data/test/rbbt/knowledge_base/test_registry.rb +52 -0
- data/test/rbbt/test_association.rb +3 -3
- data/test/rbbt/test_knowledge_base.rb +79 -51
- data/test/rbbt/test_monitor.rb +0 -2
- data/test/rbbt/test_packed_index.rb +1 -1
- data/test/rbbt/test_resource.rb +6 -6
- data/test/rbbt/test_tsv.rb +34 -44
- data/test/rbbt/tsv/parallel/test_through.rb +2 -4
- data/test/rbbt/tsv/parallel/test_traverse.rb +30 -28
- data/test/rbbt/tsv/test_change_id.rb +10 -0
- data/test/rbbt/util/R/test_model.rb +9 -10
- data/test/rbbt/util/test_misc.rb +1 -1
- data/test/test_helper.rb +4 -1
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec2d34290a61ca4f3f32cd875a07a15c9c7c06fd
|
4
|
+
data.tar.gz: 08ce21aa7a885530dcba3859231d94874f99bba2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d532ef379f2238e8dbaf311f485a4e18ac774177624e327d7b1d432a6cd0304f17f945448523407bb0cbb8f14a1067b50d36585b6d554d646dd5a01124c5b4f2
|
7
|
+
data.tar.gz: b15a2660fd8be0a782fb0a139bc44b8670adf3629446be6c0b8dc3e6d27f017a2c71db0cb6d76602b306917c9909f03013226566d963c0247506a4723968ead8
|
data/bin/rbbt
CHANGED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'rbbt/association/util'
|
2
|
+
require 'rbbt/tsv/change_id'
|
3
|
+
|
4
|
+
module Association
|
5
|
+
|
6
|
+
def self.add_reciprocal(tsv)
|
7
|
+
new = TSV.open(tsv.dumper_stream)
|
8
|
+
tsv.with_unnamed do
|
9
|
+
case tsv.type
|
10
|
+
when :double
|
11
|
+
tsv.through do |source, values|
|
12
|
+
Misc.zip_fields(values).each do |info|
|
13
|
+
target, *rest = info
|
14
|
+
new.zip_new target, [source] + rest
|
15
|
+
end
|
16
|
+
end
|
17
|
+
else
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
tsv.annotate(new)
|
22
|
+
|
23
|
+
new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.translate(tsv, source_final_format, target_final_format, options = {})
|
27
|
+
source_field = tsv.key_field
|
28
|
+
target_field = tsv.fields.first
|
29
|
+
namespace = tsv.namespace
|
30
|
+
|
31
|
+
if source_final_format and source_field != source_final_format
|
32
|
+
Log.debug("Changing source format from #{tsv.key_field} to #{source_final_format}")
|
33
|
+
|
34
|
+
identifier_files = tsv.identifier_files.dup
|
35
|
+
identifier_files.concat Entity.identifier_files(source_final_format) if defined? Entity
|
36
|
+
identifier_files.uniq!
|
37
|
+
identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if namespace
|
38
|
+
identifier_files.reject!{|f| f.match(/\bNAMESPACE\b/)}
|
39
|
+
|
40
|
+
tsv = TSV.translate(tsv, source_field, source_final_format, options.merge(:identifier_files => identifier_files))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Translate target
|
44
|
+
if target_final_format and target_field != target_final_format
|
45
|
+
Log.debug("Changing target format from #{target_field} to #{target_final_format}")
|
46
|
+
old_key_field = tsv.key_field
|
47
|
+
tsv.key_field = "MASK"
|
48
|
+
|
49
|
+
identifier_files = tsv.identifier_files.dup
|
50
|
+
identifier_files.concat Entity.identifier_files(target_final_format) if defined? Entity
|
51
|
+
identifier_files.uniq!
|
52
|
+
identifier_files.collect!{|f| f.annotate(f.gsub(/\bNAMESPACE\b/, namespace))} if namespace
|
53
|
+
identifier_files.reject!{|f| f.match(/\bNAMESPACE\b/)}
|
54
|
+
|
55
|
+
tsv = TSV.translate(tsv, target_field, target_final_format, options.merge(:identifier_files => identifier_files))
|
56
|
+
tsv.key_field = old_key_field
|
57
|
+
end
|
58
|
+
|
59
|
+
tsv
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.reorder_tsv(tsv, options = {})
|
63
|
+
fields, undirected, persist = Misc.process_options options, :fields, :undirected, :persist
|
64
|
+
all_fields = tsv.all_fields
|
65
|
+
|
66
|
+
source_pos, field_pos, source_header, field_headers, source_format, target_format = headers(all_fields, fields, options)
|
67
|
+
|
68
|
+
source_field = source_pos == :key ? :key : all_fields[source_pos]
|
69
|
+
info_fields = field_pos.collect{|f| f == :key ? :key : all_fields[f]}
|
70
|
+
options = options.merge({:key_field => source_field, :fields => info_fields})
|
71
|
+
|
72
|
+
tsv = tsv.reorder source_field, fields, :zipped => true
|
73
|
+
|
74
|
+
tsv.key_field = source_header
|
75
|
+
tsv.fields = field_headers
|
76
|
+
|
77
|
+
tsv = translate tsv, source_format, target_format, :persist => persist if source_format or target_format
|
78
|
+
|
79
|
+
tsv = add_reciprocal tsv if undirected
|
80
|
+
|
81
|
+
tsv
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.open_stream(stream, options = {})
|
85
|
+
fields, undirected, persist = Misc.process_options options, :fields, :undirected, :persist
|
86
|
+
|
87
|
+
parser = TSV::Parser.new stream, options.merge(:fields => nil, :key_field => nil)
|
88
|
+
|
89
|
+
key_field, *_fields = all_fields = parser.all_fields
|
90
|
+
|
91
|
+
source_pos, field_pos, source_header, field_headers, source_format, target_format = headers parser.all_fields, fields, options
|
92
|
+
|
93
|
+
parser.key_field = source_pos
|
94
|
+
parser.fields = field_pos
|
95
|
+
|
96
|
+
case parser.type
|
97
|
+
when :single
|
98
|
+
class << parser
|
99
|
+
def get_values(parts)
|
100
|
+
[parts[@key_field], parts.values_at(*@fields).first]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
when :list
|
104
|
+
class << parser
|
105
|
+
def get_values(parts)
|
106
|
+
[parts[@key_field], parts.values_at(*@fields)]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
when :double, :list, :single
|
110
|
+
class << parser
|
111
|
+
def get_values(parts)
|
112
|
+
[parts[@key_field].split(@sep2,-1), parts.values_at(*@fields).collect{|v| v.nil? ? [] : v.split(@sep2,-1) }]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
when :flat
|
116
|
+
class << parser
|
117
|
+
def get_values(parts)
|
118
|
+
fields = (0..parts.length-1).to_a - [@key_field]
|
119
|
+
values = parts.values_at(*fields).compact.collect{|v| v.split(@sep2,-1) }.flatten
|
120
|
+
[parts[@key_field].split(@sep2,-1), values]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
open_options = options.merge(parser.options).merge(:parser => parser)
|
126
|
+
|
127
|
+
tsv = TSV.parse parser.stream, {}, open_options
|
128
|
+
tsv.key_field = source_header
|
129
|
+
tsv.fields = field_headers
|
130
|
+
|
131
|
+
tsv = tsv.to_double unless tsv.type == :double
|
132
|
+
|
133
|
+
tsv = translate tsv, source_format, target_format, :persist => persist if source_format or target_format
|
134
|
+
|
135
|
+
tsv = add_reciprocal tsv if undirected
|
136
|
+
|
137
|
+
tsv
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.database(file, options = {})
|
141
|
+
case file
|
142
|
+
when TSV
|
143
|
+
file = file.to_double unless file.type == :double
|
144
|
+
reorder_tsv(file, options.dup)
|
145
|
+
when IO
|
146
|
+
open_stream(file, options.dup)
|
147
|
+
else
|
148
|
+
stream = TSV.get_stream(file)
|
149
|
+
open_stream(stream, options.dup)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -1,5 +1,85 @@
|
|
1
1
|
require 'rbbt/tsv'
|
2
|
+
require 'rbbt/association/open'
|
3
|
+
|
2
4
|
module Association
|
5
|
+
def self.index(file, options = nil, persist_options = nil)
|
6
|
+
options = options.nil? ? {} : options.dup
|
7
|
+
persist_options = persist_options.nil? ? Misc.pull_keys(options, :persist) : persist_options.dup
|
8
|
+
|
9
|
+
persist_options = Misc.add_defaults persist_options.dup, :persist => true, :engine => "BDB"
|
10
|
+
persist = persist_options[:persist]
|
11
|
+
|
12
|
+
file = version_file(file, options[:namespace]) if options[:namespace] and String === file
|
13
|
+
|
14
|
+
undirected = options[:undirected]
|
15
|
+
Persist.persist_tsv(file, "Association Index", options, persist_options.dup) do |data|
|
16
|
+
recycle = options[:recycle]
|
17
|
+
|
18
|
+
persist_options[:file] = persist_options[:file] + '.database' if persist_options[:file]
|
19
|
+
database = open(file, options, persist_options.dup)
|
20
|
+
|
21
|
+
fields = database.fields
|
22
|
+
source_field = database.key_field
|
23
|
+
target_field = fields.first.split(":").last
|
24
|
+
key_field = [source_field, target_field, undirected ? "undirected" : nil].compact * "~"
|
25
|
+
|
26
|
+
TSV.setup(data, :key_field => key_field, :fields => fields[1..-1], :type => :list, :serializer => :list)
|
27
|
+
|
28
|
+
data.key_field = key_field
|
29
|
+
data.fields = fields[1..-1]
|
30
|
+
data.type = :list
|
31
|
+
data.serializer = :list
|
32
|
+
|
33
|
+
database.with_unnamed do
|
34
|
+
database.through do |source, values|
|
35
|
+
case database.type
|
36
|
+
when :single
|
37
|
+
values = [[values]]
|
38
|
+
when :list
|
39
|
+
values = values.collect{|v| [v] }
|
40
|
+
when :flat
|
41
|
+
values = [values]
|
42
|
+
end
|
43
|
+
next if values.empty?
|
44
|
+
next if source.nil? or source.empty?
|
45
|
+
next if values.empty?
|
46
|
+
|
47
|
+
targets, *rest = values
|
48
|
+
|
49
|
+
size = targets ? targets.length : 0
|
50
|
+
|
51
|
+
rest.each_with_index do |list,i|
|
52
|
+
list.replace [list.first] * size if list.length == 1
|
53
|
+
end if recycle and size > 1
|
54
|
+
|
55
|
+
rest = Misc.zip_fields rest
|
56
|
+
|
57
|
+
annotations = rest.length > 1 ?
|
58
|
+
targets.zip(rest) :
|
59
|
+
targets.zip(rest * targets.length)
|
60
|
+
|
61
|
+
annotations.each do |target, info|
|
62
|
+
next if target.nil? or target.empty?
|
63
|
+
key = [source, target] * "~"
|
64
|
+
if data[key].nil? or info.nil?
|
65
|
+
data[key] = info
|
66
|
+
else
|
67
|
+
old_info = data[key]
|
68
|
+
info = old_info.zip(info).collect{|p| p * ";;" }
|
69
|
+
data[key] = info
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
data.close
|
76
|
+
data
|
77
|
+
end.tap do |data|
|
78
|
+
data.read if not Hash === data and data.respond_to? :read
|
79
|
+
Association::Index.setup data
|
80
|
+
data
|
81
|
+
end
|
82
|
+
end
|
3
83
|
module Index
|
4
84
|
|
5
85
|
attr_accessor :source_field, :target_field, :undirected
|
@@ -16,9 +96,15 @@ module Association
|
|
16
96
|
|
17
97
|
def reverse
|
18
98
|
@reverse ||= begin
|
19
|
-
|
20
|
-
|
21
|
-
|
99
|
+
if self.respond_to? :persistence_path
|
100
|
+
persistence_path = self.persistence_path
|
101
|
+
persistence_path = persistence_path.find if Path === persistence_path
|
102
|
+
reverse_filename = persistence_path + '.reverse'
|
103
|
+
else
|
104
|
+
raise "Can only reverse a TokyoCabinet::BDB dataset at the time"
|
105
|
+
end
|
106
|
+
|
107
|
+
self.read if self.respond_to? :read
|
22
108
|
|
23
109
|
if File.exists?(reverse_filename)
|
24
110
|
new = Persist.open_tokyocabinet(reverse_filename, false, serializer, TokyoCabinet::BDB)
|
@@ -66,16 +152,6 @@ module Association
|
|
66
152
|
|
67
153
|
#{{{ Subset
|
68
154
|
|
69
|
-
def select_entities(entities)
|
70
|
-
source_type = Entity.formats[source_field]
|
71
|
-
target_type = Entity.formats[target_field]
|
72
|
-
|
73
|
-
source_entities = entities[:source] || entities[source_field] || entities[Entity.formats[source_field].to_s]
|
74
|
-
target_entities = entities[:target] || entities[target_field] || entities[Entity.formats[target_field].to_s]
|
75
|
-
|
76
|
-
[source_entities, target_entities]
|
77
|
-
end
|
78
|
-
|
79
155
|
def subset(source, target)
|
80
156
|
return [] if source.nil? or target.nil? or source.empty? or target.empty?
|
81
157
|
|
@@ -110,12 +186,5 @@ module Association
|
|
110
186
|
target_matches.values_at(*target.uniq).flatten.compact
|
111
187
|
end
|
112
188
|
|
113
|
-
def subset_entities(entities)
|
114
|
-
source, target = select_entities(entities)
|
115
|
-
return [] if source.nil? or target.nil?
|
116
|
-
return [] if Array === target and target.empty?
|
117
|
-
return [] if Array === source and source.empty?
|
118
|
-
subset source, target
|
119
|
-
end
|
120
189
|
end
|
121
190
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rbbt/association/database'
|
2
|
+
|
3
|
+
module Association
|
4
|
+
def self.version_file(file, namespace)
|
5
|
+
old_file, file = file, file.sub('NAMESPACE', namespace) if namespace and String === file
|
6
|
+
old_file.annotate file if Path === old_file
|
7
|
+
file
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.open(file, options = nil, persist_options = nil)
|
11
|
+
options = options.nil? ? {} : options.dup
|
12
|
+
persist_options = persist_options.nil? ? Misc.pull_keys(options, :persist) : persist_options.dup
|
13
|
+
|
14
|
+
options = Misc.add_defaults options, :zipped => true
|
15
|
+
persist_options = Misc.add_defaults persist_options, :persist => true, :dir => Rbbt.var.associations
|
16
|
+
persist = persist_options[:persist]
|
17
|
+
|
18
|
+
file = version_file(file, options[:namespace]) if options[:namespace] and String === file
|
19
|
+
file = file.call if Proc === file
|
20
|
+
|
21
|
+
data = Persist.persist_tsv(file, "Association Database", options, persist_options) do |data|
|
22
|
+
tsv = Association.database(file, options.merge(:persist => persist))
|
23
|
+
tsv = tsv.to_double unless tsv.type == :double
|
24
|
+
tsv.annotate data
|
25
|
+
|
26
|
+
data.serializer = :double if data.respond_to? :serializer
|
27
|
+
tsv.each do |k,v|
|
28
|
+
data[k] = v
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
data
|
33
|
+
end
|
34
|
+
data
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'rbbt/entity'
|
2
|
+
|
3
|
+
module Association
|
4
|
+
def self.identify_entity_format(format, fields)
|
5
|
+
entity_type = Entity.formats[format]
|
6
|
+
raise "Field #{ format } could not be resolved: #{fields}" if entity_type.nil?
|
7
|
+
main_field = fields.select{|f| Entity.formats[f] == entity_type}.first
|
8
|
+
raise "Field #{ format } not present, options: #{Misc.fingerprint fields}" if main_field.nil?
|
9
|
+
[main_field, nil, format]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse_field_specification(spec)
|
13
|
+
return [2,nil,nil] if Fixnum === spec
|
14
|
+
spec = spec.split "=>" unless Array === spec
|
15
|
+
field_part, final_format = spec
|
16
|
+
|
17
|
+
field, format = field_part.split "=~", -1
|
18
|
+
|
19
|
+
field = nil if field.nil? or field.empty?
|
20
|
+
|
21
|
+
[field, format, final_format]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.normalize_specs(spec, all_fields = nil)
|
25
|
+
return nil if spec.nil?
|
26
|
+
field, header, format = parse_field_specification spec
|
27
|
+
|
28
|
+
specs = if all_fields.nil? or all_fields.include? field
|
29
|
+
[field, header, format]
|
30
|
+
else
|
31
|
+
if all_fields.nil?
|
32
|
+
begin
|
33
|
+
identify_entity_format field, all_fields
|
34
|
+
rescue
|
35
|
+
[field, header, format]
|
36
|
+
end
|
37
|
+
else
|
38
|
+
[field, header, format]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
specs
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.extract_specs(all_fields=nil, options = {})
|
45
|
+
source, source_format, target, target_format = Misc.process_options options, :source, :source_format, :target, :target_format
|
46
|
+
|
47
|
+
key_field, *fields = all_fields.nil? ? [nil] : all_fields
|
48
|
+
|
49
|
+
source_specs = normalize_specs source, all_fields
|
50
|
+
target_specs = normalize_specs target, all_fields
|
51
|
+
|
52
|
+
source_specs = [nil, nil, nil] if source_specs.nil?
|
53
|
+
target_specs = [nil, nil, nil] if target_specs.nil?
|
54
|
+
|
55
|
+
source_specs[2] = source_format if source_format
|
56
|
+
target_specs[2] = target_format if target_format
|
57
|
+
|
58
|
+
if source_specs[0].nil? and target_specs[0].nil?
|
59
|
+
source_specs[0] = key_field
|
60
|
+
target_specs[0] = fields[0]
|
61
|
+
elsif source_specs[0].nil?
|
62
|
+
if target_specs[0] == :key or target_specs[0] == key_field
|
63
|
+
source_specs[0] = fields[0]
|
64
|
+
else
|
65
|
+
source_specs[0] = key_field
|
66
|
+
end
|
67
|
+
elsif target_specs[0].nil?
|
68
|
+
if source_specs[0] == fields.first
|
69
|
+
target_specs[0] = key_field
|
70
|
+
else
|
71
|
+
target_specs[0] = fields.first
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
{:source => source_specs, :target => target_specs}
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.process_formats(field, default_format = {})
|
79
|
+
return nil if default_format.nil? or default_format.empty?
|
80
|
+
default_format.each do |type, format|
|
81
|
+
entity_type = Entity.formats[field] || format
|
82
|
+
return format if entity_type.to_s === type
|
83
|
+
end
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.headers(all_fields, info_fields = nil, options = {})
|
88
|
+
specs = extract_specs all_fields, options
|
89
|
+
|
90
|
+
source_field = specs[:source][0]
|
91
|
+
target_field = specs[:target][0]
|
92
|
+
|
93
|
+
source_pos = all_fields.index source_field
|
94
|
+
target_pos = all_fields.index target_field
|
95
|
+
|
96
|
+
source_header = specs[:source][1] || specs[:source][0]
|
97
|
+
target_header = specs[:target][1] || specs[:target][0]
|
98
|
+
|
99
|
+
info_fields = all_fields.dup if info_fields.nil?
|
100
|
+
info_fields.delete source_field
|
101
|
+
info_fields.delete target_field
|
102
|
+
info_fields.unshift target_field
|
103
|
+
|
104
|
+
field_headers = [target_header]
|
105
|
+
info_fields[1..-1].each do |field|
|
106
|
+
header = case field
|
107
|
+
when String
|
108
|
+
field
|
109
|
+
when Fixnum
|
110
|
+
all_fields[field]
|
111
|
+
when :key
|
112
|
+
all_fields.first
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
field_headers << header
|
117
|
+
end
|
118
|
+
|
119
|
+
field_pos = info_fields.collect{|f| raise "Field #{f} not found. Options: #{info_fields* ", "}" unless all_fields.include?(f); f == :key ? 0 : all_fields.index(f); }
|
120
|
+
|
121
|
+
source_format = specs[:source][2]
|
122
|
+
target_format = specs[:target][2]
|
123
|
+
|
124
|
+
|
125
|
+
if format = options[:format]
|
126
|
+
source_format = process_formats(specs[:source][1] || specs[:source][0], format) || source_format
|
127
|
+
target_format = process_formats(specs[:target][1] || specs[:target][0], format) || target_format
|
128
|
+
end
|
129
|
+
|
130
|
+
Log.low "Headers -- #{[source_pos, field_pos, source_header, field_headers, source_format, target_format]}"
|
131
|
+
[source_pos, field_pos, source_header, field_headers, source_format, target_format]
|
132
|
+
end
|
133
|
+
end
|