oddb2xml 2.7.1 → 2.7.5

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -2
  3. data/.standard.yml +2 -0
  4. data/Gemfile +3 -3
  5. data/History.txt +24 -0
  6. data/README.md +3 -3
  7. data/Rakefile +24 -23
  8. data/bin/check_artikelstamm +11 -11
  9. data/bin/compare_v5 +23 -23
  10. data/bin/oddb2xml +14 -13
  11. data/lib/oddb2xml/builder.rb +1070 -1038
  12. data/lib/oddb2xml/calc.rb +232 -233
  13. data/lib/oddb2xml/chapter_70_hack.rb +38 -32
  14. data/lib/oddb2xml/cli.rb +252 -236
  15. data/lib/oddb2xml/compare.rb +70 -59
  16. data/lib/oddb2xml/compositions_syntax.rb +451 -430
  17. data/lib/oddb2xml/compressor.rb +20 -20
  18. data/lib/oddb2xml/downloader.rb +157 -129
  19. data/lib/oddb2xml/extractor.rb +295 -295
  20. data/lib/oddb2xml/options.rb +34 -35
  21. data/lib/oddb2xml/parslet_compositions.rb +265 -269
  22. data/lib/oddb2xml/semantic_check.rb +39 -33
  23. data/lib/oddb2xml/util.rb +163 -163
  24. data/lib/oddb2xml/version.rb +1 -1
  25. data/lib/oddb2xml/xml_definitions.rb +32 -33
  26. data/lib/oddb2xml.rb +1 -1
  27. data/oddb2xml.gemspec +34 -34
  28. data/shell.nix +17 -0
  29. data/spec/artikelstamm_spec.rb +111 -110
  30. data/spec/builder_spec.rb +490 -505
  31. data/spec/calc_spec.rb +552 -593
  32. data/spec/check_artikelstamm_spec.rb +26 -26
  33. data/spec/cli_spec.rb +173 -174
  34. data/spec/compare_spec.rb +9 -11
  35. data/spec/composition_syntax_spec.rb +390 -409
  36. data/spec/compressor_spec.rb +48 -48
  37. data/spec/data/transfer.dat +1 -0
  38. data/spec/data_helper.rb +47 -49
  39. data/spec/downloader_spec.rb +251 -260
  40. data/spec/extractor_spec.rb +171 -159
  41. data/spec/fixtures/vcr_cassettes/oddb2xml.json +1 -1
  42. data/spec/galenic_spec.rb +233 -256
  43. data/spec/options_spec.rb +116 -119
  44. data/spec/parslet_spec.rb +896 -863
  45. data/spec/spec_helper.rb +153 -153
  46. data/test_options.rb +39 -42
  47. data/tools/win_fetch_cacerts.rb +2 -3
  48. metadata +42 -12
@@ -1,22 +1,22 @@
1
- # encoding: utf-8
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
- STDOUT.flush
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 = ['ITEMS'])
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 = V3_NAME_REG.match(filename) ? 3 : 5
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
- return 'LIMNAMEBAG' if /LIMITATION/i.match(component_name)
29
- return 'PRODNO' if /PRODUCT/i.match(component_name)
30
- return 'GTIN' if /ITEM/i.match(component_name)
31
- raise "Cannot determine keyname for component #{component_name}"
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('PRODUCTS', item['PRODNO'].first.to_i)['LIMNAMEBAG'] ? ['true'] : nil
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('PRODUCTS', item['PRODNO'].first.to_i)[field_name]
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
- items = @hash[component_name]
45
+ @hash[component_name]
42
46
  else
43
- items = @hash[component_name].first.values.first
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
- :components => ["PRODUCTS", "LIMITATIONS", "ITEMS",],
59
- :fields_to_ignore => ['COMP', 'DOSAGE_FORMF', 'MEASUREF'],
60
- :fields_as_floats => [ 'PEXT', 'PEXF', 'PPUB' ],
61
- :min_diff_for_floats => 0.01,
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
- def get_keys(items, key='GTIN')
72
- items.collect{|item| item[key].first.to_i }
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
- items.collect{|item| item.keys}.flatten.uniq.sort
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
- begin
81
- puts "\n#{Time.now.strftime("%H:%M:%S")}: Comparing #{name} in #{@left.basename} with #{@right.basename}"
82
- key = StammXML.get_component_key_name(name)
83
- left_items = @left.get_items(name)
84
- next unless left_items
85
- right_items = @right.get_items(name)
86
- next unless right_items
87
- @diff_stat[name] = {}
88
- @occurrences[name] = {}
89
- @diff_stat[name][NR_COMPARED] = 0
90
- l_names = get_names(left_items)
91
- r_names = get_names(right_items)
92
- compare_names = l_names & r_names
93
- l_keys = get_keys(left_items, key)
94
- r_keys = get_keys(right_items, key)
95
- (l_keys & r_keys).each do |id|
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
- NR_COMPARED = 'NR_COMPARED'
121
- COUNT = '_count'
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 '-'*(text.length+2*pad)
127
- puts ''.ljust(pad) + text
128
- puts '-'*(text.length+2*pad)
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['DSCR'] ? l_item['DSCR'].first[0..length-1].rjust(length) : ''.rjust(length)
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 += 'S' unless /S$/.match(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) && '--missing--'.eql?(r_value.first)) || (l_value.is_a?(Array) && '--missing--'.eql?(l_value.first))
158
- # TODO: get_field_from_v5_product
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(/[\[\]]/,'') if found
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 ' ' + keys[idx..(idx + batch_size-1)].join(' ')
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 += 'S' unless /S$/.match(component_name)
176
- @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"
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}: #{(keys).size} keys only in #{@right.basename}"
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}: #{(keys).size} keys only in #{@left.basename}"
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