ruby3mf 0.2.0 → 0.2.1

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
  SHA1:
3
- metadata.gz: c96a243d6561a8d9bf5a047012d87275035191ae
4
- data.tar.gz: 7e913c8167d75dff3aad79a74fda2270b4c2811a
3
+ metadata.gz: 0e69399223f22bf72d431f634a3dae81966252da
4
+ data.tar.gz: f8a87375c839cb3e42e00496104ee0c0a6a1c93f
5
5
  SHA512:
6
- metadata.gz: 537228530d6b5baf851932a7c920b99b85ad25a202dfb6d5f20887b7cf9cb195588425031079bf483533d2f9bb06e856fe5f34f17fa18d8574baed3162fac2c5
7
- data.tar.gz: d416b8615337f1a199e6f8e0f968a754e07204a377d0b9cce7de63822bef42c84eb08feadd179552ae36f84b7a7bac0293fdae121b79053d354573f9efaa20bd
6
+ metadata.gz: 8ad2102f909a1df3f614010c4738b81e5b0ece6415d6f3f6cc47951151ed57f282b3150e4c2c581b41cd2685f46253df48c40117fbf0a323968a41502f594412
7
+ data.tar.gz: 7c0182a9da87926ad9a76eb604a72dfc68926720b14e7174a4672d8c8f18773bdfb835b6fff4c428983bdb9dbdf169b7980b55fec53aea070d697a98c8e36322
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
- --format documentation
2
1
  --color
2
+ --require spec_helper
data/bin/batch.rb CHANGED
@@ -5,16 +5,17 @@ require_relative '../lib/ruby3mf'
5
5
  files = Dir["spec/ruby3mf-testfiles/#{ARGV[0] || "failing_cases"}/*.#{ARGV[1] || '3mf'}"]
6
6
 
7
7
  files.each do |file|
8
+ begin
9
+ Log3mf.reset_log
10
+ doc = Document.read(file)
11
+ errors = Log3mf.entries(:error, :fatal_error)
8
12
 
9
- Log3mf.reset_log
10
- doc = Document.read(file)
11
- errors = Log3mf.entries(:error, :fatal_error)
12
-
13
- puts "=" * 100
14
- puts "Validating file: #{file}"
15
- errors.each do |ent|
16
- h = { context: ent[0], severity: ent[1], message: ent[2] }
17
- puts h
13
+ puts "=" * 100
14
+ puts "Validating file: #{file}"
15
+ errors.each do |ent|
16
+ h = { context: ent[0], severity: ent[1], message: ent[2] }
17
+ puts h
18
+ end
19
+ rescue
18
20
  end
19
-
20
21
  end
data/bin/suite.rb ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/ruby3mf'
4
+
5
+ # usage
6
+ # bin/suite.rb {path to 3mf-test-suite} optional
7
+ # assumes . is ~/src/ruby3mf and that ~/src/3mf-test-suite is path to suite repo files
8
+
9
+ $stdout.sync = true
10
+
11
+ good_files = Dir["#{ARGV[0] || '../3mf-test-suite'}/Positive/*.3mf"]
12
+ bad_files = Dir["#{ARGV[0] || '../3mf-test-suite'}/Negative/*.3mf"]
13
+
14
+ false_negatives = {}
15
+ true_negatives={}
16
+ false_positives = []
17
+
18
+ def val3mf(f)
19
+ Log3mf.reset_log
20
+ Document.read(f)
21
+ Log3mf.entries(:fatal_error, :error)
22
+ end
23
+
24
+ puts "\n\nPositive"
25
+ good_files.each do |file|
26
+ print "." # "Validating file: #{file}"
27
+ errors=val3mf(file)
28
+
29
+ if errors.size > 0
30
+ false_negatives[file]=errors
31
+ puts "\n#{file}"
32
+ errors.each do |ent|
33
+ h = {context: ent[0], severity: ent[1], message: ent[2]}
34
+ puts " #{h}"
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ puts "\n\nNegative"
41
+ bad_files.each do |file|
42
+ print "." #puts "Validating file #{file}"
43
+ errors=val3mf(file)
44
+ if errors.size > 0
45
+ true_negatives[file] = errors
46
+ else
47
+ false_positives << file
48
+ puts "\n#{file} - No Errors Found!"
49
+ end
50
+ end
data/lib/ruby3mf.rb CHANGED
@@ -8,6 +8,8 @@ require_relative "ruby3mf/relationships"
8
8
  require_relative "ruby3mf/thumbnail3mf"
9
9
  require_relative "ruby3mf/texture3mf"
10
10
  require_relative "ruby3mf/xml_val"
11
+ require_relative "ruby3mf/edge_list"
12
+ require_relative "ruby3mf/mesh_analyzer"
11
13
 
12
14
  require 'zip'
13
15
  require 'nokogiri'
@@ -16,10 +16,10 @@ Items within this schema follow a simple naming convention of appending a prefix
16
16
  <!-- Complex Types -->
17
17
  <xs:complexType name="CT_Model">
18
18
  <xs:sequence>
19
- <xs:element ref="metadata" minOccurs="0" maxOccurs="30000"/>
19
+ <xs:element ref="metadata" minOccurs="0" maxOccurs="unbounded"/>
20
20
  <xs:element ref="resources"/>
21
21
  <xs:element ref="build"/>
22
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
22
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
23
23
  </xs:sequence>
24
24
  <xs:attribute name="unit" type="ST_Unit" default="millimeter"/>
25
25
  <xs:attribute ref="xml:lang"/>
@@ -28,21 +28,21 @@ Items within this schema follow a simple naming convention of appending a prefix
28
28
  </xs:complexType>
29
29
  <xs:complexType name="CT_Resources">
30
30
  <xs:sequence>
31
- <xs:element ref="basematerials" minOccurs="0" maxOccurs="30000"/>
32
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
33
- <xs:element ref="object" minOccurs="0" maxOccurs="30000"/>
31
+ <xs:element ref="basematerials" minOccurs="0" maxOccurs="unbounded"/>
32
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
33
+ <xs:element ref="object" minOccurs="0" maxOccurs="unbounded"/>
34
34
  </xs:sequence>
35
35
  <xs:anyAttribute namespace="##other" processContents="lax"/>
36
36
  </xs:complexType>
37
37
  <xs:complexType name="CT_Build">
38
38
  <xs:sequence>
39
- <xs:element ref="item" minOccurs="0" maxOccurs="30000"/>
39
+ <xs:element ref="item" minOccurs="0" maxOccurs="unbounded"/>
40
40
  </xs:sequence>
41
41
  <xs:anyAttribute namespace="##other" processContents="lax"/>
42
42
  </xs:complexType>
43
43
  <xs:complexType name="CT_BaseMaterials">
44
44
  <xs:sequence>
45
- <xs:element ref="base" maxOccurs="30000"/>
45
+ <xs:element ref="base" maxOccurs="unbounded"/>
46
46
  </xs:sequence>
47
47
  <xs:attribute name="id" type="ST_ResourceID" use="required"/>
48
48
  </xs:complexType>
@@ -71,12 +71,12 @@ Items within this schema follow a simple naming convention of appending a prefix
71
71
  <xs:sequence>
72
72
  <xs:element ref="vertices"/>
73
73
  <xs:element ref="triangles"/>
74
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
74
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
75
75
  </xs:sequence>
76
76
  </xs:complexType>
77
77
  <xs:complexType name="CT_Vertices">
78
78
  <xs:sequence>
79
- <xs:element ref="vertex" minOccurs="3" maxOccurs="30000"/>
79
+ <xs:element ref="vertex" minOccurs="3" maxOccurs="unbounded"/>
80
80
  </xs:sequence>
81
81
  </xs:complexType>
82
82
  <xs:complexType name="CT_Vertex">
@@ -87,7 +87,7 @@ Items within this schema follow a simple naming convention of appending a prefix
87
87
  </xs:complexType>
88
88
  <xs:complexType name="CT_Triangles">
89
89
  <xs:sequence>
90
- <xs:element ref="triangle" minOccurs="1" maxOccurs="30000"/>
90
+ <xs:element ref="triangle" minOccurs="1" maxOccurs="unbounded"/>
91
91
  </xs:sequence>
92
92
  </xs:complexType>
93
93
  <xs:complexType name="CT_Triangle">
@@ -102,7 +102,7 @@ Items within this schema follow a simple naming convention of appending a prefix
102
102
  </xs:complexType>
103
103
  <xs:complexType name="CT_Components">
104
104
  <xs:sequence>
105
- <xs:element ref="component" maxOccurs="30000"/>
105
+ <xs:element ref="component" maxOccurs="unbounded"/>
106
106
  </xs:sequence>
107
107
  </xs:complexType>
108
108
  <xs:complexType name="CT_Component">
@@ -185,4 +185,4 @@ Items within this schema follow a simple naming convention of appending a prefix
185
185
  <xs:element name="component" type="CT_Component"/>
186
186
  <xs:element name="metadata" type="CT_Metadata"/>
187
187
  <xs:element name="item" type="CT_Item"/>
188
- </xs:schema>
188
+ </xs:schema>
@@ -38,31 +38,16 @@ class Document
38
38
 
39
39
  #verify that each texture part in the 3MF is related to the model through a texture relationship in a rels file
40
40
  def self.validate_texture_parts(document, log)
41
-
42
- return unless document.types.size > 0
43
- document.parts.each do |filename|
44
- ext = File::extname(filename).delete '.'
45
- content_type = document.types[ext]
46
- next unless TEXTURE_TYPES.include?(content_type)
47
-
48
- has_relationship = false
49
- document.textures.each do |texture_file|
50
- if texture_file[:target] == filename
51
- has_relationship = true
52
- break
53
- end
54
- end
55
-
56
- next unless !has_relationship
57
- document.thumbnails.each do |thumbnail_file|
58
- if thumbnail_file[:target] == filename
59
- has_relationship = true
60
- break
41
+ unless document.types.empty?
42
+ document.parts.select { |part| TEXTURE_TYPES.include?(document.types[File.extname(part).strip.downcase[1..-1]]) }.each do |tfile|
43
+ if document.textures.select { |f| f[:target] == tfile }.size == 0
44
+ if document.thumbnails.select { |t| t[:target] == tfile }.size == 0
45
+ log.context "part names" do |l|
46
+ l.warning "#{tfile} appears to be a texture file but no rels file declares any relationship to the model", page: 13
47
+ end
48
+ end
61
49
  end
62
50
  end
63
- log.context "part names /#{filename}" do |l|
64
- l.error :texture_without_relationship, name: filename unless has_relationship
65
- end
66
51
  end
67
52
  end
68
53
 
@@ -75,8 +60,10 @@ class Document
75
60
  Zip.warn_invalid_date = false
76
61
 
77
62
  # check for the general purpose flag set - if so, warn that 3mf may not work on some systems
78
- if File.read(input_file)[6] == "\b"
79
- l.warning 'File format: this file may not open on all systems'
63
+ File.open(input_file, "r") do |file|
64
+ if file.read[6] == "\b"
65
+ l.warning 'File format: this file may not open on all systems'
66
+ end
80
67
  end
81
68
 
82
69
  Zip::File.open(input_file) do |zip_file|
@@ -108,6 +95,9 @@ class Document
108
95
  content_type_match = zip_file.glob('\[Content_Types\].xml').first
109
96
  if content_type_match
110
97
  m.types = ContentTypes.parse(content_type_match)
98
+ model_extension = m.types.key('application/vnd.ms-package.3dmanufacturing-3dmodel+xml')
99
+ model_file = zip_file.glob("**/*.#{model_extension}").first
100
+ l.error :no_3d_model, extension: model_extension if model_file.nil?
111
101
  else
112
102
  l.error 'Missing required file: [Content_Types].xml', page: 4
113
103
  end
@@ -115,7 +105,7 @@ class Document
115
105
 
116
106
  l.context 'relationships' do |l|
117
107
  rel_file = zip_file.glob('_rels/.rels').first
118
- l.fatal_error 'Missing required file _rels/.rels', page: 4 unless rel_file
108
+ l.fatal_error :missing_dot_rels_file unless rel_file
119
109
 
120
110
  zip_file.glob('**/*.rels').each do |rel|
121
111
  m.relationships[rel.name] = Relationships.parse(rel)
@@ -49,6 +49,9 @@ invalid_content_type:
49
49
  invalid_startpart_type:
50
50
  msg: "rels/.rels Relationship file has an invalid attribute type for the root 3D Model (StartPart). The required type is \"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\""
51
51
  page: 10
52
+ invalid_startpart_target:
53
+ msg: "Invalid StartPart target '%{target}'. The 3MF Document StartPart relationship MUST point to the 3D Model part that identifies the root of the 3D payload."
54
+ page: 10
52
55
  invalid_relationship_type:
53
56
  msg: "Invalid relationship type '%{type}' specified in .rels relationship file. Parts in the 3D payload MUST use one of the appropriate relationship types to establish that relationship between two parts in the payload."
54
57
  page: 10
@@ -77,8 +80,8 @@ multiple_relationships:
77
80
  msg: "There MUST NOT be more than one relationship of a given relationship type from one part to a second part"
78
81
  page: 10
79
82
  no_3d_model:
80
- msg: "Relationship Target file /3D/3dmodel.model not found"
81
- page: 11
83
+ msg: "Required 3D model payload not found with provided Content Type model extension: .%{extension}"
84
+ page: 10
82
85
  not_a_zip:
83
86
  msg: "File provided is not a valid ZIP archive"
84
87
  page: 9
@@ -109,6 +112,9 @@ build_with_other_item:
109
112
  resource_id_collision:
110
113
  msg: "resources must be unique within the model"
111
114
  page: 22
115
+ resource_pid_missing:
116
+ msg: "A model resource referenced a property group id (pid) that is not present. Missing pid is: %{pid}"
117
+ page: 20
112
118
  metadata_elements_with_same_name:
113
119
  msg: "metadata elements must not share the same name"
114
120
  page: 22
@@ -121,18 +127,24 @@ unknown_required_extension:
121
127
  missing_extension_namespace_uri:
122
128
  msg: "Required extension '%{ns}' MUST refer to namespace with URI"
123
129
  page: 14
124
- texture_without_relationship:
125
- msg: "%{name} appears to be a texture file but no rels file declares any relationship to the model"
126
- page: 13
127
130
  invalid_metadata_under_defaultns:
128
131
  msg: "Metadata without a namespace name must only contain allowed name values"
129
132
  page: 21
133
+ invalid_metadata_name:
134
+ msg: "Metadata names must be prefixed with a valid namespace"
135
+ page: 21
130
136
  has_commas_for_floats:
131
137
  msg: "numbers not formatted for the en-US locale"
132
138
  page: 15
133
- invalid_language_locale:
134
- msg: "locale should be en-US"
135
- page: 15
136
139
  invalid_xml_core:
137
140
  msg: "XML file doesn't pass validation with the XSD file"
138
- page: 41
141
+ page: 15
142
+ missing_object_reference:
143
+ msg: "3D objects not referenced by an item element"
144
+ page: 23
145
+ non_distinct_indices:
146
+ msg: "The indices v1, v2 and v3 MUST be distinct."
147
+ page: 31
148
+ has_improper_base_color:
149
+ msg: "An sRGB color MUST be specified with a value of a 6 or 8 digit hexadecimal number"
150
+ page: 35
@@ -7,18 +7,14 @@ module Interpolation
7
7
  )
8
8
 
9
9
  def interpolate(string, values = {})
10
- if values.keys == 0
11
- string
12
- else
13
- string.gsub(INTERPOLATION_PATTERN) do |match|
14
- if match == '%%'
15
- '%'
16
- else
17
- key = ($1 || $2 || match.tr("%{}", "")).to_sym
18
- value = values[key]
19
- value = value.call(values) if value.respond_to?(:call)
20
- $3 ? sprintf("%#{$3}", value) : value
21
- end
10
+ string.gsub(INTERPOLATION_PATTERN) do |match|
11
+ if match == '%%'
12
+ '%'
13
+ else
14
+ key = ($1 || $2 || match.tr("%{}", "")).to_sym
15
+ value = values[key]
16
+ value = value.call(values) if value.respond_to?(:call)
17
+ $3 ? sprintf("%#{$3}", value) : value
22
18
  end
23
19
  end
24
20
  end
@@ -1,6 +1,3 @@
1
- require_relative 'edge_list'
2
-
3
-
4
1
  def find_child(node, child_name)
5
2
  node.children.each do |child|
6
3
  if child.name == child_name
@@ -37,6 +34,10 @@ class MeshAnalyzer
37
34
  v2 = triangle.attributes["v2"].to_s().to_i()
38
35
  v3 = triangle.attributes["v3"].to_s().to_i()
39
36
 
37
+ if v1 == v2 || v2 == v3 || v3 == v1
38
+ l.error :non_distinct_indices
39
+ end
40
+
40
41
  list.add_edge(v1, v2)
41
42
  list.add_edge(v2, v3)
42
43
  list.add_edge(v3, v1)
@@ -1,16 +1,16 @@
1
- require_relative 'mesh_analyzer'
2
-
3
1
  class Model3mf
4
2
 
5
3
  VALID_UNITS = ['micron', 'millimeter', 'centimeter', 'meter', 'inch', 'foot'].freeze
6
4
  VALID_EXTENSIONS = {
7
- 'http://schemas.microsoft.com/3dmanufacturing/slice/2015/07' => {},
8
- 'http://schemas.microsoft.com/3dmanufacturing/material/2015/02' => {},
9
- 'http://schemas.microsoft.com/3dmanufacturing/production/2015/06' => {},
5
+ 'http://schemas.microsoft.com/3dmanufacturing/slice/2015/07' => {},
6
+ 'http://schemas.microsoft.com/3dmanufacturing/material/2015/02' => {},
7
+ 'http://schemas.microsoft.com/3dmanufacturing/production/2015/06' => {},
10
8
  }.freeze
11
9
 
12
10
  SCHEMA = '3MFcoreSpec_1.1.xsd'
13
11
 
12
+ VALID_CORE_METADATA_NAMES = ['Title', 'Designer', 'Description', 'Copyright', 'LicenseTerms', 'Rating', 'CreationDate', 'ModificationDate'].freeze
13
+
14
14
  def self.parse(document, zip_entry)
15
15
  model_doc = nil
16
16
 
@@ -77,13 +77,32 @@ class Model3mf
77
77
  end
78
78
  end
79
79
 
80
+ l.context "verifying StartPart relationship points to the root 3D Model" do |l|
81
+ #Find the root 3D model which is pointed to by the start part
82
+ root_rels = document.relationships['_rels/.rels']
83
+ unless root_rels.nil?
84
+ start_part_rel = root_rels.select { |rel| rel[:type] == Document::MODEL_TYPE }.first
85
+ unless start_part_rel.nil? || start_part_rel[:target] != '/' + zip_entry.name
86
+ #Verify that the model is a valid root 3D model by checking if it has at least one object
87
+ l.fatal_error :invalid_startpart_target, :target => start_part_rel[:target] if model_doc.css("//model//resources//object").size == 0
88
+ end
89
+ else
90
+ l.fatal_error :missing_dot_rels_file
91
+ end
92
+ end
93
+
80
94
  end
81
95
 
82
- l.context "verifying resources" do |l|
83
- resources = find_child(model_doc.root, "resources")
96
+ l.context 'verifying resources' do |l|
97
+ resources = find_child(model_doc.root, 'resources')
84
98
  if resources
85
- ids = resources.children.map { |child| child.attributes["id"].to_s() if child.attributes["id"] }
99
+ ids = resources.children.map { |child| child.attributes['id'].to_s if child.attributes['id'] }
86
100
  l.error :resource_id_collision if ids.uniq.size != ids.size
101
+ pids = resources.children.map { |child| child.attributes['pid'].to_s }
102
+ missing_pids = pids.select { |pid| !pid.empty? and !ids.include? pid }
103
+ missing_pids.each do |p|
104
+ l.error :resource_pid_missing, pid: p
105
+ end
87
106
  end
88
107
  end
89
108
 
@@ -103,19 +122,19 @@ class Model3mf
103
122
  end
104
123
 
105
124
  l.context "checking metadata" do |l|
106
-
107
- metadata = model_doc.root.css("metadata")
108
-
109
- metadata_names = metadata.map { |met| met['name'] }
125
+ metadata_names = model_doc.root.css("metadata").map { |met| met['name'] }
110
126
  l.error :metadata_elements_with_same_name unless metadata_names.uniq!.nil?
111
127
 
112
- # metadata values allowed under default namespace (xmlns):
113
- metadata_values = ['Title', 'Designer', 'Description', 'Copyright', 'LicenseTerms', 'Rating', 'CreationDate', 'ModificationDate']
128
+ unless (metadata_names - VALID_CORE_METADATA_NAMES).empty?
129
+ extra_names = metadata_names - VALID_CORE_METADATA_NAMES
130
+ ns_names = extra_names.select { |n| n.include? ':' }
131
+
132
+ l.error :invalid_metadata_under_defaultns unless (extra_names - ns_names).empty?
114
133
 
115
- known_namespaces = ["http://schemas.microsoft.com/3dmanufacturing/core/2015/02", "http://schemas.microsoft.com/3dmanufacturing/material/2015/02"]
116
- only_known_namespaces = model_doc.root.namespace_definitions.all? { |ns| known_namespaces.include?(ns.href) }
117
- unless model_doc.root.namespace.href.nil? || !only_known_namespaces
118
- l.error :invalid_metadata_under_defaultns unless (metadata_names - metadata_values).empty?
134
+ unless ns_names.empty?
135
+ prefixes = model_doc.root.namespace_definitions.map { |defs| defs.prefix }.reject { |pre| pre.nil? }
136
+ l.error :invalid_metadata_name unless (ns_names.collect { |i| i.split(':').first } - prefixes).empty?
137
+ end
119
138
  end
120
139
  end
121
140
 
@@ -26,7 +26,7 @@ class Relationships
26
26
 
27
27
  if zip_entry.name=="_rels/.rels"
28
28
  l.context "Verifying StartPart" do |l|
29
- start_part_type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel"
29
+ start_part_type = Document::MODEL_TYPE
30
30
  start_part_count = relationships.select { |r| r[:type] == start_part_type }.size
31
31
  if start_part_count != 1
32
32
  l.error :invalid_startpart_type
@@ -1,3 +1,3 @@
1
1
  module Ruby3mf
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -12,32 +12,40 @@ class XmlVal
12
12
 
13
13
  def self.validate(file, document, schema_filename=nil)
14
14
  Log3mf.context "validations" do |l|
15
- l.error :invalid_language_locale if invalid_locale?(document)
16
- l.error :has_xml_space_attribute if space_attribute_exists?(document)
17
- l.error :wrong_encoding if xml_not_utf8_encoded?(document)
18
- l.error :dtd_not_allowed if dtd_exists?(file)
19
- l.error :has_commas_for_floats if bad_floating_numbers?(document)
15
+ l.error :has_xml_space_attribute if space_attribute_exists?(document)
16
+ l.error :wrong_encoding if xml_not_utf8_encoded?(document)
17
+ l.error :dtd_not_allowed if dtd_exists?(file)
18
+ l.error :has_commas_for_floats if bad_floating_numbers?(document)
19
+ l.warning :missing_object_reference if objects_not_referenced?(document)
20
20
 
21
21
  if schema_filename
22
22
  Log3mf.context "validating core schema" do |l|
23
- xsd = Nokogiri::XML::Schema(File.read(File.join(File.dirname(__FILE__), schema_filename)))
24
- core_schema_errors = xsd.validate(document)
25
- core_schema_errors.each { |error| puts error } if ENV["DEBUG_XSD_VALIDATION"]
26
- l.error :invalid_xml_core if core_schema_errors.size > 0
23
+ File.open(File.join(File.dirname(__FILE__), schema_filename), "r") do |file|
24
+ xsd = Nokogiri::XML::Schema(file.read)
25
+ puts "the schema is NIL!" if xsd.nil?
26
+ core_schema_errors = xsd.validate(document)
27
+ l.error :invalid_xml_core if core_schema_errors.size > 0
28
+ core_schema_errors.each do |error|
29
+ if error_involves_colorvalue?(error)
30
+ l.error :has_improper_base_color
31
+ else
32
+ l.error error
33
+ end
34
+ end
35
+ end
27
36
  end
28
37
  end
29
38
  end
30
39
  end
31
40
 
32
-
33
- def self.invalid_locale?(document)
34
- !document.xpath('//@xml:lang').empty? && document.xpath('//@xml:lang').text != "en-US"
41
+ def self.objects_not_referenced?(document)
42
+ document.css('object').map { |x| x.attributes["id"].value } != document.css('item').map { |x| x.attributes["objectid"].value }
35
43
  end
36
44
 
37
45
  def self.bad_floating_numbers?(document)
38
46
  !document.xpath('.//*[find_with_regex(., "[0-9]+\,[0-9]+")]', Class.new {
39
47
  def find_with_regex node_set, regex
40
- node_set.find_all { |node| node.values.any? {|v| v =~ /#{regex}/ } }
48
+ node_set.find_all { |node| node.values.any? { |v| v =~ /#{regex}/ } }
41
49
  end
42
50
  }.new).empty?
43
51
  end
@@ -54,4 +62,8 @@ class XmlVal
54
62
  found = file.get_input_stream.find { |line| line =~ /(!DOCTYPE\b)|(!ELEMENT\b)|(!ENTITY\b)|(!NOTATION\b)|(!ATTLIST\b)/ }
55
63
  !found.nil?
56
64
  end
65
+
66
+ def self.error_involves_colorvalue?(error)
67
+ error.to_s.include?("ST_ColorValue") || error.to_s.include?("displaycolor")
68
+ end
57
69
  end
data/ruby3mf.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.11"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_development_dependency "rspec", "~> 3.5"
25
25
  spec.add_development_dependency "simplecov"
26
26
 
27
27
  spec.add_runtime_dependency 'rubyzip'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby3mf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Whitmarsh, Jeff Porter, and William Hertling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-13 00:00:00.000000000 Z
11
+ date: 2017-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.0'
47
+ version: '3.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -146,6 +146,7 @@ files:
146
146
  - bin/console
147
147
  - bin/folder_test.sh
148
148
  - bin/setup
149
+ - bin/suite.rb
149
150
  - lib/ruby3mf.rb
150
151
  - lib/ruby3mf/3MFcoreSpec_1.1.xsd
151
152
  - lib/ruby3mf/content_types.rb