dcc 0.2.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.
Files changed (336) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +16 -0
  5. data/.rubocop_todo.yml +10 -0
  6. data/CHANGELOG.adoc +54 -0
  7. data/CONTRIBUTING.adoc +64 -0
  8. data/Gemfile +25 -0
  9. data/LICENSE +21 -0
  10. data/README.adoc +69 -0
  11. data/Rakefile +13 -0
  12. data/dcc.gemspec +41 -0
  13. data/docs/cli-reference.adoc +67 -0
  14. data/docs/getting-started.adoc +117 -0
  15. data/docs/schema-versions.adoc +65 -0
  16. data/examples/build_minimal_dcc.rb +23 -0
  17. data/examples/convert_all_formats.rb +19 -0
  18. data/examples/parse_and_inspect.rb +19 -0
  19. data/examples/quantity_math_demo.rb +32 -0
  20. data/examples/validate_full.rb +27 -0
  21. data/exe/dcc +7 -0
  22. data/lib/dcc/base/administrative_data.rb +43 -0
  23. data/lib/dcc/base/byte_data.rb +36 -0
  24. data/lib/dcc/base/calibration_laboratory.rb +29 -0
  25. data/lib/dcc/base/comment.rb +23 -0
  26. data/lib/dcc/base/condition.rb +34 -0
  27. data/lib/dcc/base/contact.rb +38 -0
  28. data/lib/dcc/base/contact_not_strict.rb +38 -0
  29. data/lib/dcc/base/core_data.rb +44 -0
  30. data/lib/dcc/base/data.rb +42 -0
  31. data/lib/dcc/base/digital_calibration_certificate.rb +32 -0
  32. data/lib/dcc/base/equipment_class.rb +24 -0
  33. data/lib/dcc/base/formula.rb +33 -0
  34. data/lib/dcc/base/hash_type.rb +34 -0
  35. data/lib/dcc/base/identification.rb +27 -0
  36. data/lib/dcc/base/identifications.rb +27 -0
  37. data/lib/dcc/base/influence_condition.rb +16 -0
  38. data/lib/dcc/base/influence_condition_list.rb +40 -0
  39. data/lib/dcc/base/item.rb +38 -0
  40. data/lib/dcc/base/item_list.rb +38 -0
  41. data/lib/dcc/base/list.rb +44 -0
  42. data/lib/dcc/base/location.rb +36 -0
  43. data/lib/dcc/base/measurement_meta_data.rb +15 -0
  44. data/lib/dcc/base/measurement_meta_data_list.rb +27 -0
  45. data/lib/dcc/base/measurement_result.rb +41 -0
  46. data/lib/dcc/base/measurement_result_list.rb +28 -0
  47. data/lib/dcc/base/measuring_equipment.rb +41 -0
  48. data/lib/dcc/base/measuring_equipment_list.rb +38 -0
  49. data/lib/dcc/base/quantity.rb +61 -0
  50. data/lib/dcc/base/ref_type_definition.rb +36 -0
  51. data/lib/dcc/base/ref_type_definition_list.rb +21 -0
  52. data/lib/dcc/base/resp_person.rb +38 -0
  53. data/lib/dcc/base/resp_person_list.rb +27 -0
  54. data/lib/dcc/base/result.rb +31 -0
  55. data/lib/dcc/base/result_list.rb +27 -0
  56. data/lib/dcc/base/rich_content.rb +34 -0
  57. data/lib/dcc/base/software.rb +35 -0
  58. data/lib/dcc/base/software_list.rb +27 -0
  59. data/lib/dcc/base/statement.rb +50 -0
  60. data/lib/dcc/base/statement_list.rb +27 -0
  61. data/lib/dcc/base/string_with_lang.rb +24 -0
  62. data/lib/dcc/base/text.rb +33 -0
  63. data/lib/dcc/base/used_method.rb +31 -0
  64. data/lib/dcc/base/used_method_list.rb +27 -0
  65. data/lib/dcc/base/xml_blob.rb +20 -0
  66. data/lib/dcc/base.rb +58 -0
  67. data/lib/dcc/builder/dsl.rb +10 -0
  68. data/lib/dcc/builder/session.rb +170 -0
  69. data/lib/dcc/builder.rb +34 -0
  70. data/lib/dcc/cli/cli.rb +149 -0
  71. data/lib/dcc/cli/formatters.rb +77 -0
  72. data/lib/dcc/cli.rb +7 -0
  73. data/lib/dcc/common_elements.rb +20 -0
  74. data/lib/dcc/context_configuration.rb +167 -0
  75. data/lib/dcc/context_options.rb +47 -0
  76. data/lib/dcc/convert/csv.rb +129 -0
  77. data/lib/dcc/convert/html.rb +127 -0
  78. data/lib/dcc/convert/json.rb +62 -0
  79. data/lib/dcc/convert/result.rb +51 -0
  80. data/lib/dcc/convert/yaml.rb +21 -0
  81. data/lib/dcc/convert.rb +14 -0
  82. data/lib/dcc/diff/change.rb +21 -0
  83. data/lib/dcc/diff/result.rb +58 -0
  84. data/lib/dcc/diff.rb +83 -0
  85. data/lib/dcc/error.rb +54 -0
  86. data/lib/dcc/extract/file.rb +143 -0
  87. data/lib/dcc/extract/ring.rb +28 -0
  88. data/lib/dcc/extract.rb +9 -0
  89. data/lib/dcc/i18n/text_lookup.rb +67 -0
  90. data/lib/dcc/i18n.rb +12 -0
  91. data/lib/dcc/inspect/report.rb +139 -0
  92. data/lib/dcc/inspect.rb +9 -0
  93. data/lib/dcc/migrate.rb +41 -0
  94. data/lib/dcc/namespace/dcc.rb +30 -0
  95. data/lib/dcc/namespace/dsig.rb +15 -0
  96. data/lib/dcc/namespace/math_ml.rb +14 -0
  97. data/lib/dcc/namespace/qudt.rb +15 -0
  98. data/lib/dcc/namespace/si.rb +26 -0
  99. data/lib/dcc/namespace.rb +18 -0
  100. data/lib/dcc/plugin/registry.rb +45 -0
  101. data/lib/dcc/plugin.rb +42 -0
  102. data/lib/dcc/quantity_format/formatter.rb +90 -0
  103. data/lib/dcc/quantity_format.rb +10 -0
  104. data/lib/dcc/quantity_math/quantity.rb +46 -0
  105. data/lib/dcc/quantity_math/real.rb +116 -0
  106. data/lib/dcc/quantity_math.rb +14 -0
  107. data/lib/dcc/schema/resources/dcc/dsi/v1.0.1.xsd +415 -0
  108. data/lib/dcc/schema/resources/dcc/dsi/v1.3.0.xsd +814 -0
  109. data/lib/dcc/schema/resources/dcc/dsi/v1.3.1.xsd +814 -0
  110. data/lib/dcc/schema/resources/dcc/dsi/v2.0.0.xsd +869 -0
  111. data/lib/dcc/schema/resources/dcc/dsi/v2.1.0.xsd +1031 -0
  112. data/lib/dcc/schema/resources/dcc/dsi/v2.2.1.xsd +1574 -0
  113. data/lib/dcc/schema/resources/dcc/qudt/v2.2.1.xsd +44 -0
  114. data/lib/dcc/schema/resources/dcc/v2.1.0/dcc.xsd +650 -0
  115. data/lib/dcc/schema/resources/dcc/v2.1.1/dcc.xsd +669 -0
  116. data/lib/dcc/schema/resources/dcc/v2.2.0/dcc.xsd +730 -0
  117. data/lib/dcc/schema/resources/dcc/v2.3.0/dcc.xsd +708 -0
  118. data/lib/dcc/schema/resources/dcc/v2.4.0/dcc.xsd +725 -0
  119. data/lib/dcc/schema/resources/dcc/v3.0.0/dcc.xsd +749 -0
  120. data/lib/dcc/schema/resources/dcc/v3.1.0/dcc.xsd +843 -0
  121. data/lib/dcc/schema/resources/dcc/v3.1.1/dcc.xsd +843 -0
  122. data/lib/dcc/schema/resources/dcc/v3.1.2/dcc.xsd +844 -0
  123. data/lib/dcc/schema/resources/dcc/v3.2.0/dcc.xsd +940 -0
  124. data/lib/dcc/schema/resources/dcc/v3.2.1/dcc.xsd +963 -0
  125. data/lib/dcc/schema/resources/dcc/v3.3.0/dcc.xsd +1008 -0
  126. data/lib/dcc/schema/resources/dcc/xmldsig-core-schema.xsd +312 -0
  127. data/lib/dcc/schema/resources/dsi/qudt/v2.2.1.xsd +44 -0
  128. data/lib/dcc/schema/resources/dsi/v1.0.1/SI_Format.xsd +415 -0
  129. data/lib/dcc/schema/resources/dsi/v1.3.0/SI_Format.xsd +814 -0
  130. data/lib/dcc/schema/resources/dsi/v1.3.1/SI_Format.xsd +814 -0
  131. data/lib/dcc/schema/resources/dsi/v2.0.0/SI_Format.xsd +869 -0
  132. data/lib/dcc/schema/resources/dsi/v2.1.0/SI_Format.xsd +1031 -0
  133. data/lib/dcc/schema/resources/dsi/v2.2.1/SI_Format.xsd +1574 -0
  134. data/lib/dcc/schema/resources/qudt/qudt.xsd +44 -0
  135. data/lib/dcc/schema/resources/schematron/dcc.sch +523 -0
  136. data/lib/dcc/schema/resources/schematron/dcc.svrl +2302 -0
  137. data/lib/dcc/schema/resources/xmldsig/xmldsig-core-schema.xsd +312 -0
  138. data/lib/dcc/schema/version.rb +94 -0
  139. data/lib/dcc/schema.rb +35 -0
  140. data/lib/dcc/server/app.rb +133 -0
  141. data/lib/dcc/server/storage/entry.rb +15 -0
  142. data/lib/dcc/server/storage/memory.rb +57 -0
  143. data/lib/dcc/server/storage.rb +13 -0
  144. data/lib/dcc/server.rb +33 -0
  145. data/lib/dcc/si/base/complex.rb +43 -0
  146. data/lib/dcc/si/base/complex_list_xml_list.rb +39 -0
  147. data/lib/dcc/si/base/constant.rb +39 -0
  148. data/lib/dcc/si/base/coverage_interval_mu.rb +31 -0
  149. data/lib/dcc/si/base/expanded_mu.rb +29 -0
  150. data/lib/dcc/si/base/expanded_unc_xml_list.rb +30 -0
  151. data/lib/dcc/si/base/hybrid.rb +42 -0
  152. data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +28 -0
  153. data/lib/dcc/si/base/real.rb +48 -0
  154. data/lib/dcc/si/base/real_list_xml_list.rb +45 -0
  155. data/lib/dcc/si/base/si_list.rb +37 -0
  156. data/lib/dcc/si/base/standard_mu.rb +25 -0
  157. data/lib/dcc/si/base.rb +24 -0
  158. data/lib/dcc/si/common_elements.rb +13 -0
  159. data/lib/dcc/si/namespace.rb +7 -0
  160. data/lib/dcc/si/v1/common_elements.rb +13 -0
  161. data/lib/dcc/si/v1/complex.rb +8 -0
  162. data/lib/dcc/si/v1/complex_list_xml_list.rb +8 -0
  163. data/lib/dcc/si/v1/configuration.rb +13 -0
  164. data/lib/dcc/si/v1/constant.rb +8 -0
  165. data/lib/dcc/si/v1/coverage_interval_mu.rb +8 -0
  166. data/lib/dcc/si/v1/expanded_mu.rb +8 -0
  167. data/lib/dcc/si/v1/expanded_unc.rb +23 -0
  168. data/lib/dcc/si/v1/expanded_unc_xml_list.rb +8 -0
  169. data/lib/dcc/si/v1/hybrid.rb +8 -0
  170. data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +8 -0
  171. data/lib/dcc/si/v1/namespace.rb +9 -0
  172. data/lib/dcc/si/v1/real.rb +8 -0
  173. data/lib/dcc/si/v1/real_list_xml_list.rb +8 -0
  174. data/lib/dcc/si/v1/si_list.rb +8 -0
  175. data/lib/dcc/si/v1/standard_mu.rb +8 -0
  176. data/lib/dcc/si/v1.rb +46 -0
  177. data/lib/dcc/si/v2/common_elements.rb +13 -0
  178. data/lib/dcc/si/v2/complex.rb +8 -0
  179. data/lib/dcc/si/v2/complex_list_xml_list.rb +8 -0
  180. data/lib/dcc/si/v2/configuration.rb +13 -0
  181. data/lib/dcc/si/v2/constant.rb +8 -0
  182. data/lib/dcc/si/v2/coverage_interval_mu.rb +8 -0
  183. data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +24 -0
  184. data/lib/dcc/si/v2/expanded_mu.rb +8 -0
  185. data/lib/dcc/si/v2/expanded_mu_xml_list.rb +22 -0
  186. data/lib/dcc/si/v2/expanded_unc_xml_list.rb +8 -0
  187. data/lib/dcc/si/v2/hybrid.rb +8 -0
  188. data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +8 -0
  189. data/lib/dcc/si/v2/namespace.rb +9 -0
  190. data/lib/dcc/si/v2/real.rb +8 -0
  191. data/lib/dcc/si/v2/real_list_xml_list.rb +8 -0
  192. data/lib/dcc/si/v2/si_list.rb +8 -0
  193. data/lib/dcc/si/v2/standard_mu.rb +8 -0
  194. data/lib/dcc/si/v2/standard_mu_xml_list.rb +18 -0
  195. data/lib/dcc/si/v2.rb +49 -0
  196. data/lib/dcc/si.rb +34 -0
  197. data/lib/dcc/signature/result.rb +43 -0
  198. data/lib/dcc/signature/signer.rb +36 -0
  199. data/lib/dcc/signature/verifier.rb +41 -0
  200. data/lib/dcc/signature.rb +13 -0
  201. data/lib/dcc/transform/result.rb +24 -0
  202. data/lib/dcc/transform/xslt.rb +72 -0
  203. data/lib/dcc/transform.rb +12 -0
  204. data/lib/dcc/type/base64_binary.rb +55 -0
  205. data/lib/dcc/type/decimal_xml_list.rb +47 -0
  206. data/lib/dcc/type/iso_country_code.rb +23 -0
  207. data/lib/dcc/type/iso_language_code.rb +23 -0
  208. data/lib/dcc/type/schema_version.rb +37 -0
  209. data/lib/dcc/type/si_unit.rb +26 -0
  210. data/lib/dcc/type.rb +16 -0
  211. data/lib/dcc/type_guards.rb +140 -0
  212. data/lib/dcc/v2/administrative_data.rb +8 -0
  213. data/lib/dcc/v2/byte_data.rb +8 -0
  214. data/lib/dcc/v2/calibration_laboratory.rb +8 -0
  215. data/lib/dcc/v2/comment.rb +8 -0
  216. data/lib/dcc/v2/common_elements.rb +13 -0
  217. data/lib/dcc/v2/condition.rb +8 -0
  218. data/lib/dcc/v2/configuration.rb +17 -0
  219. data/lib/dcc/v2/contact.rb +8 -0
  220. data/lib/dcc/v2/contact_not_strict.rb +8 -0
  221. data/lib/dcc/v2/core_data.rb +8 -0
  222. data/lib/dcc/v2/data.rb +8 -0
  223. data/lib/dcc/v2/digital_calibration_certificate.rb +8 -0
  224. data/lib/dcc/v2/equipment_class.rb +8 -0
  225. data/lib/dcc/v2/formula.rb +8 -0
  226. data/lib/dcc/v2/hash_type.rb +8 -0
  227. data/lib/dcc/v2/identification.rb +8 -0
  228. data/lib/dcc/v2/identifications.rb +8 -0
  229. data/lib/dcc/v2/influence_condition.rb +7 -0
  230. data/lib/dcc/v2/influence_condition_list.rb +8 -0
  231. data/lib/dcc/v2/item.rb +8 -0
  232. data/lib/dcc/v2/item_list.rb +8 -0
  233. data/lib/dcc/v2/list.rb +8 -0
  234. data/lib/dcc/v2/location.rb +8 -0
  235. data/lib/dcc/v2/measurement_meta_data.rb +8 -0
  236. data/lib/dcc/v2/measurement_meta_data_list.rb +8 -0
  237. data/lib/dcc/v2/measurement_result.rb +8 -0
  238. data/lib/dcc/v2/measurement_result_list.rb +8 -0
  239. data/lib/dcc/v2/measuring_equipment.rb +8 -0
  240. data/lib/dcc/v2/measuring_equipment_list.rb +8 -0
  241. data/lib/dcc/v2/namespace.rb +8 -0
  242. data/lib/dcc/v2/quantity.rb +49 -0
  243. data/lib/dcc/v2/ref_type_definition.rb +11 -0
  244. data/lib/dcc/v2/ref_type_definition_list.rb +15 -0
  245. data/lib/dcc/v2/resp_person.rb +8 -0
  246. data/lib/dcc/v2/resp_person_list.rb +8 -0
  247. data/lib/dcc/v2/result.rb +8 -0
  248. data/lib/dcc/v2/result_list.rb +8 -0
  249. data/lib/dcc/v2/rich_content.rb +12 -0
  250. data/lib/dcc/v2/software.rb +8 -0
  251. data/lib/dcc/v2/software_list.rb +8 -0
  252. data/lib/dcc/v2/statement.rb +8 -0
  253. data/lib/dcc/v2/statement_list.rb +8 -0
  254. data/lib/dcc/v2/string_with_lang.rb +8 -0
  255. data/lib/dcc/v2/text.rb +8 -0
  256. data/lib/dcc/v2/used_method.rb +8 -0
  257. data/lib/dcc/v2/used_method_list.rb +8 -0
  258. data/lib/dcc/v2/xml_blob.rb +8 -0
  259. data/lib/dcc/v2.rb +84 -0
  260. data/lib/dcc/v3/administrative_data.rb +8 -0
  261. data/lib/dcc/v3/byte_data.rb +8 -0
  262. data/lib/dcc/v3/calibration_laboratory.rb +8 -0
  263. data/lib/dcc/v3/comment.rb +8 -0
  264. data/lib/dcc/v3/common_elements.rb +11 -0
  265. data/lib/dcc/v3/condition.rb +8 -0
  266. data/lib/dcc/v3/configuration.rb +17 -0
  267. data/lib/dcc/v3/contact.rb +8 -0
  268. data/lib/dcc/v3/contact_not_strict.rb +8 -0
  269. data/lib/dcc/v3/core_data.rb +8 -0
  270. data/lib/dcc/v3/data.rb +8 -0
  271. data/lib/dcc/v3/digital_calibration_certificate.rb +8 -0
  272. data/lib/dcc/v3/equipment_class.rb +8 -0
  273. data/lib/dcc/v3/formula.rb +8 -0
  274. data/lib/dcc/v3/hash_type.rb +8 -0
  275. data/lib/dcc/v3/identification.rb +8 -0
  276. data/lib/dcc/v3/identifications.rb +8 -0
  277. data/lib/dcc/v3/influence_condition.rb +7 -0
  278. data/lib/dcc/v3/influence_condition_list.rb +8 -0
  279. data/lib/dcc/v3/item.rb +8 -0
  280. data/lib/dcc/v3/item_list.rb +8 -0
  281. data/lib/dcc/v3/list.rb +8 -0
  282. data/lib/dcc/v3/location.rb +8 -0
  283. data/lib/dcc/v3/measurement_meta_data.rb +8 -0
  284. data/lib/dcc/v3/measurement_meta_data_list.rb +8 -0
  285. data/lib/dcc/v3/measurement_result.rb +8 -0
  286. data/lib/dcc/v3/measurement_result_list.rb +8 -0
  287. data/lib/dcc/v3/measuring_equipment.rb +8 -0
  288. data/lib/dcc/v3/measuring_equipment_list.rb +8 -0
  289. data/lib/dcc/v3/namespace.rb +7 -0
  290. data/lib/dcc/v3/quantity.rb +49 -0
  291. data/lib/dcc/v3/ref_type_definition.rb +8 -0
  292. data/lib/dcc/v3/ref_type_definition_list.rb +8 -0
  293. data/lib/dcc/v3/resp_person.rb +8 -0
  294. data/lib/dcc/v3/resp_person_list.rb +8 -0
  295. data/lib/dcc/v3/result.rb +8 -0
  296. data/lib/dcc/v3/result_list.rb +8 -0
  297. data/lib/dcc/v3/rich_content.rb +8 -0
  298. data/lib/dcc/v3/software.rb +8 -0
  299. data/lib/dcc/v3/software_list.rb +8 -0
  300. data/lib/dcc/v3/statement.rb +8 -0
  301. data/lib/dcc/v3/statement_list.rb +8 -0
  302. data/lib/dcc/v3/string_with_lang.rb +8 -0
  303. data/lib/dcc/v3/text.rb +8 -0
  304. data/lib/dcc/v3/used_method.rb +8 -0
  305. data/lib/dcc/v3/used_method_list.rb +8 -0
  306. data/lib/dcc/v3/xml_blob.rb +8 -0
  307. data/lib/dcc/v3.rb +111 -0
  308. data/lib/dcc/validate/business_rules.rb +121 -0
  309. data/lib/dcc/validate/issue.rb +56 -0
  310. data/lib/dcc/validate/result.rb +105 -0
  311. data/lib/dcc/validate/schematron/profile.rb +64 -0
  312. data/lib/dcc/validate/schematron/rule.rb +49 -0
  313. data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +42 -0
  314. data/lib/dcc/validate/schematron/rules/base.rb +15 -0
  315. data/lib/dcc/validate/schematron/rules/date_range_check.rb +41 -0
  316. data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +61 -0
  317. data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +58 -0
  318. data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +53 -0
  319. data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +39 -0
  320. data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +82 -0
  321. data/lib/dcc/validate/schematron/rules/release_format_check.rb +44 -0
  322. data/lib/dcc/validate/schematron/rules/schema_version_check.rb +31 -0
  323. data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +58 -0
  324. data/lib/dcc/validate/schematron/rules/unit_format_check.rb +74 -0
  325. data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +65 -0
  326. data/lib/dcc/validate/schematron/rules/used_software_placement.rb +43 -0
  327. data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +42 -0
  328. data/lib/dcc/validate/schematron/rules.rb +30 -0
  329. data/lib/dcc/validate/schematron.rb +22 -0
  330. data/lib/dcc/validate/severity.rb +39 -0
  331. data/lib/dcc/validate/xsd.rb +97 -0
  332. data/lib/dcc/validate.rb +15 -0
  333. data/lib/dcc/version.rb +5 -0
  334. data/lib/dcc/versioned_parser.rb +48 -0
  335. data/lib/dcc.rb +141 -0
  336. metadata +425 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Dcc
6
+ module Validate
7
+ module Schematron
8
+ # Base class for Schematron rules. Subclasses implement `#check_on(dcc)`
9
+ # returning an array of `Dcc::Validate::Issue` records.
10
+ class Rule
11
+ # @return [Symbol] severity for issues this rule produces.
12
+ def severity
13
+ ::Dcc::Validate::Severity::ERROR
14
+ end
15
+
16
+ # @return [String] rule code used in `Issue#code`.
17
+ def code
18
+ "dcc.schematron.#{self.class.name.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}"
19
+ end
20
+
21
+ # @param dcc [Lutaml::Model::Serializable]
22
+ # @return [Array<Dcc::Validate::Issue>]
23
+ def check_on(dcc)
24
+ issues = []
25
+ walk(dcc, issues)
26
+ issues
27
+ end
28
+
29
+ protected
30
+
31
+ def walk(_node, _issues)
32
+ # Override in subclasses to traverse the model tree.
33
+ end
34
+
35
+ def issue(severity:, message:, line: nil, column: nil, path: nil, source: "schematron")
36
+ ::Dcc::Validate::Issue.build(
37
+ severity: severity,
38
+ message: message,
39
+ code: code,
40
+ line: line,
41
+ column: column,
42
+ path: path,
43
+ source: source,
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Validate
5
+ module Schematron
6
+ module Rules
7
+ # Validates that all required sections are present in
8
+ # `dcc:administrativeData`: dccSoftware, coreData, items,
9
+ # calibrationLaboratory, respPersons, customer.
10
+ class AdministrativeDataCompleteness < Base
11
+ REQUIRED_SECTIONS = {
12
+ dcc_software: "dccSoftware",
13
+ core_data: "coreData",
14
+ items: "items",
15
+ calibration_laboratory: "calibrationLaboratory",
16
+ resp_persons: "respPersons",
17
+ customer: "customer",
18
+ }.freeze
19
+
20
+ def check_on(dcc)
21
+ issues = []
22
+ return issues unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
23
+
24
+ admin = dcc.administrative_data
25
+ return [issue(severity: :error, message: "administrativeData is missing")] unless admin
26
+
27
+ REQUIRED_SECTIONS.each do |attr, label|
28
+ value = Dcc::TypeGuards.has_attribute?(admin, attr) ? admin.public_send(attr) : nil
29
+ next unless value.nil? || ((value.is_a?(::String) || value.is_a?(::Array)) && value.empty?)
30
+
31
+ issues << issue(
32
+ severity: :error,
33
+ message: "dcc:administrativeData/#{label} is missing",
34
+ )
35
+ end
36
+ issues
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Schematron rule base. Concrete rules subclass this and implement
9
+ # `#check_on(dcc)`. Each subclass declares its `severity`.
10
+ class Base < ::Dcc::Validate::Schematron::Rule
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Errors if `endPerformanceDate` precedes `beginPerformanceDate`.
9
+ class DateRangeCheck < Base
10
+ def check_on(dcc)
11
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
12
+
13
+ core = safe_attr(dcc.administrative_data, :core_data)
14
+ return [] if core.nil?
15
+
16
+ begin_d = Dcc::TypeGuards.has_attribute?(core, :begin_performance_date) ? core.begin_performance_date : nil
17
+ end_d = Dcc::TypeGuards.has_attribute?(core, :end_performance_date) ? core.end_performance_date : nil
18
+
19
+ return [] if begin_d.nil? || end_d.nil?
20
+ return [] unless end_d < begin_d
21
+
22
+ [
23
+ issue(
24
+ severity: :error,
25
+ message: "endPerformanceDate (#{end_d}) precedes beginPerformanceDate (#{begin_d})",
26
+ ),
27
+ ]
28
+ end
29
+
30
+ private
31
+
32
+ def safe_attr(parent, attr)
33
+ return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
34
+
35
+ parent.public_send(attr)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Validates that every `@id` on a DCC element has a matching `@refId`
9
+ # reference and vice versa.
10
+ class IdRefIdLinking < Base
11
+ def check_on(dcc)
12
+ issues = []
13
+ ids = ::Set.new
14
+ ref_ids = ::Set.new
15
+
16
+ collect(dcc, ids, ref_ids)
17
+
18
+ unused_ids = ids - ref_ids
19
+ unused_ids.each do |id|
20
+ issues << issue(
21
+ severity: :warning,
22
+ message: "@id '#{id}' is never referenced by any @refId",
23
+ )
24
+ end
25
+
26
+ dangling = ref_ids - ids
27
+ dangling.each do |rid|
28
+ issues << issue(
29
+ severity: :error,
30
+ message: "@refId '#{rid}' does not match any @id",
31
+ )
32
+ end
33
+
34
+ issues
35
+ end
36
+
37
+ private
38
+
39
+ def collect(node, ids, ref_ids)
40
+ return unless node.is_a?(::Lutaml::Model::Serializable)
41
+
42
+ id = node.respond_to?(:id) ? node.id : nil
43
+ ids << id if id && !id.empty?
44
+
45
+ ref_id = node.respond_to?(:ref_id) ? node.ref_id : nil
46
+ if ref_id && !ref_id.empty?
47
+ ref_id.split(/\s+/).each { |r| ref_ids << r }
48
+ end
49
+
50
+ node.class.attributes.each_key do |attr|
51
+ value = node.public_send(attr)
52
+ Array(value).each { |c| collect(c, ids, ref_ids) }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ require "set"
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # `dcc:influenceConditions` must appear somewhere (global, list, or
9
+ # quantity level). Error if missing.
10
+ class InfluenceConditionsPlacement < Base
11
+ def check_on(dcc)
12
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results)
13
+
14
+ mr_list = safe_attr(dcc.measurement_results, :measurement_result)
15
+ return [] if mr_list.empty?
16
+
17
+ any_present = mr_list.any? do |mr|
18
+ next false unless Dcc::TypeGuards.has_attribute?(mr, :influence_conditions)
19
+ next true unless mr.influence_conditions.nil?
20
+
21
+ Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results &&
22
+ has_in_descendants?(mr.results)
23
+ end
24
+
25
+ any_present ? [] : [
26
+ issue(
27
+ severity: :error,
28
+ message: "dcc:influenceConditions is missing everywhere",
29
+ ),
30
+ ]
31
+ end
32
+
33
+ private
34
+
35
+ def has_in_descendants?(node)
36
+ return false unless node.is_a?(::Lutaml::Model::Serializable)
37
+
38
+ if Dcc::TypeGuards.has_attribute?(node, :influence_conditions) && !node.influence_conditions.nil?
39
+ return true
40
+ end
41
+
42
+ node.class.attributes.each_key do |attr|
43
+ value = node.public_send(attr)
44
+ Array(value).any? { |c| has_in_descendants?(c) } if value.is_a?(::Array) || value.is_a?(::Lutaml::Model::Serializable)
45
+ end
46
+ false
47
+ end
48
+
49
+ def safe_attr(parent, attr)
50
+ return [] unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
51
+
52
+ Array(parent.public_send(attr))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Validates ISO 3166-1 (country) and ISO 639-1 (language) codes used
9
+ # in coreData. Custom type casts already enforce format; here we only
10
+ # flag empties that escaped earlier casts.
11
+ class IsoCodeValidation < Base
12
+ def check_on(dcc)
13
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
14
+
15
+ core = safe_attr(dcc.administrative_data, :core_data)
16
+ return [] if core.nil?
17
+
18
+ issues = []
19
+ country = Dcc::TypeGuards.has_attribute?(core, :country_code_iso_3166_1) ? core.country_code_iso_3166_1 : nil
20
+ if country.nil? || country.to_s.empty?
21
+ issues << issue(
22
+ severity: :error,
23
+ message: "dcc:countryCodeISO3166_1 is missing",
24
+ )
25
+ end
26
+
27
+ used = Dcc::TypeGuards.has_attribute?(core, :used_lang_code_iso_639_1) ? Array(core.used_lang_code_iso_639_1) : []
28
+ issues << issue(
29
+ severity: :error,
30
+ message: "dcc:usedLangCodeISO639_1 must have at least one entry",
31
+ ) if used.empty?
32
+
33
+ mandatory = Dcc::TypeGuards.has_attribute?(core, :mandatory_lang_code_iso_639_1) ? Array(core.mandatory_lang_code_iso_639_1) : []
34
+ issues << issue(
35
+ severity: :error,
36
+ message: "dcc:mandatoryLangCodeISO639_1 must have at least one entry",
37
+ ) if mandatory.empty?
38
+
39
+ issues
40
+ end
41
+
42
+ private
43
+
44
+ def safe_attr(parent, attr)
45
+ return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
46
+
47
+ parent.public_send(attr)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Errors on duplicate language codes in `dcc:usedLangCodeISO639_1`.
9
+ class LanguageCodeDedup < Base
10
+ def check_on(dcc)
11
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
12
+
13
+ core = safe_attr(dcc.administrative_data, :core_data)
14
+ return [] if core.nil?
15
+
16
+ used = Dcc::TypeGuards.has_attribute?(core, :used_lang_code_iso_639_1) ? Array(core.used_lang_code_iso_639_1) : []
17
+ used_strings = used.map(&:to_s)
18
+ duplicates = used_strings.group_by(&:itself).select { |_k, v| v.size > 1 }.keys
19
+
20
+ duplicates.map do |dup|
21
+ issue(
22
+ severity: :error,
23
+ message: "dcc:usedLangCodeISO639_1 contains duplicate '#{dup}'",
24
+ )
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def safe_attr(parent, attr)
31
+ return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
32
+
33
+ parent.public_send(attr)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Validate
5
+ module Schematron
6
+ module Rules
7
+ # Validates that non-SI units (prefixed with `|`) are declared
8
+ # somewhere in the DCC via `dcc:nonSIUnit` and `dcc:nonSIDefinition`
9
+ # elements inside `dcc:statement`.
10
+ class NonSiDeclaration < Base
11
+ def check_on(dcc)
12
+ issues = []
13
+ return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
14
+
15
+ declared_units = collect_declared_non_si_units(dcc, ::Set.new)
16
+ used_units = ::Set.new
17
+ walk_for_used_units(dcc, used_units, ::Set.new)
18
+
19
+ (used_units - declared_units).each do |unit|
20
+ issues << issue(
21
+ severity: :error,
22
+ message: "non-SI unit '#{unit}' is used but not declared in dcc:nonSIUnit",
23
+ )
24
+ end
25
+ issues
26
+ end
27
+
28
+ private
29
+
30
+ def collect_declared_non_si_units(node, visited)
31
+ return [].to_set unless node.is_a?(::Lutaml::Model::Serializable)
32
+ return [].to_set if visited.include?(node.object_id)
33
+
34
+ visited << node.object_id
35
+ declared = collect_from_node(node)
36
+ node.class.attributes.each_key do |attr_name|
37
+ value = node.public_send(attr_name)
38
+ Array(value).each do |child|
39
+ declared += collect_declared_non_si_units(child, visited) if child.is_a?(::Lutaml::Model::Serializable)
40
+ end
41
+ end
42
+ declared
43
+ end
44
+
45
+ def collect_from_node(node)
46
+ return [].to_set unless node.respond_to?(:non_si_unit)
47
+
48
+ u = node.non_si_unit
49
+ u.to_s.empty? ? [].to_set : ::Set.new([u.to_s])
50
+ end
51
+
52
+ def walk_for_used_units(node, accumulator, visited)
53
+ return unless node.is_a?(::Lutaml::Model::Serializable)
54
+ return if visited.include?(node.object_id)
55
+
56
+ visited << node.object_id
57
+ extract_non_si_unit(node, accumulator)
58
+ node.class.attributes.each_key do |attr_name|
59
+ value = node.public_send(attr_name)
60
+ Array(value).each { |child| walk_for_used_units(child, accumulator, visited) }
61
+ end
62
+ end
63
+
64
+ def extract_non_si_unit(node, accumulator)
65
+ %i[unit unit_xml_list].each do |attr|
66
+ next unless Dcc::TypeGuards.has_attribute?(node, attr)
67
+
68
+ v = node.public_send(attr)
69
+ next if v.nil? || v.to_s.empty?
70
+
71
+ v.to_s.split(/\s+/).each do |tok|
72
+ accumulator << tok if tok.start_with?("|")
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ require "set"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Validates `dcc:release` format: `^[a-zA-Z]{1}(\s)?([0-9]{1,3}\.){0,3}([0-9]{1,3})$`
9
+ class ReleaseFormatCheck < Base
10
+ PATTERN = /\A[a-zA-Z]{1} ?([0-9]{1,3}\.){0,3}[0-9]{1,3}\z/
11
+
12
+ def check_on(dcc)
13
+ issues = []
14
+ return issues unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
15
+
16
+ software_list = safe_attr(dcc.administrative_data, :dcc_software)
17
+ return issues if software_list.nil?
18
+
19
+ Array(safe_attr(software_list, :software)).each do |sw|
20
+ release = Dcc::TypeGuards.has_attribute?(sw, :release) ? sw.release : nil
21
+ next if release.nil? || release.empty?
22
+ next if release.match?(PATTERN)
23
+
24
+ issues << issue(
25
+ severity: :error,
26
+ message: "dcc:release '#{release}' does not match the expected format",
27
+ )
28
+ end
29
+
30
+ issues
31
+ end
32
+
33
+ private
34
+
35
+ def safe_attr(parent, attr)
36
+ return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
37
+
38
+ parent.public_send(attr)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module Dcc
5
+ module Validate
6
+ module Schematron
7
+ module Rules
8
+ # Warn when the schemaVersion is not the latest known release.
9
+ class SchemaVersionCheck < Base
10
+ def severity
11
+ ::Dcc::Validate::Severity::WARNING
12
+ end
13
+
14
+ def check_on(dcc)
15
+ return [] unless Dcc::TypeGuards.has_attribute?(dcc, :schema_version)
16
+
17
+ current = dcc.schema_version.to_s
18
+ latest = ::Dcc::Schema::Version::DCC_LATEST
19
+
20
+ current == latest ? [] : [
21
+ issue(
22
+ severity: :warning,
23
+ message: "schemaVersion '#{current}' is not the latest release (#{latest})",
24
+ ),
25
+ ]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Validate
5
+ module Schematron
6
+ module Rules
7
+ # Validates that for every `si:realListXMLList` paired with an
8
+ # `si:expandedUncXMLList`, the count of values matches the count
9
+ # of uncertainty entries.
10
+ class UncertaintyConsistency < Base
11
+ def check_on(dcc)
12
+ issues = []
13
+ return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
14
+
15
+ walk(dcc, issues, ::Set.new)
16
+ issues
17
+ end
18
+
19
+ private
20
+
21
+ def walk(node, issues, visited)
22
+ return unless node.is_a?(::Lutaml::Model::Serializable)
23
+ return if visited.include?(node.object_id)
24
+
25
+ visited << node.object_id
26
+
27
+ check_node(node, issues) if node.class.name.end_with?("::RealListXmlList")
28
+ descend(node, issues, visited)
29
+ end
30
+
31
+ def check_node(list_node, issues)
32
+ values = list_node.value_xml_list
33
+ unc = list_node.expanded_unc_xml_list
34
+ return unless unc && values
35
+
36
+ unc_count = Array(unc.uncertainty_xml_list).size
37
+ value_count = Array(values).size
38
+ return if unc_count == value_count || unc_count.zero?
39
+
40
+ issues << issue(
41
+ severity: :error,
42
+ message: "valueXMLList count (#{value_count}) does not match expandedUncertaintyXMLList count (#{unc_count})",
43
+ )
44
+ end
45
+
46
+ def descend(node, issues, visited)
47
+ node.class.attributes.each_key do |attr_name|
48
+ value = node.public_send(attr_name)
49
+ Array(value).each { |child| walk(child, issues, visited) }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ require "set"
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Validate
5
+ module Schematron
6
+ module Rules
7
+ # Validates that SI unit expressions contain no whitespace and
8
+ # that `unitXMLList` element count matches `valueXMLList` count.
9
+ class UnitFormatCheck < Base
10
+ def check_on(dcc)
11
+ issues = []
12
+ return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
13
+
14
+ walk(dcc, issues, ::Set.new)
15
+ issues
16
+ end
17
+
18
+ private
19
+
20
+ def walk(node, issues, visited)
21
+ return unless node.is_a?(::Lutaml::Model::Serializable)
22
+ return if visited.include?(node.object_id)
23
+
24
+ visited << node.object_id
25
+
26
+ check_single_unit(node, issues)
27
+ check_list_unit(node, issues)
28
+ descend(node, issues, visited)
29
+ end
30
+
31
+ def check_single_unit(node, issues)
32
+ return unless node.class.name.end_with?("::Real", "::Complex", "::Constant")
33
+ return unless node.respond_to?(:unit)
34
+
35
+ unit = node.unit
36
+ return unless unit && unit.to_s.match?(/\s/)
37
+
38
+ issues << issue(
39
+ severity: :error,
40
+ message: "si:unit '#{unit}' must not contain whitespace",
41
+ )
42
+ end
43
+
44
+ def check_list_unit(node, issues)
45
+ return unless node.class.name.end_with?("::RealListXmlList")
46
+ return unless node.respond_to?(:unit_xml_list)
47
+
48
+ unit_list = node.unit_xml_list
49
+ value_list = node.respond_to?(:value_xml_list) ? node.value_xml_list : nil
50
+ return unless unit_list && value_list
51
+
52
+ unit_count = unit_list.to_s.split(/\s+/).length
53
+ value_count = Array(value_list).length
54
+ return if unit_count == value_count || unit_count == 1
55
+
56
+ issues << issue(
57
+ severity: :error,
58
+ message: "unitXMLList count (#{unit_count}) does not match valueXMLList count (#{value_count})",
59
+ )
60
+ end
61
+
62
+ def descend(node, issues, visited)
63
+ node.class.attributes.each_key do |attr_name|
64
+ value = node.public_send(attr_name)
65
+ Array(value).each { |child| walk(child, issues, visited) }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ require "set"