proformaxml 1.2.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 606acc3bf478e597146722128fa681af0e50985af661a74d302de9c3ab2b5b37
4
- data.tar.gz: 474a73f7e5a09f850d9c8b9e5a4fb90b93953d2ceece434750f91f5a8581b633
3
+ metadata.gz: 8284cbc28d6d2cabde0247312b5a526ffdb8be758261295757f3b4b132250004
4
+ data.tar.gz: 0fa49ec56a760ff164eed881b362bcb4307dcf6d789c9d395e65d67945c9654d
5
5
  SHA512:
6
- metadata.gz: d482b1a2a9ad647fe971577eeb6e5d19210e08b51bcdab7cc2daecea68cd1cc1389b80ff9da2d75cf628dd36999241655549a29ad41c9c666a9db4c698a7216d
7
- data.tar.gz: d5b0f74efc13fda6dbf91d55799321d694db0961b9d80d07bed395e6f202a0dc8ba935a2437fac82f51d455623af7b208df0b2e3f9e3fc264f1763488ec42031
6
+ metadata.gz: 16a96f01c9bb5a05008820954da688600b65d01d4733a45204c933d205635977e8e18358b05c20f2d14c898a6fca3b6e005ad84aa20122df8f2f8e3b8471f73e
7
+ data.tar.gz: 7b743f6b785d69e549bfb0948e19d90fdec93644aca4ae312c7d27c27c7748def994f1ea11e10084fc061567db47e2b14e2e7a7b026378448d7bcbbdb2a5268b
data/.rubocop.yml CHANGED
@@ -13,7 +13,7 @@ inherit_from:
13
13
  - .rubocop/style.yml
14
14
 
15
15
  AllCops:
16
- TargetRubyVersion: 3.2
16
+ TargetRubyVersion: 3.3
17
17
  TargetRailsVersion: 7.0 # for ActiveSupport
18
18
  UseCache: True
19
19
  NewCops: enable
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- proformaxml (1.2.0)
4
+ proformaxml (1.4.0)
5
5
  activemodel (>= 5.2.3, < 8.0.0)
6
6
  activesupport (>= 5.2.3, < 8.0.0)
7
7
  dachsfisch (~> 1.0.0)
@@ -11,9 +11,9 @@ PATH
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- activemodel (7.1.1)
15
- activesupport (= 7.1.1)
16
- activesupport (7.1.1)
14
+ activemodel (7.1.3.4)
15
+ activesupport (= 7.1.3.4)
16
+ activesupport (7.1.3.4)
17
17
  base64
18
18
  bigdecimal
19
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -24,21 +24,20 @@ GEM
24
24
  mutex_m
25
25
  tzinfo (~> 2.0)
26
26
  ast (2.4.2)
27
- base64 (0.1.1)
28
- bigdecimal (3.1.4)
27
+ base64 (0.2.0)
28
+ bigdecimal (3.1.8)
29
29
  byebug (11.1.3)
30
30
  coderay (1.1.3)
31
- concurrent-ruby (1.2.2)
31
+ concurrent-ruby (1.3.1)
32
32
  connection_pool (2.4.1)
33
33
  dachsfisch (1.0.0)
34
34
  nokogiri (>= 1.14.1, < 2.0.0)
35
- diff-lcs (1.5.0)
35
+ diff-lcs (1.5.1)
36
36
  docile (1.4.0)
37
- drb (2.1.1)
38
- ruby2_keywords
39
- factory_bot (6.3.0)
37
+ drb (2.2.1)
38
+ factory_bot (6.4.6)
40
39
  activesupport (>= 5.0.0)
41
- ffi (1.16.1)
40
+ ffi (1.16.3)
42
41
  formatador (1.1.0)
43
42
  guard (2.18.1)
44
43
  formatador (>= 0.2.4)
@@ -54,27 +53,27 @@ GEM
54
53
  guard (~> 2.1)
55
54
  guard-compat (~> 1.1)
56
55
  rspec (>= 2.99.0, < 4.0)
57
- i18n (1.14.1)
56
+ i18n (1.14.5)
58
57
  concurrent-ruby (~> 1.0)
59
- json (2.6.3)
58
+ json (2.7.2)
60
59
  language_server-protocol (3.17.0.3)
61
- listen (3.8.0)
60
+ listen (3.9.0)
62
61
  rb-fsevent (~> 0.10, >= 0.10.3)
63
62
  rb-inotify (~> 0.9, >= 0.9.10)
64
- lumberjack (1.2.9)
65
- method_source (1.0.0)
66
- mini_portile2 (2.8.4)
67
- minitest (5.20.0)
68
- mutex_m (0.1.2)
63
+ lumberjack (1.2.10)
64
+ method_source (1.1.0)
65
+ mini_portile2 (2.8.7)
66
+ minitest (5.23.1)
67
+ mutex_m (0.2.0)
69
68
  nenv (0.3.0)
70
- nokogiri (1.15.4)
69
+ nokogiri (1.16.6)
71
70
  mini_portile2 (~> 2.8.2)
72
71
  racc (~> 1.4)
73
72
  notiffany (0.1.3)
74
73
  nenv (~> 0.1)
75
74
  shellany (~> 0.0)
76
- parallel (1.23.0)
77
- parser (3.2.2.4)
75
+ parallel (1.24.0)
76
+ parser (3.3.1.0)
78
77
  ast (~> 2.4.1)
79
78
  racc
80
79
  pry (0.14.2)
@@ -83,63 +82,66 @@ GEM
83
82
  pry-byebug (3.10.1)
84
83
  byebug (~> 11.0)
85
84
  pry (>= 0.13, < 0.15)
86
- racc (1.7.1)
87
- rack (3.0.8)
85
+ racc (1.8.0)
86
+ rack (3.0.11)
88
87
  rainbow (3.1.1)
89
- rake (13.0.6)
88
+ rake (13.2.1)
90
89
  rb-fsevent (0.11.2)
91
90
  rb-inotify (0.10.1)
92
91
  ffi (~> 1.0)
93
- regexp_parser (2.8.2)
94
- rexml (3.2.6)
95
- rspec (3.12.0)
96
- rspec-core (~> 3.12.0)
97
- rspec-expectations (~> 3.12.0)
98
- rspec-mocks (~> 3.12.0)
92
+ regexp_parser (2.9.1)
93
+ rexml (3.2.8)
94
+ strscan (>= 3.0.9)
95
+ rspec (3.13.0)
96
+ rspec-core (~> 3.13.0)
97
+ rspec-expectations (~> 3.13.0)
98
+ rspec-mocks (~> 3.13.0)
99
99
  rspec-collection_matchers (1.2.1)
100
100
  rspec-expectations (>= 2.99.0.beta1)
101
- rspec-core (3.12.2)
102
- rspec-support (~> 3.12.0)
103
- rspec-expectations (3.12.3)
101
+ rspec-core (3.13.0)
102
+ rspec-support (~> 3.13.0)
103
+ rspec-expectations (3.13.0)
104
104
  diff-lcs (>= 1.2.0, < 2.0)
105
- rspec-support (~> 3.12.0)
105
+ rspec-support (~> 3.13.0)
106
106
  rspec-github (2.4.0)
107
107
  rspec-core (~> 3.0)
108
- rspec-mocks (3.12.6)
108
+ rspec-mocks (3.13.1)
109
109
  diff-lcs (>= 1.2.0, < 2.0)
110
- rspec-support (~> 3.12.0)
111
- rspec-support (3.12.1)
112
- rubocop (1.57.1)
113
- base64 (~> 0.1.1)
110
+ rspec-support (~> 3.13.0)
111
+ rspec-support (3.13.1)
112
+ rubocop (1.63.5)
114
113
  json (~> 2.3)
115
114
  language_server-protocol (>= 3.17.0)
116
115
  parallel (~> 1.10)
117
- parser (>= 3.2.2.4)
116
+ parser (>= 3.3.0.2)
118
117
  rainbow (>= 2.2.2, < 4.0)
119
118
  regexp_parser (>= 1.8, < 3.0)
120
119
  rexml (>= 3.2.5, < 4.0)
121
- rubocop-ast (>= 1.28.1, < 2.0)
120
+ rubocop-ast (>= 1.31.1, < 2.0)
122
121
  ruby-progressbar (~> 1.7)
123
122
  unicode-display_width (>= 2.4.0, < 3.0)
124
- rubocop-ast (1.29.0)
125
- parser (>= 3.2.1.0)
126
- rubocop-capybara (2.19.0)
123
+ rubocop-ast (1.31.3)
124
+ parser (>= 3.3.1.0)
125
+ rubocop-capybara (2.20.0)
127
126
  rubocop (~> 1.41)
128
- rubocop-factory_bot (2.24.0)
129
- rubocop (~> 1.33)
130
- rubocop-performance (1.19.1)
131
- rubocop (>= 1.7.0, < 2.0)
132
- rubocop-ast (>= 0.4.0)
133
- rubocop-rails (2.21.2)
127
+ rubocop-factory_bot (2.25.1)
128
+ rubocop (~> 1.41)
129
+ rubocop-performance (1.21.0)
130
+ rubocop (>= 1.48.1, < 2.0)
131
+ rubocop-ast (>= 1.31.1, < 2.0)
132
+ rubocop-rails (2.24.1)
134
133
  activesupport (>= 4.2.0)
135
134
  rack (>= 1.1)
136
135
  rubocop (>= 1.33.0, < 2.0)
137
- rubocop-rspec (2.24.1)
138
- rubocop (~> 1.33)
136
+ rubocop-ast (>= 1.31.1, < 2.0)
137
+ rubocop-rspec (2.29.2)
138
+ rubocop (~> 1.40)
139
139
  rubocop-capybara (~> 2.17)
140
140
  rubocop-factory_bot (~> 2.22)
141
+ rubocop-rspec_rails (~> 2.28)
142
+ rubocop-rspec_rails (2.28.3)
143
+ rubocop (~> 1.40)
141
144
  ruby-progressbar (1.13.0)
142
- ruby2_keywords (0.0.5)
143
145
  rubyzip (2.3.2)
144
146
  shellany (0.0.1)
145
147
  simplecov (0.22.0)
@@ -148,7 +150,8 @@ GEM
148
150
  simplecov_json_formatter (~> 0.1)
149
151
  simplecov-html (0.12.3)
150
152
  simplecov_json_formatter (0.1.4)
151
- thor (1.2.2)
153
+ strscan (3.1.0)
154
+ thor (1.3.1)
152
155
  tzinfo (2.0.6)
153
156
  concurrent-ruby (~> 1.0)
154
157
  unicode-display_width (2.5.0)
@@ -175,4 +178,4 @@ DEPENDENCIES
175
178
  simplecov
176
179
 
177
180
  BUNDLED WITH
178
- 2.4.18
181
+ 2.5.11
@@ -23,7 +23,7 @@ module ProformaXML
23
23
  if object.is_a? Hash
24
24
  object[name] = value
25
25
  else
26
- object.send("#{name}=", value)
26
+ object.send(:"#{name}=", value)
27
27
  end
28
28
  end
29
29
 
@@ -56,10 +56,10 @@ module ProformaXML
56
56
  end
57
57
 
58
58
  def add_test_configuration(test, test_node)
59
- test_configuration_node = test_node.xpath('xmlns:test-configuration')
59
+ test_configuration_node = test_node.xpath("#{@pro_ns}:test-configuration")
60
60
  test.files = test_files_from_test_configuration(test_configuration_node)
61
61
  test.configuration = extra_configuration_from_test_configuration(test_configuration_node)
62
- meta_data_node = test_node.xpath('xmlns:test-configuration').xpath('xmlns:test-meta-data')
62
+ meta_data_node = test_node.xpath("#{@pro_ns}:test-configuration").xpath("#{@pro_ns}:test-meta-data")
63
63
  test.meta_data = convert_xml_node_to_json(meta_data_node) if meta_data_node.present?
64
64
  end
65
65
 
@@ -75,28 +75,35 @@ module ProformaXML
75
75
  end
76
76
 
77
77
  def test_files_from_test_configuration(test_configuration_node)
78
- files_from_filerefs(test_configuration_node.search('filerefs'))
78
+ files_from_filerefs(test_configuration_node.xpath("#{@pro_ns}:filerefs"))
79
79
  end
80
80
 
81
81
  private
82
82
 
83
83
  def convert_xml_node_to_json(any_node)
84
84
  xml_snippet = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new, any_node)
85
- all_namespaces(any_node).each do |namespace|
85
+ all_namespaces_without_default(any_node).each do |namespace|
86
86
  xml_snippet.children.first.add_namespace_definition(namespace[:prefix], namespace[:href])
87
87
  end
88
- JSON.parse(Dachsfisch::XML2JSONConverter.perform(xml: xml_snippet.to_xml))
88
+ xml_without_custom_default_ns = xml_snippet.to_xml.gsub(%r{(</?)#{custom_default_namespace_prefix(any_node)}:}, '\1')
89
+ JSON.parse(Dachsfisch::XML2JSONConverter.perform(xml: xml_without_custom_default_ns))
89
90
  end
90
91
 
91
- def all_namespaces(node)
92
+ def all_namespaces_without_default(node)
92
93
  node.xpath('.|.//*').map(&:namespace).reject do |ns|
93
- ns.prefix.nil?
94
+ ns.prefix.nil? || ns.href.match?(/^urn:proforma:v\d.*$/)
94
95
  end.map {|ns| {prefix: ns.prefix, href: ns.href} }.uniq
95
96
  end
96
97
 
98
+ def custom_default_namespace_prefix(node)
99
+ node.xpath('.|.//*').map(&:namespace).filter do |ns|
100
+ ns.href.match?(/^urn:proforma:v\d.*$/)
101
+ end.map(&:prefix).first
102
+ end
103
+
97
104
  def value_from_node(name, node, attribute)
98
105
  xml_name = name.is_a?(Array) ? name[0] : name
99
- attribute ? node.attribute(xml_name)&.value : node.xpath("xmlns:#{xml_name}").text
106
+ attribute ? node.attribute(xml_name)&.value : node.xpath("#{@pro_ns}:#{xml_name}").text
100
107
  end
101
108
 
102
109
  def content_from_file_tag(file_tag, binary)
@@ -12,18 +12,26 @@ module ProformaXML
12
12
  @expected_version = expected_version
13
13
 
14
14
  xml = filestring_from_zip('task.xml')
15
- raise PreImportValidationError if xml.nil?
15
+ raise PreImportValidationError.new(['no task_xml found']) if xml.blank?
16
16
 
17
17
  @doc = Nokogiri::XML(xml, &:noblanks)
18
18
  @task = Task.new
19
19
  end
20
20
 
21
+ def proforma_namespace
22
+ namespace_regex = /^urn:proforma:v\d.*$/
23
+ namespaces = @doc.namespaces.filter do |_, href|
24
+ href.match? namespace_regex
25
+ end
26
+ namespaces.first.first.gsub('xmlns:', '')
27
+ end
28
+
21
29
  def perform
22
30
  errors = validate
31
+ raise PreImportValidationError.new(errors.map(&:message)) if errors.any?
23
32
 
24
- raise PreImportValidationError.new(errors) if errors.any?
25
-
26
- @task_node = @doc.xpath('/xmlns:task')
33
+ @pro_ns = proforma_namespace
34
+ @task_node = @doc.xpath("/#{@pro_ns}:task")
27
35
 
28
36
  set_data
29
37
  @task
@@ -37,11 +45,17 @@ module ProformaXML
37
45
  end
38
46
  end
39
47
 
48
+ def remove_referenced_files
49
+ referenced_files = (@task.tests.map(&:files) + @task.model_solutions.map(&:files)).flatten
50
+ @task.files.reject! {|f| referenced_files.include? f }
51
+ end
52
+
40
53
  def set_data
41
54
  set_base_data
42
55
  set_files
43
56
  set_model_solutions
44
57
  set_tests
58
+ remove_referenced_files
45
59
  set_meta_data
46
60
  set_extra_data
47
61
  end
@@ -57,44 +71,44 @@ module ProformaXML
57
71
  end
58
72
 
59
73
  def set_proglang
60
- return if @task_node.xpath('xmlns:proglang').text.blank?
74
+ return if @task_node.xpath("#{@pro_ns}:proglang").text.blank?
61
75
 
62
- @task.proglang = {name: @task_node.xpath('xmlns:proglang').text,
63
- version: @task_node.xpath('xmlns:proglang').attribute('version').value.presence}.compact
76
+ @task.proglang = {name: @task_node.xpath("#{@pro_ns}:proglang").text,
77
+ version: @task_node.xpath("#{@pro_ns}:proglang").attribute('version').value.presence}.compact
64
78
  end
65
79
 
66
80
  def set_files
67
- @task_node.search('files//file').each {|file_node| add_file file_node }
81
+ @task_node.xpath("#{@pro_ns}:files//#{@pro_ns}:file").each {|file_node| add_file file_node }
68
82
  end
69
83
 
70
84
  def set_tests
71
- @task_node.search('tests//test').each {|test_node| add_test test_node }
85
+ @task_node.xpath("#{@pro_ns}:tests//#{@pro_ns}:test").each {|test_node| add_test test_node }
72
86
  end
73
87
 
74
88
  def set_model_solutions
75
- @task_node.search('model-solutions//model-solution').each do |model_solution_node|
89
+ @task_node.xpath("#{@pro_ns}:model-solutions//#{@pro_ns}:model-solution").each do |model_solution_node|
76
90
  add_model_solution model_solution_node
77
91
  end
78
92
  end
79
93
 
80
94
  def set_meta_data
81
- meta_data_node = @task_node.xpath('xmlns:meta-data').first
95
+ meta_data_node = @task_node.xpath("#{@pro_ns}:meta-data").first
82
96
  @task.meta_data = convert_xml_node_to_json(meta_data_node) if meta_data_node.text.present?
83
97
  end
84
98
 
85
99
  def set_extra_data
86
- submission_restrictions_node = @task_node.xpath('xmlns:submission-restrictions').first
100
+ submission_restrictions_node = @task_node.xpath("#{@pro_ns}:submission-restrictions").first
87
101
  @task.submission_restrictions = convert_xml_node_to_json(submission_restrictions_node) unless submission_restrictions_node.nil?
88
- external_resources_node = @task_node.xpath('xmlns:external-resources').first
102
+ external_resources_node = @task_node.xpath("#{@pro_ns}:external-resources").first
89
103
  @task.external_resources = convert_xml_node_to_json(external_resources_node) unless external_resources_node.nil?
90
- grading_hints_node = @task_node.xpath('xmlns:grading-hints').first
104
+ grading_hints_node = @task_node.xpath("#{@pro_ns}:grading-hints").first
91
105
  @task.grading_hints = convert_xml_node_to_json(grading_hints_node) unless grading_hints_node.nil?
92
106
  end
93
107
 
94
108
  def add_model_solution(model_solution_node)
95
109
  model_solution = ModelSolution.new
96
110
  model_solution.id = model_solution_node.attributes['id'].value
97
- model_solution.files = files_from_filerefs(model_solution_node.search('filerefs'))
111
+ model_solution.files = files_from_filerefs(model_solution_node.xpath("#{@pro_ns}:filerefs"))
98
112
  set_value_from_xml(object: model_solution, node: model_solution_node, name: 'description')
99
113
  set_value_from_xml(object: model_solution, node: model_solution_node, name: 'internal-description')
100
114
  @task.model_solutions << model_solution unless model_solution.files.first&.id == 'ms-placeholder-file'
@@ -125,9 +139,9 @@ module ProformaXML
125
139
 
126
140
  def files_from_filerefs(filerefs_node)
127
141
  [].tap do |files|
128
- filerefs_node.search('fileref').each do |fileref_node|
142
+ filerefs_node.xpath("#{@pro_ns}:fileref").each do |fileref_node|
129
143
  fileref = fileref_node.attributes['refid'].value
130
- files << @task.files.delete(@task.files.detect {|file| file.id == fileref })
144
+ files << @task.files.detect {|file| file.id == fileref }
131
145
  end
132
146
  end
133
147
  end
@@ -14,7 +14,14 @@ module ProformaXML
14
14
  private
15
15
 
16
16
  def doc_schema_version
17
- @doc_schema_version ||= /^urn:proforma:v(.*)$/.match(@doc.namespaces['xmlns'])&.captures&.dig(0)
17
+ namespace_regex = /^urn:proforma:v(\d.*)$/
18
+ potential_namespaces = @doc.namespaces.filter do |_, href|
19
+ href.match? namespace_regex
20
+ end
21
+ return nil unless potential_namespaces.length == 1
22
+
23
+ @pro_ns = potential_namespaces.first[0].gsub('xmlns:', '')
24
+ @doc_schema_version ||= namespace_regex.match(potential_namespaces.first[1])&.captures&.dig(0)
18
25
  end
19
26
 
20
27
  def node_as_doc_with_namespace(config_node)
@@ -38,7 +45,7 @@ module ProformaXML
38
45
  end
39
46
 
40
47
  def validate_test_configuration
41
- @doc.xpath('/xmlns:task/xmlns:tests/xmlns:test/xmlns:test-configuration').flat_map do |test_config|
48
+ @doc.xpath("/#{@pro_ns}:task/#{@pro_ns}:tests/#{@pro_ns}:test/#{@pro_ns}:test-configuration").flat_map do |test_config|
42
49
  test_config.children.flat_map do |config_node|
43
50
  next [] unless config_node.namespace&.href&.start_with?('urn:proforma:tests:')
44
51
  next [] unless TEST_TYPE_SCHEMA_NAMES.include? config_node.name
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProformaXML
4
- VERSION = '1.2.0'
4
+ VERSION = '1.4.0'
5
5
  end
data/proformaxml.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'https://github.com/openHPI/proformaxml'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.required_ruby_version = '>= 3.2'
16
+ spec.required_ruby_version = '>= 3.3'
17
17
 
18
18
  # Specify which files should be added to the gem when it is released.
19
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proformaxml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karol
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-25 00:00:00.000000000 Z
11
+ date: 2024-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -160,14 +160,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
160
  requirements:
161
161
  - - ">="
162
162
  - !ruby/object:Gem::Version
163
- version: '3.2'
163
+ version: '3.3'
164
164
  required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  requirements:
166
166
  - - ">="
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.4.1
170
+ rubygems_version: 3.5.9
171
171
  signing_key:
172
172
  specification_version: 4
173
173
  summary: Implements parts of ProFormA-XML specification