dcc 0.2.0 → 0.2.1

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +19 -0
  3. data/.github/workflows/release.yml +28 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop_todo.yml +560 -10
  6. data/CHANGELOG.adoc +34 -1
  7. data/CONTRIBUTING.adoc +8 -1
  8. data/Gemfile +5 -7
  9. data/README.adoc +162 -7
  10. data/dcc.gemspec +8 -2
  11. data/docs/schema-versions.adoc +20 -7
  12. data/examples/build_minimal_dcc.rb +0 -0
  13. data/examples/convert_all_formats.rb +2 -1
  14. data/examples/parse_and_inspect.rb +0 -0
  15. data/examples/quantity_math_demo.rb +7 -7
  16. data/examples/validate_full.rb +1 -1
  17. data/lib/dcc/base/calibration_laboratory.rb +2 -1
  18. data/lib/dcc/base/condition.rb +5 -2
  19. data/lib/dcc/base/core_data.rb +8 -3
  20. data/lib/dcc/base/formula.rb +3 -3
  21. data/lib/dcc/base/identification.rb +6 -3
  22. data/lib/dcc/base/mathml.rb +33 -0
  23. data/lib/dcc/base/quantity.rb +2 -1
  24. data/lib/dcc/base/resp_person.rb +4 -2
  25. data/lib/dcc/base/text.rb +1 -1
  26. data/lib/dcc/base.rb +2 -1
  27. data/lib/dcc/builder/dsl.rb +1 -1
  28. data/lib/dcc/builder/session.rb +16 -14
  29. data/lib/dcc/builder.rb +3 -3
  30. data/lib/dcc/cli/cli.rb +36 -18
  31. data/lib/dcc/cli/formatters.rb +35 -7
  32. data/lib/dcc/cli.rb +1 -1
  33. data/lib/dcc/context_configuration.rb +2 -1
  34. data/lib/dcc/context_options.rb +4 -2
  35. data/lib/dcc/convert/csv.rb +27 -9
  36. data/lib/dcc/convert/html.rb +26 -110
  37. data/lib/dcc/convert/json.rb +10 -7
  38. data/lib/dcc/convert/liquid_filters.rb +58 -0
  39. data/lib/dcc/convert/result.rb +1 -1
  40. data/lib/dcc/convert/templates/report.liquid +250 -0
  41. data/lib/dcc/convert/yaml.rb +1 -1
  42. data/lib/dcc/convert.rb +1 -0
  43. data/lib/dcc/diff/change.rb +1 -1
  44. data/lib/dcc/diff/result.rb +8 -4
  45. data/lib/dcc/diff.rb +43 -11
  46. data/lib/dcc/error.rb +7 -0
  47. data/lib/dcc/extract/file.rb +3 -4
  48. data/lib/dcc/extract/ring.rb +1 -1
  49. data/lib/dcc/extract.rb +1 -1
  50. data/lib/dcc/i18n/text_lookup.rb +8 -4
  51. data/lib/dcc/i18n.rb +1 -1
  52. data/lib/dcc/inspect/report.rb +51 -14
  53. data/lib/dcc/inspect.rb +1 -1
  54. data/lib/dcc/migrate/route.rb +44 -0
  55. data/lib/dcc/migrate/v2_to_v3.rb +445 -0
  56. data/lib/dcc/migrate.rb +130 -26
  57. data/lib/dcc/plugin/base.rb +64 -0
  58. data/lib/dcc/plugin/registry.rb +7 -2
  59. data/lib/dcc/plugin.rb +6 -2
  60. data/lib/dcc/quantity_format/formatter.rb +16 -10
  61. data/lib/dcc/quantity_format.rb +1 -1
  62. data/lib/dcc/quantity_math/quantity.rb +1 -1
  63. data/lib/dcc/quantity_math/real.rb +6 -6
  64. data/lib/dcc/quantity_math.rb +1 -1
  65. data/lib/dcc/schema/version.rb +2 -2
  66. data/lib/dcc/server/app.html +282 -0
  67. data/lib/dcc/server/app.rb +171 -87
  68. data/lib/dcc/server/demo_cert.xml +244 -0
  69. data/lib/dcc/server/storage/entry.rb +1 -1
  70. data/lib/dcc/server/storage/memory.rb +3 -2
  71. data/lib/dcc/server/storage.rb +1 -1
  72. data/lib/dcc/server.rb +1 -1
  73. data/lib/dcc/si/base/complex.rb +1 -1
  74. data/lib/dcc/si/base/complex_list_xml_list.rb +1 -1
  75. data/lib/dcc/si/base/constant.rb +1 -1
  76. data/lib/dcc/si/base/coverage_interval.rb +36 -0
  77. data/lib/dcc/si/base/coverage_interval_mu.rb +1 -1
  78. data/lib/dcc/si/base/expanded_mu.rb +1 -1
  79. data/lib/dcc/si/base/expanded_unc.rb +34 -0
  80. data/lib/dcc/si/base/expanded_unc_xml_list.rb +3 -2
  81. data/lib/dcc/si/base/hybrid.rb +3 -2
  82. data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +1 -1
  83. data/lib/dcc/si/base/real.rb +13 -3
  84. data/lib/dcc/si/base/real_list_xml_list.rb +5 -3
  85. data/lib/dcc/si/base/si_list.rb +3 -2
  86. data/lib/dcc/si/base/standard_mu.rb +1 -1
  87. data/lib/dcc/si/base.rb +5 -2
  88. data/lib/dcc/si/v1/coverage_interval.rb +8 -0
  89. data/lib/dcc/si/v1/expanded_unc.rb +1 -16
  90. data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +2 -1
  91. data/lib/dcc/si/v1.rb +5 -2
  92. data/lib/dcc/si/v2/coverage_interval.rb +8 -0
  93. data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +4 -2
  94. data/lib/dcc/si/v2/expanded_mu_xml_list.rb +2 -1
  95. data/lib/dcc/si/v2/expanded_unc.rb +8 -0
  96. data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +2 -1
  97. data/lib/dcc/si/v2.rb +8 -3
  98. data/lib/dcc/signature/result.rb +2 -2
  99. data/lib/dcc/signature/signer.rb +31 -18
  100. data/lib/dcc/signature/verifier.rb +23 -21
  101. data/lib/dcc/signature.rb +1 -1
  102. data/lib/dcc/transform/result.rb +1 -1
  103. data/lib/dcc/transform/xslt.rb +22 -12
  104. data/lib/dcc/transform.rb +5 -4
  105. data/lib/dcc/type/base64_binary.rb +5 -3
  106. data/lib/dcc/type/decimal_xml_list.rb +99 -13
  107. data/lib/dcc/type/iso_country_code.rb +3 -2
  108. data/lib/dcc/type/iso_language_code.rb +3 -2
  109. data/lib/dcc/type/schema_version.rb +3 -2
  110. data/lib/dcc/type/si_unit.rb +3 -2
  111. data/lib/dcc/type_guards.rb +3 -3
  112. data/lib/dcc/v2/calibration_laboratory.rb +2 -1
  113. data/lib/dcc/v2/condition.rb +22 -1
  114. data/lib/dcc/v2/configuration.rb +1 -1
  115. data/lib/dcc/v2/digital_calibration_certificate.rb +2 -1
  116. data/lib/dcc/v2/identification.rb +14 -1
  117. data/lib/dcc/v2/mathml.rb +8 -0
  118. data/lib/dcc/v2/measurement_meta_data_list.rb +2 -1
  119. data/lib/dcc/v2/quantity.rb +4 -2
  120. data/lib/dcc/v2.rb +4 -2
  121. data/lib/dcc/v3/calibration_laboratory.rb +2 -1
  122. data/lib/dcc/v3/configuration.rb +1 -1
  123. data/lib/dcc/v3/digital_calibration_certificate.rb +2 -1
  124. data/lib/dcc/v3/mathml.rb +8 -0
  125. data/lib/dcc/v3/measurement_meta_data_list.rb +2 -1
  126. data/lib/dcc/v3/quantity.rb +4 -2
  127. data/lib/dcc/v3.rb +12 -2
  128. data/lib/dcc/validate/business_rules.rb +23 -9
  129. data/lib/dcc/validate/issue.rb +2 -1
  130. data/lib/dcc/validate/result.rb +6 -4
  131. data/lib/dcc/validate/schematron/profile.rb +73 -18
  132. data/lib/dcc/validate/schematron/rule.rb +13 -3
  133. data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +11 -4
  134. data/lib/dcc/validate/schematron/rules/base.rb +1 -2
  135. data/lib/dcc/validate/schematron/rules/date_range_check.rb +11 -5
  136. data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +0 -3
  137. data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +22 -12
  138. data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +31 -14
  139. data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +12 -5
  140. data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +7 -4
  141. data/lib/dcc/validate/schematron/rules/release_format_check.rb +7 -4
  142. data/lib/dcc/validate/schematron/rules/schema_version_check.rb +13 -9
  143. data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +39 -10
  144. data/lib/dcc/validate/schematron/rules/unit_format_check.rb +2 -3
  145. data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +15 -10
  146. data/lib/dcc/validate/schematron/rules/used_software_placement.rb +15 -10
  147. data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +4 -3
  148. data/lib/dcc/validate/schematron/rules.rb +28 -14
  149. data/lib/dcc/validate/schematron.rb +1 -1
  150. data/lib/dcc/validate/xsd.rb +9 -3
  151. data/lib/dcc/validate.rb +1 -1
  152. data/lib/dcc/version.rb +1 -1
  153. data/lib/dcc/versioned_parser.rb +1 -1
  154. data/lib/dcc.rb +55 -7
  155. data/sample_dcc.xml +140 -0
  156. data/web/index.html +12 -0
  157. data/web/package-lock.json +1599 -0
  158. data/web/package.json +22 -0
  159. data/web/src/App.vue +349 -0
  160. data/web/src/lib/builder.ts +171 -0
  161. data/web/src/lib/dcc.ts +338 -0
  162. data/web/src/lib/units.json +5581 -0
  163. data/web/src/main.ts +5 -0
  164. data/web/src/style.css +27 -0
  165. data/web/tsconfig.json +15 -0
  166. data/web/vite.config.ts +14 -0
  167. metadata +125 -9
@@ -1,19 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bigdecimal"
4
+ require "forwardable"
4
5
  require "lutaml/model"
5
6
 
6
7
  module Dcc
7
8
  module Type
8
9
  # Space-separated list of decimals, as used by D-SI `*XMLList` elements
9
10
  # (e.g. `<si:valueXMLList>306 373 448</si:valueXMLList>`). Parses to/from
10
- # an Array of BigDecimal values.
11
+ # a `Values` list of BigDecimal.
12
+ #
13
+ # `cast` deliberately does not return a plain Array: lutaml-model treats an
14
+ # Array-valued attribute as a collection and would emit one element per
15
+ # decimal instead of a single space-separated list.
11
16
  class DecimalXmlList < Lutaml::Model::Type::Value
17
+ # An ordered list of BigDecimals that renders as space-separated text and
18
+ # compares equal to the equivalent Array.
19
+ class Values
20
+ include Enumerable
21
+ extend Forwardable
22
+
23
+ def_delegators :@decimals, :size, :length, :empty?, :last, :[]
24
+
25
+ def initialize(decimals)
26
+ @decimals = decimals
27
+ end
28
+
29
+ def each(&)
30
+ return to_enum(:each) unless block_given?
31
+
32
+ @decimals.each(&)
33
+ self
34
+ end
35
+
36
+ # Implicit conversion, so `Array#==` delegates back here instead of
37
+ # returning false and making equality asymmetric.
38
+ def to_ary
39
+ @decimals.dup
40
+ end
41
+
42
+ # Joined over the serialized decimals, not the raw BigDecimals, so it
43
+ # cannot disagree with `to_s` by emitting "0.72e-1" for "0.072".
44
+ def join(separator = " ")
45
+ map { |decimal| DecimalXmlList.serialize_one(decimal) }.join(separator)
46
+ end
47
+
48
+ def to_s
49
+ DecimalXmlList.serialize(self)
50
+ end
51
+
52
+ # Dumped as its wire form, so YAML matches JSON rather than leaking a
53
+ # `!ruby/object:` tag that `safe_load` refuses to read back.
54
+ def encode_with(coder)
55
+ coder.represent_scalar(nil, to_s)
56
+ end
57
+
58
+ def ==(other)
59
+ case other
60
+ when Values then to_a == other.to_a
61
+ when ::Array then to_a == other
62
+ else false
63
+ end
64
+ end
65
+
66
+ # Stricter than `==`, which accepts a plain Array. Hash lookup pairs
67
+ # `eql?` with `hash`, and an Array keyed alongside us would hash the
68
+ # same while comparing equal in only one direction.
69
+ def eql?(other)
70
+ other.is_a?(Values) && to_a == other.to_a
71
+ end
72
+
73
+ def hash
74
+ to_a.hash
75
+ end
76
+ end
77
+
12
78
  def self.cast(value)
13
- return [] if value.nil?
14
- return value.map { |v| cast_one(v) } if value.is_a?(::Array)
79
+ return value if value.is_a?(Values)
80
+ return Values.new([]) if value.nil?
15
81
 
16
- value.to_s.split(/\s+/).reject(&:empty?).map { |s| cast_one(s) }
82
+ tokens = value.is_a?(::Array) ? value : value.to_s.split
83
+ Values.new(tokens.map { |token| cast_one(token) })
17
84
  end
18
85
 
19
86
  def self.serialize(value)
@@ -22,24 +89,43 @@ module Dcc
22
89
  Array(value).map { |v| serialize_one(v) }.join(" ")
23
90
  end
24
91
 
92
+ # One decimal in the notation D-SI writes, e.g. 0.072 rather than
93
+ # BigDecimal's own "0.72e-1". `to_s("F")` renders every BigDecimal,
94
+ # finite or not, and `sub` only trims a trailing ".0". That is what
95
+ # lets `NaN` through, which D-SI admits in every decimal type
96
+ # (SI_Format.xsd:1195).
97
+ def self.serialize_one(value)
98
+ reject_infinite!(value)
99
+
100
+ case value
101
+ when ::BigDecimal then value.to_s("F").sub(/\.0\z/, "")
102
+ when ::Float then format("%.15g", value)
103
+ else value.to_s
104
+ end
105
+ end
106
+
25
107
  class << self
26
108
  private
27
109
 
28
110
  def cast_one(token)
29
- return token if token.is_a?(::BigDecimal)
30
-
31
- BigDecimal(token.to_s)
111
+ decimal = token.is_a?(::BigDecimal) ? token : BigDecimal(token.to_s)
112
+ reject_infinite!(decimal)
113
+ decimal
32
114
  rescue ::ArgumentError => e
33
115
  raise Lutaml::Model::Type::InvalidValueError.new(token,
34
116
  "invalid decimal in XML list: #{e.message}")
35
117
  end
36
118
 
37
- def serialize_one(value)
38
- case value
39
- when ::BigDecimal then value.to_i.to_s == value.to_s("F") ? value.to_i.to_s : value.to_s("F").sub(/\.0\z/, "")
40
- when ::Float then format("%.15g", value)
41
- else value.to_s
42
- end
119
+ # Called from `cast_one` and from the public `serialize_one`, since
120
+ # `serialize` takes a raw BigDecimal and casting is not the only way in.
121
+ def reject_infinite!(value)
122
+ return unless value.is_a?(::BigDecimal) && value.infinite?
123
+
124
+ raise Lutaml::Model::Type::InvalidValueError.new(
125
+ value,
126
+ "infinity is not a D-SI decimal: SI_Format.xsd:1195 admits " \
127
+ "numbers and NaN only",
128
+ )
43
129
  end
44
130
  end
45
131
  end
@@ -7,13 +7,14 @@ module Dcc
7
7
  # ISO 3166-1 alpha-2 country code (two uppercase letters, e.g. `"DE"`).
8
8
  # Used by `dcc:countryCodeISO3166_1`.
9
9
  class IsoCountryCode < Lutaml::Model::Type::String
10
- PATTERN = /\A[A-Z]{2}\z/.freeze
10
+ PATTERN = /\A[A-Z]{2}\z/
11
11
 
12
12
  def self.cast(value)
13
13
  return nil unless value.is_a?(::String) && value != ""
14
14
 
15
15
  unless PATTERN.match?(value)
16
- raise Lutaml::Model::Type::InvalidValueError.new(value, "invalid ISO 3166-1 alpha-2 country code: #{value.inspect}")
16
+ raise Lutaml::Model::Type::InvalidValueError.new(value,
17
+ "invalid ISO 3166-1 alpha-2 country code: #{value.inspect}")
17
18
  end
18
19
 
19
20
  value
@@ -7,13 +7,14 @@ module Dcc
7
7
  # ISO 639-1 language code (two lowercase letters, e.g. `"en"`).
8
8
  # Used by `dcc:usedLangCodeISO639_1` and `dcc:mandatoryLangCodeISO639_1`.
9
9
  class IsoLanguageCode < Lutaml::Model::Type::String
10
- PATTERN = /\A[a-z]{2}\z/.freeze
10
+ PATTERN = /\A[a-z]{2}\z/
11
11
 
12
12
  def self.cast(value)
13
13
  return nil unless value.is_a?(::String) && value != ""
14
14
 
15
15
  unless PATTERN.match?(value)
16
- raise Lutaml::Model::Type::InvalidValueError.new(value, "invalid ISO 639-1 language code: #{value.inspect}")
16
+ raise Lutaml::Model::Type::InvalidValueError.new(value,
17
+ "invalid ISO 639-1 language code: #{value.inspect}")
17
18
  end
18
19
 
19
20
  value
@@ -12,13 +12,14 @@ module Dcc
12
12
  (?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)
13
13
  (?:-(?<pre>[0-9A-Za-z.-]+))?
14
14
  (?:\+(?<build>[0-9A-Za-z.-]+))?
15
- \z/x.freeze
15
+ \z/x
16
16
 
17
17
  def self.cast(value)
18
18
  return nil unless value.is_a?(::String) && value != ""
19
19
 
20
20
  unless PATTERN.match?(value)
21
- raise Lutaml::Model::Type::InvalidValueError.new(value, "invalid schemaVersion")
21
+ raise Lutaml::Model::Type::InvalidValueError.new(value,
22
+ "invalid schemaVersion")
22
23
  end
23
24
 
24
25
  value
@@ -10,13 +10,14 @@ module Dcc
10
10
  # check: the string must not contain whitespace (Schematron rule), and the
11
11
  # non-SI declaration prefix (`|unit`) is allowed.
12
12
  class SiUnit < Lutaml::Model::Type::String
13
- NO_WHITESPACE_PATTERN = /\A\S+\z/.freeze
13
+ NO_WHITESPACE_PATTERN = /\A\S+\z/
14
14
 
15
15
  def self.cast(value)
16
16
  return nil unless value.is_a?(::String) && value != ""
17
17
 
18
18
  unless NO_WHITESPACE_PATTERN.match?(value)
19
- raise Lutaml::Model::Type::InvalidValueError.new(value, "invalid SI unit expression (whitespace not allowed): #{value.inspect}")
19
+ raise Lutaml::Model::Type::InvalidValueError.new(value,
20
+ "invalid SI unit expression (whitespace not allowed): #{value.inspect}")
20
21
  end
21
22
 
22
23
  value
@@ -130,11 +130,11 @@ module Dcc
130
130
  end
131
131
 
132
132
  # Safe method call: invokes the method if the node's class declares it.
133
- def call_if_present(node, method_name, *args)
133
+ def call_if_present(node, method_name, *)
134
134
  return nil unless node.is_a?(::Lutaml::Model::Serializable)
135
135
  return nil unless node.class.attributes.key?(method_name)
136
136
 
137
- node.public_send(method_name, *args)
137
+ node.public_send(method_name, *)
138
138
  end
139
139
  end
140
- end
140
+ end
@@ -4,5 +4,6 @@ module Dcc::V2
4
4
  class CalibrationLaboratory < CommonElements
5
5
  include ::Dcc::Base::CalibrationLaboratory
6
6
  end
7
- Configuration.register_model(CalibrationLaboratory, id: :calibrationLaboratory)
7
+ Configuration.register_model(CalibrationLaboratory,
8
+ id: :calibrationLaboratory)
8
9
  end
@@ -1,8 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dcc::V2
4
+ # v2 calls the influence condition's state element `state`; v3 renamed it to
5
+ # `status`, which the shared base module carries.
4
6
  class Condition < CommonElements
5
- include ::Dcc::Base::Condition
7
+ attribute :id, :string
8
+ attribute :ref_id, :string
9
+ attribute :ref_type, :string
10
+ attribute :name, :text
11
+ attribute :description, :text
12
+ attribute :status, :string
13
+ attribute :data, :data, collection: true
14
+
15
+ xml do
16
+ namespace ::Dcc::Namespace::Dcc
17
+ element "influenceCondition"
18
+ ordered
19
+ map_attribute "id", to: :id
20
+ map_attribute "refId", to: :ref_id
21
+ map_attribute "refType", to: :ref_type
22
+ map_element "name", to: :name
23
+ map_element "description", to: :description
24
+ map_element "state", to: :status
25
+ map_element "data", to: :data
26
+ end
6
27
  end
7
28
  Configuration.register_model(Condition, id: :influenceCondition)
8
29
  end
@@ -10,7 +10,7 @@ module Dcc
10
10
  # V2 DCC imports D-SI v1.x (registered as :dsi_v1). We also fall back
11
11
  # to :dsi_v2 for forward-compatible parsing.
12
12
  def self.fallback_contexts
13
- [:dsi_v1, :dsi_v2, :default]
13
+ %i[dsi_v1 dsi_v2 default]
14
14
  end
15
15
  end
16
16
  end
@@ -4,5 +4,6 @@ module Dcc::V2
4
4
  class DigitalCalibrationCertificate < CommonElements
5
5
  include ::Dcc::Base::DigitalCalibrationCertificate
6
6
  end
7
- Configuration.register_model(DigitalCalibrationCertificate, id: :digitalCalibrationCertificate)
7
+ Configuration.register_model(DigitalCalibrationCertificate,
8
+ id: :digitalCalibrationCertificate)
8
9
  end
@@ -1,8 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dcc::V2
4
+ # v2 calls the identification's third child `description`; v3 renamed it to
5
+ # `name`, which the shared base module carries.
4
6
  class Identification < CommonElements
5
- include ::Dcc::Base::Identification
7
+ attribute :issuer, :string
8
+ attribute :value, :string
9
+ attribute :description, :text
10
+
11
+ xml do
12
+ namespace ::Dcc::Namespace::Dcc
13
+ element "identification"
14
+ ordered
15
+ map_element "issuer", to: :issuer
16
+ map_element "value", to: :value
17
+ map_element "description", to: :description
18
+ end
6
19
  end
7
20
  Configuration.register_model(Identification, id: :identification)
8
21
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc::V2
4
+ class Mathml < CommonElements
5
+ include ::Dcc::Base::Mathml
6
+ end
7
+ Configuration.register_model(Mathml, id: :mathml)
8
+ end
@@ -4,5 +4,6 @@ module Dcc::V2
4
4
  class MeasurementMetaDataList < CommonElements
5
5
  include ::Dcc::Base::MeasurementMetaDataList
6
6
  end
7
- Configuration.register_model(MeasurementMetaDataList, id: :measurementMetaData)
7
+ Configuration.register_model(MeasurementMetaDataList,
8
+ id: :measurementMetaData)
8
9
  end
@@ -19,8 +19,10 @@ module Dcc::V2
19
19
  attribute :complex, ::Dcc::Si::V1::Complex, collection: true
20
20
  attribute :constant, ::Dcc::Si::V1::Constant, collection: true
21
21
  attribute :hybrid, ::Dcc::Si::V1::Hybrid, collection: true
22
- attribute :real_list_xml_list, ::Dcc::Si::V1::RealListXmlList, collection: true
23
- attribute :complex_list_xml_list, ::Dcc::Si::V1::ComplexListXmlList, collection: true
22
+ attribute :real_list_xml_list, ::Dcc::Si::V1::RealListXmlList,
23
+ collection: true
24
+ attribute :complex_list_xml_list, ::Dcc::Si::V1::ComplexListXmlList,
25
+ collection: true
24
26
  attribute :list, ::Dcc::Si::V1::SiList, collection: true
25
27
 
26
28
  xml do
data/lib/dcc/v2.rb CHANGED
@@ -14,6 +14,7 @@ module Dcc
14
14
  autoload :Text, "dcc/v2/text"
15
15
  autoload :ByteData, "dcc/v2/byte_data"
16
16
  autoload :Formula, "dcc/v2/formula"
17
+ autoload :Mathml, "dcc/v2/mathml"
17
18
  autoload :RichContent, "dcc/v2/rich_content"
18
19
  autoload :XmlBlob, "dcc/v2/xml_blob"
19
20
  autoload :Comment, "dcc/v2/comment"
@@ -53,14 +54,15 @@ module Dcc
53
54
  autoload :MeasurementResult, "dcc/v2/measurement_result"
54
55
  autoload :MeasurementResultList, "dcc/v2/measurement_result_list"
55
56
  autoload :AdministrativeData, "dcc/v2/administrative_data"
56
- autoload :DigitalCalibrationCertificate, "dcc/v2/digital_calibration_certificate"
57
+ autoload :DigitalCalibrationCertificate,
58
+ "dcc/v2/digital_calibration_certificate"
57
59
 
58
60
  ROOT_ELEMENT_TAG = "digitalCalibrationCertificate"
59
61
 
60
62
  extend ::Dcc::VersionedParser
61
63
 
62
64
  ELEMENT_CLASSES = %i[
63
- StringWithLang Text ByteData Formula RichContent XmlBlob Comment
65
+ StringWithLang Text ByteData Mathml Formula RichContent XmlBlob Comment
64
66
  EquipmentClass Location Contact ContactNotStrict HashType
65
67
  Identification Identifications Software SoftwareList
66
68
  RefTypeDefinition RefTypeDefinitionList
@@ -4,5 +4,6 @@ module Dcc::V3
4
4
  class CalibrationLaboratory < CommonElements
5
5
  include ::Dcc::Base::CalibrationLaboratory
6
6
  end
7
- Configuration.register_model(CalibrationLaboratory, id: :calibrationLaboratory)
7
+ Configuration.register_model(CalibrationLaboratory,
8
+ id: :calibrationLaboratory)
8
9
  end
@@ -10,7 +10,7 @@ module Dcc
10
10
  # V3 DCC imports D-SI v2.x for quantity expressions. Returned as
11
11
  # instance method (becomes class method via `extend`).
12
12
  def fallback_contexts
13
- [:dsi_v2, :default]
13
+ %i[dsi_v2 default]
14
14
  end
15
15
  end
16
16
  end
@@ -4,5 +4,6 @@ module Dcc::V3
4
4
  class DigitalCalibrationCertificate < CommonElements
5
5
  include ::Dcc::Base::DigitalCalibrationCertificate
6
6
  end
7
- Configuration.register_model(DigitalCalibrationCertificate, id: :digitalCalibrationCertificate)
7
+ Configuration.register_model(DigitalCalibrationCertificate,
8
+ id: :digitalCalibrationCertificate)
8
9
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc::V3
4
+ class Mathml < CommonElements
5
+ include ::Dcc::Base::Mathml
6
+ end
7
+ Configuration.register_model(Mathml, id: :mathml)
8
+ end
@@ -4,5 +4,6 @@ module Dcc::V3
4
4
  class MeasurementMetaDataList < CommonElements
5
5
  include ::Dcc::Base::MeasurementMetaDataList
6
6
  end
7
- Configuration.register_model(MeasurementMetaDataList, id: :measurementMetaData)
7
+ Configuration.register_model(MeasurementMetaDataList,
8
+ id: :measurementMetaData)
8
9
  end
@@ -19,8 +19,10 @@ module Dcc::V3
19
19
  attribute :complex, ::Dcc::Si::V2::Complex, collection: true
20
20
  attribute :constant, ::Dcc::Si::V2::Constant, collection: true
21
21
  attribute :hybrid, ::Dcc::Si::V2::Hybrid, collection: true
22
- attribute :real_list_xml_list, ::Dcc::Si::V2::RealListXmlList, collection: true
23
- attribute :complex_list_xml_list, ::Dcc::Si::V2::ComplexListXmlList, collection: true
22
+ attribute :real_list_xml_list, ::Dcc::Si::V2::RealListXmlList,
23
+ collection: true
24
+ attribute :complex_list_xml_list, ::Dcc::Si::V2::ComplexListXmlList,
25
+ collection: true
24
26
  attribute :list, ::Dcc::Si::V2::SiList, collection: true
25
27
 
26
28
  xml do
data/lib/dcc/v3.rb CHANGED
@@ -14,6 +14,7 @@ module Dcc
14
14
  autoload :Text, "dcc/v3/text"
15
15
  autoload :ByteData, "dcc/v3/byte_data"
16
16
  autoload :Formula, "dcc/v3/formula"
17
+ autoload :Mathml, "dcc/v3/mathml"
17
18
  autoload :RichContent, "dcc/v3/rich_content"
18
19
  autoload :XmlBlob, "dcc/v3/xml_blob"
19
20
  autoload :Comment, "dcc/v3/comment"
@@ -53,7 +54,8 @@ module Dcc
53
54
  autoload :MeasurementResult, "dcc/v3/measurement_result"
54
55
  autoload :MeasurementResultList, "dcc/v3/measurement_result_list"
55
56
  autoload :AdministrativeData, "dcc/v3/administrative_data"
56
- autoload :DigitalCalibrationCertificate, "dcc/v3/digital_calibration_certificate"
57
+ autoload :DigitalCalibrationCertificate,
58
+ "dcc/v3/digital_calibration_certificate"
57
59
 
58
60
  ROOT_ELEMENT_TAG = "digitalCalibrationCertificate"
59
61
 
@@ -63,7 +65,7 @@ module Dcc
63
65
  # `Configuration.populate_context!` can register them. Iterating
64
66
  # `constants` triggers each autoload lazily.
65
67
  ELEMENT_CLASSES = %i[
66
- StringWithLang Text ByteData Formula RichContent XmlBlob Comment
68
+ StringWithLang Text ByteData Mathml Formula RichContent XmlBlob Comment
67
69
  EquipmentClass Location Contact ContactNotStrict HashType
68
70
  Identification Identifications Software SoftwareList
69
71
  RefTypeDefinition RefTypeDefinitionList
@@ -90,9 +92,17 @@ module Dcc
90
92
 
91
93
  # Re-export D-SI v2 type registrations into the DCC v3 context. Uses
92
94
  # only the public `register_model` API (no instance_variable access).
95
+ #
96
+ # Ids DCC already owns are skipped: `register_model` overwrites on
97
+ # duplicate, and both DCC and D-SI define a `list` element, so without this
98
+ # the D-SI one would displace `Dcc::V3::List` and every `dcc:list` would
99
+ # parse as an empty `si:list`.
93
100
  def self.register_dsi_types!
94
101
  ::Dcc::Si::V2.load_all!
102
+ own_ids = Configuration.registered_model_ids
95
103
  ::Dcc::Si::V2::Configuration.registered_model_ids.each do |id|
104
+ next if own_ids.include?(id)
105
+
96
106
  klass = ::Dcc::Si::V2::Configuration.registered_model_class(id)
97
107
  Configuration.register_model(klass, id: id)
98
108
  end
@@ -43,7 +43,9 @@ module Dcc
43
43
  end
44
44
 
45
45
  def code
46
- "dcc.business_rule.#{self.class.name.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}"
46
+ "dcc.business_rule.#{self.class.name.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(
47
+ /([a-z\d])([A-Z])/, '\1_\2'
48
+ ).downcase}"
47
49
  end
48
50
 
49
51
  # @param _dcc [Lutaml::Model::Serializable]
@@ -68,10 +70,12 @@ module Dcc
68
70
  # Require exactly one respPerson with mainSigner = true.
69
71
  class MainSignerSingle < Rule
70
72
  def check_on(dcc)
71
- return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
73
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc,
74
+ :administrative_data)
72
75
 
73
76
  admin = dcc.administrative_data
74
- return [] unless admin && Dcc::TypeGuards.has_attribute?(admin, :resp_persons) && admin.resp_persons
77
+ return [] unless admin && Dcc::TypeGuards.has_attribute?(admin,
78
+ :resp_persons) && admin.resp_persons
75
79
 
76
80
  resp_persons = Array(admin.resp_persons.resp_person)
77
81
  main_signers = resp_persons.select { |p| Dcc::TypeGuards.has_attribute?(p, :main_signer) && p.main_signer }
@@ -89,15 +93,20 @@ module Dcc
89
93
  # Require non-empty uniqueIdentifier.
90
94
  class UniqueIdentifierPresent < Rule
91
95
  def check_on(dcc)
92
- return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
96
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc,
97
+ :administrative_data)
93
98
 
94
99
  core = dcc.administrative_data&.core_data
95
- return [issue(severity: :error, message: "coreData is missing")] unless core
100
+ unless core
101
+ return [issue(severity: :error,
102
+ message: "coreData is missing")]
103
+ end
96
104
 
97
105
  id = core.unique_identifier
98
106
  return [] if id && !id.to_s.empty?
99
107
 
100
- [issue(severity: :error, message: "uniqueIdentifier is missing or empty")]
108
+ [issue(severity: :error,
109
+ message: "uniqueIdentifier is missing or empty")]
101
110
  end
102
111
  end
103
112
 
@@ -108,14 +117,19 @@ module Dcc
108
117
  # @param dcc [Lutaml::Model::Serializable]
109
118
  # @return [Dcc::Validate::BusinessRules::Result]
110
119
  def call(dcc)
111
- issues = Registry.all.flat_map { |rule_class| rule_class.new.check_on(dcc) }
120
+ issues = Registry.all.flat_map do |rule_class|
121
+ rule_class.new.check_on(dcc)
122
+ end
112
123
  Result.new(
113
124
  issues: issues,
114
- schema_version: Dcc::TypeGuards.has_attribute?(dcc, :schema_version) ? dcc.schema_version.to_s : nil,
125
+ schema_version: if Dcc::TypeGuards.has_attribute?(dcc,
126
+ :schema_version)
127
+ dcc.schema_version.to_s
128
+ end,
115
129
  source: "business_rule",
116
130
  )
117
131
  end
118
132
  end
119
133
  end
120
134
  end
121
- end
135
+ end
@@ -24,7 +24,8 @@ module Dcc
24
24
  # @param column [Integer, nil] XML column number if known.
25
25
  # @param path [String, nil] XPath / element path if known.
26
26
  # @param source [String, nil] validator name (e.g. "xsd", "schematron").
27
- def self.build(severity:, message:, code: nil, line: nil, column: nil, path: nil, source: nil)
27
+ def self.build(severity:, message:, code: nil, line: nil, column: nil,
28
+ path: nil, source: nil)
28
29
  new(
29
30
  severity: ::Dcc::Validate::Severity.normalize(severity),
30
31
  message: message,
@@ -58,12 +58,12 @@ module Dcc
58
58
 
59
59
  def to_s
60
60
  if ok?
61
- "OK: no errors found#{schema_version ? " (schemaVersion #{schema_version})" : ''}"
61
+ "OK: no errors found#{" (schemaVersion #{schema_version})" if schema_version}"
62
62
  else
63
63
  header = "#{errors.size} error(s), #{warnings.size} warning(s)"
64
64
  header += " (schemaVersion #{schema_version})" if schema_version
65
- body = errors.map(&:to_s).unshift(header).join("\n")
66
- body
65
+ errors.map(&:to_s).unshift(header).join("\n")
66
+
67
67
  end
68
68
  end
69
69
 
@@ -97,7 +97,9 @@ module Dcc
97
97
  ok: ok?,
98
98
  source: source,
99
99
  schema_version: schema_version,
100
- issues: issues.map { |i| [i.severity.to_s, i.message, i.line, i.path] },
100
+ issues: issues.map do |i|
101
+ [i.severity.to_s, i.message, i.line, i.path]
102
+ end,
101
103
  }.to_yaml
102
104
  end
103
105
  end