proformaxml 1.2.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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