oddb2xml 2.7.1 → 2.7.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -2
- data/.standard.yml +2 -0
- data/Gemfile +3 -3
- data/History.txt +24 -0
- data/README.md +3 -3
- data/Rakefile +24 -23
- data/bin/check_artikelstamm +11 -11
- data/bin/compare_v5 +23 -23
- data/bin/oddb2xml +14 -13
- data/lib/oddb2xml/builder.rb +1070 -1038
- data/lib/oddb2xml/calc.rb +232 -233
- data/lib/oddb2xml/chapter_70_hack.rb +38 -32
- data/lib/oddb2xml/cli.rb +252 -236
- data/lib/oddb2xml/compare.rb +70 -59
- data/lib/oddb2xml/compositions_syntax.rb +451 -430
- data/lib/oddb2xml/compressor.rb +20 -20
- data/lib/oddb2xml/downloader.rb +157 -129
- data/lib/oddb2xml/extractor.rb +295 -295
- data/lib/oddb2xml/options.rb +34 -35
- data/lib/oddb2xml/parslet_compositions.rb +265 -269
- data/lib/oddb2xml/semantic_check.rb +39 -33
- data/lib/oddb2xml/util.rb +163 -163
- data/lib/oddb2xml/version.rb +1 -1
- data/lib/oddb2xml/xml_definitions.rb +32 -33
- data/lib/oddb2xml.rb +1 -1
- data/oddb2xml.gemspec +34 -34
- data/shell.nix +17 -0
- data/spec/artikelstamm_spec.rb +111 -110
- data/spec/builder_spec.rb +490 -505
- data/spec/calc_spec.rb +552 -593
- data/spec/check_artikelstamm_spec.rb +26 -26
- data/spec/cli_spec.rb +173 -174
- data/spec/compare_spec.rb +9 -11
- data/spec/composition_syntax_spec.rb +390 -409
- data/spec/compressor_spec.rb +48 -48
- data/spec/data/transfer.dat +1 -0
- data/spec/data_helper.rb +47 -49
- data/spec/downloader_spec.rb +251 -260
- data/spec/extractor_spec.rb +171 -159
- data/spec/fixtures/vcr_cassettes/oddb2xml.json +1 -1
- data/spec/galenic_spec.rb +233 -256
- data/spec/options_spec.rb +116 -119
- data/spec/parslet_spec.rb +896 -863
- data/spec/spec_helper.rb +153 -153
- data/test_options.rb +39 -42
- data/tools/win_fetch_cacerts.rb +2 -3
- metadata +42 -12
data/lib/oddb2xml/compare.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
|
2
|
-
require 'xmlsimple'
|
1
|
+
require "xmlsimple"
|
3
2
|
|
4
3
|
module Oddb2xml
|
5
4
|
def self.log_timestamp(msg)
|
6
5
|
full_msg = "#{Time.now.strftime("%H:%M:%S")}: #{msg}"
|
7
6
|
puts full_msg
|
8
|
-
|
7
|
+
$stdout.flush
|
9
8
|
full_msg
|
10
9
|
end
|
10
|
+
|
11
11
|
class StammXML
|
12
12
|
V3_NAME_REG = /_([N,P])_/
|
13
13
|
attr_accessor :components
|
14
14
|
attr_reader :keys, :sub_key_names, :filename, :basename, :version, :hash
|
15
|
-
def initialize(filename, components =
|
15
|
+
def initialize(filename, components = ["ITEMS"])
|
16
16
|
raise "File #{filename} must exist" unless File.exist?(filename)
|
17
17
|
@filename = filename
|
18
18
|
@basename = File.basename(filename)
|
19
|
-
@version =
|
19
|
+
@version = V3_NAME_REG.match(filename) ? 3 : 5
|
20
20
|
@components = components
|
21
21
|
if @version == 5
|
22
22
|
@hash = load_file(@filename)
|
@@ -24,41 +24,47 @@ module Oddb2xml
|
|
24
24
|
raise "Unsupported version #{@version}"
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
27
28
|
def self.get_component_key_name(component_name)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
return "LIMNAMEBAG" if /LIMITATION/i.match?(component_name)
|
30
|
+
return "PRODNO" if /PRODUCT/i.match?(component_name)
|
31
|
+
return "GTIN" if /ITEM/i.match?(component_name)
|
32
|
+
raise "Cannot determine keyname for component #{component_name}"
|
32
33
|
end
|
34
|
+
|
33
35
|
def get_limitation_from_v5(item)
|
34
|
-
get_item(
|
36
|
+
get_item("PRODUCTS", item["PRODNO"].first.to_i)["LIMNAMEBAG"] ? ["true"] : nil
|
35
37
|
end
|
38
|
+
|
36
39
|
def get_field_from_v5_product(item, field_name)
|
37
|
-
get_item(
|
40
|
+
get_item("PRODUCTS", item["PRODNO"].first.to_i)[field_name]
|
38
41
|
end
|
42
|
+
|
39
43
|
def get_items(component_name)
|
40
44
|
if @version == 3
|
41
|
-
|
45
|
+
@hash[component_name]
|
42
46
|
else
|
43
|
-
|
47
|
+
@hash[component_name].first.values.first
|
44
48
|
end
|
45
|
-
items
|
46
49
|
end
|
50
|
+
|
47
51
|
def get_item(component_name, id)
|
48
52
|
keyname = StammXML.get_component_key_name(component_name)
|
49
|
-
get_items(component_name).find{|item| item[keyname].first.to_i == id}
|
53
|
+
get_items(component_name).find { |item| item[keyname].first.to_i == id }
|
50
54
|
end
|
55
|
+
|
51
56
|
def load_file(name)
|
52
|
-
Oddb2xml.log_timestamp "Reading #{name} #{(File.size(name)/1024/1024).to_i} MB. This may take some time"
|
57
|
+
Oddb2xml.log_timestamp "Reading #{name} #{(File.size(name) / 1024 / 1024).to_i} MB. This may take some time"
|
53
58
|
XmlSimple.xml_in(IO.read(name))
|
54
59
|
end
|
55
60
|
end
|
61
|
+
|
56
62
|
class CompareV5
|
57
63
|
DEFAULTS = {
|
58
|
-
:
|
59
|
-
:
|
60
|
-
:
|
61
|
-
:
|
64
|
+
components: ["PRODUCTS", "LIMITATIONS", "ITEMS"],
|
65
|
+
fields_to_ignore: ["COMP", "DOSAGE_FORMF", "MEASUREF"],
|
66
|
+
fields_as_floats: ["PEXT", "PEXF", "PPUB"],
|
67
|
+
min_diff_for_floats: 0.01
|
62
68
|
}
|
63
69
|
def initialize(left, right, options = DEFAULTS.clone)
|
64
70
|
@options = options
|
@@ -68,37 +74,38 @@ module Oddb2xml
|
|
68
74
|
@occurrences = {}
|
69
75
|
@report = []
|
70
76
|
end
|
71
|
-
|
72
|
-
|
77
|
+
|
78
|
+
def get_keys(items, key = "GTIN")
|
79
|
+
items.collect { |item| item[key].first.to_i }
|
73
80
|
end
|
81
|
+
|
74
82
|
def get_names(items)
|
75
|
-
|
83
|
+
items.collect { |item| item.keys }.flatten.uniq.sort
|
76
84
|
end
|
85
|
+
|
77
86
|
def compare
|
78
87
|
show_header("Start comparing #{@left.filename} with #{@right.filename}")
|
79
88
|
(@left.components & @right.components).each do |name|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
(
|
96
|
-
compare_details(name, compare_names, id)
|
97
|
-
end
|
98
|
-
key_results_details(name, compare_names, l_keys, r_keys)
|
99
|
-
rescue => error
|
100
|
-
puts "Execution failed with #{error}"
|
89
|
+
puts "\n#{Time.now.strftime("%H:%M:%S")}: Comparing #{name} in #{@left.basename} with #{@right.basename}"
|
90
|
+
key = StammXML.get_component_key_name(name)
|
91
|
+
left_items = @left.get_items(name)
|
92
|
+
next unless left_items
|
93
|
+
right_items = @right.get_items(name)
|
94
|
+
next unless right_items
|
95
|
+
@diff_stat[name] = {}
|
96
|
+
@occurrences[name] = {}
|
97
|
+
@diff_stat[name][NR_COMPARED] = 0
|
98
|
+
l_names = get_names(left_items)
|
99
|
+
r_names = get_names(right_items)
|
100
|
+
compare_names = l_names & r_names
|
101
|
+
l_keys = get_keys(left_items, key)
|
102
|
+
r_keys = get_keys(right_items, key)
|
103
|
+
(l_keys & r_keys).each do |id|
|
104
|
+
compare_details(name, compare_names, id)
|
101
105
|
end
|
106
|
+
key_results_details(name, compare_names, l_keys, r_keys)
|
107
|
+
rescue => error
|
108
|
+
puts "Execution failed with #{error}"
|
102
109
|
end
|
103
110
|
show_header("Summary comparing #{@left.filename} with #{@right.filename}")
|
104
111
|
puts "Ignored differences in #{@options[:fields_to_ignore]}. Signaled when differences in #{@options[:fields_as_floats]} were bigger than #{@options[:min_diff_for_floats]}"
|
@@ -116,28 +123,31 @@ module Oddb2xml
|
|
116
123
|
puts "Execution failed with #{error}"
|
117
124
|
raise error
|
118
125
|
end
|
126
|
+
|
119
127
|
private
|
120
|
-
|
121
|
-
|
128
|
+
|
129
|
+
NR_COMPARED = "NR_COMPARED"
|
130
|
+
COUNT = "_count"
|
122
131
|
def show_header(header)
|
123
132
|
text = Oddb2xml.log_timestamp(header)
|
124
133
|
pad = 5
|
125
134
|
puts
|
126
|
-
puts
|
127
|
-
puts
|
128
|
-
puts
|
135
|
+
puts "-" * (text.length + 2 * pad)
|
136
|
+
puts "".ljust(pad) + text
|
137
|
+
puts "-" * (text.length + 2 * pad)
|
129
138
|
puts
|
130
139
|
end
|
140
|
+
|
131
141
|
def compare_details(component_name, compare_names, id)
|
132
142
|
l_item = @left.get_item(component_name, id)
|
133
143
|
r_item = @right.get_item(component_name, id)
|
134
144
|
found_one = false
|
135
145
|
length = 32
|
136
146
|
found = false
|
137
|
-
detail_name = l_item[
|
147
|
+
detail_name = l_item["DSCR"] ? l_item["DSCR"].first[0..length - 1].rjust(length) : "".rjust(length)
|
138
148
|
details = "Diff in #{id.to_s.ljust(15)} #{detail_name}"
|
139
149
|
diff_name = component_name
|
140
|
-
diff_name +=
|
150
|
+
diff_name += "S" unless /S$/.match?(diff_name)
|
141
151
|
@diff_stat[diff_name] ||= {}
|
142
152
|
@occurrences[diff_name] ||= {}
|
143
153
|
@diff_stat[diff_name][NR_COMPARED] ||= 0
|
@@ -154,33 +164,34 @@ module Oddb2xml
|
|
154
164
|
r_float = r_value ? r_value.first.to_f : 0.0
|
155
165
|
next if (l_float - r_float).abs < @options[:min_diff_for_floats]
|
156
166
|
end
|
157
|
-
next if (r_value.is_a?(Array) &&
|
158
|
-
|
167
|
+
next if (r_value.is_a?(Array) && "--missing--".eql?(r_value.first)) || (l_value.is_a?(Array) && "--missing--".eql?(l_value.first))
|
168
|
+
# TODO: get_field_from_v5_product
|
159
169
|
next if r_value.to_s.eql?(l_value.to_s)
|
160
170
|
next if r_value.to_s.upcase.eql?(l_value.to_s.upcase) && @options[:case_insensitive]
|
161
171
|
details += " #{sub_key}: '#{l_value}' != '#{r_value}'"
|
162
172
|
found = found_one = true
|
163
173
|
@diff_stat[diff_name][sub_key] += 1
|
164
174
|
end
|
165
|
-
puts details.gsub(/[\[\]]/,
|
175
|
+
puts details.gsub(/[\[\]]/, "") if found
|
166
176
|
end
|
167
177
|
|
168
178
|
def show_keys(keys, batch_size = 20)
|
169
179
|
0.upto(keys.size) do |idx|
|
170
180
|
next unless idx % batch_size == 0
|
171
|
-
puts
|
181
|
+
puts " " + keys[idx..(idx + batch_size - 1)].join(" ")
|
172
182
|
end
|
173
183
|
end
|
184
|
+
|
174
185
|
def key_results_details(component_name, compare_names, l_keys, r_keys)
|
175
|
-
component_name +=
|
176
|
-
@report <<
|
186
|
+
component_name += "S" unless /S$/.match?(component_name)
|
187
|
+
@report << "#{component_name}: Found #{l_keys.size} items only in #{@left.basename} #{r_keys.size} items only in #{@right.basename}, compared #{@diff_stat[component_name][NR_COMPARED]} items"
|
177
188
|
keys = r_keys - l_keys
|
178
|
-
head = "#{component_name}: #{
|
189
|
+
head = "#{component_name}: #{keys.size} keys only in #{@right.basename}"
|
179
190
|
puts "#{head}: Keys were #{keys.size}"
|
180
191
|
show_keys(keys)
|
181
192
|
@report << head
|
182
193
|
keys = l_keys - r_keys
|
183
|
-
head = "#{component_name}: #{
|
194
|
+
head = "#{component_name}: #{keys.size} keys only in #{@left.basename}"
|
184
195
|
puts "#{head}: Keys were #{keys.size}"
|
185
196
|
show_keys(keys)
|
186
197
|
@report << head
|