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,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tty-table"
4
+
5
+ module Dcc
6
+ module Cli
7
+ # `Dcc::Cli::Formatters` picks the right text/JSON/YAML representation
8
+ # of a result model and prints it.
9
+ module Formatters
10
+ module_function
11
+
12
+ def print(object, format: "text")
13
+ case format
14
+ when "json" then puts object.to_json
15
+ when "yaml" then puts object.to_yaml
16
+ else
17
+ puts object.to_s
18
+ end
19
+ end
20
+
21
+ def print_files(files)
22
+ if files.empty?
23
+ puts "(no embedded files)"
24
+ return
25
+ end
26
+
27
+ # TTY::Table calls ioctl which fails on StringIO / pipes. Fall back
28
+ # to a plain-text rendering when stdout isn't a real terminal.
29
+ if $stdout.is_a?(::IO) && !$stdout.tty?
30
+ print_files_plain(files)
31
+ return
32
+ end
33
+
34
+ table = ::TTY::Table.new(
35
+ ["Index", "Name", "File Name", "MIME", "Ring", "Size"],
36
+ files.each_with_index.map do |f, i|
37
+ [i, f.name.to_s, f.file_name.to_s, f.mime_type.to_s, f.ring, f.data.bytesize]
38
+ end,
39
+ )
40
+ puts table.render
41
+ rescue StandardError
42
+ # Fallback if TTY::Table rendering fails for any reason.
43
+ print_files_plain(files)
44
+ end
45
+
46
+ def print_files_plain(files)
47
+ # Widths
48
+ widths = ["Index".size, "Name".size, "File Name".size, "MIME".size, "Ring".size, "Size".size]
49
+ rows = files.each_with_index.map do |f, i|
50
+ [
51
+ i.to_s,
52
+ f.name.to_s,
53
+ f.file_name.to_s,
54
+ f.mime_type.to_s,
55
+ f.ring.to_s,
56
+ f.data.bytesize.to_s,
57
+ ].each_with_index { |v, idx| widths[idx] = [widths[idx], v.size].max }
58
+ end
59
+ header = ["Index", "Name", "File Name", "MIME", "Ring", "Size"]
60
+ sep = widths.map { |w| "-" * (w + 2) }.join("+")
61
+ puts header.zip(widths).map { |c, w| " #{c.ljust(w)} " }.join("|")
62
+ puts sep
63
+ files.each_with_index do |f, i|
64
+ row = [
65
+ i.to_s,
66
+ f.name.to_s,
67
+ f.file_name.to_s,
68
+ f.mime_type.to_s,
69
+ f.ring.to_s,
70
+ f.data.bytesize.to_s,
71
+ ]
72
+ puts row.zip(widths).map { |c, w| " #{c.ljust(w)} " }.join("|")
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
data/lib/dcc/cli.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `Dcc::Cli` namespace root — autoloads the Thor command class.
4
+ module Dcc
5
+ module Cli
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Dcc
6
+ # `Dcc::CommonElements` is the base class for all DCC element wrappers in a
7
+ # version namespace. It provides the shared `lutaml_default_register`
8
+ # override that version wrappers inherit, so they don't each have to declare
9
+ # it themselves.
10
+ #
11
+ # Version modules (`Dcc::V2`, `Dcc::V3`) subclass this to define their
12
+ # own `CommonElements` with a `lutaml_default_register` matching their
13
+ # `CONTEXT_ID`.
14
+ class CommonElements < Lutaml::Model::Serializable
15
+ # Default context; version wrappers override this via subclassing.
16
+ def self.lutaml_default_register
17
+ :dcc_v3
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `Dcc::ContextConfiguration` mirrors the registry-aware per-major-version
4
+ # pattern from plurimath/mml. Each version module (`Dcc::V2`, `Dcc::V3`,
5
+ # `Dcc::Si::V1`, `Dcc::Si::V2`) extends this module and defines a unique
6
+ # `CONTEXT_ID` symbol (e.g. `:dcc_v3`). The version's Configuration then
7
+ # provides:
8
+ #
9
+ # * `register_model(klass, id:)` — register a model class for an XML element
10
+ # name within this version's type registry.
11
+ # * `create_context(id:, substitutions:, ...)` — derive a custom context for
12
+ # minor-version variants (e.g. `:dcc_v3_4`).
13
+ # * `populate_context!` — rebuild the version's built-in context (useful in
14
+ # tests after clearing the global cache).
15
+ # * `default_context_id` — the context id that `parse` uses when no override
16
+ # is supplied.
17
+ module Dcc
18
+ module ContextConfiguration
19
+ # @return [Symbol] the version's canonical context id (e.g. `:dcc_v3`).
20
+ def context_id
21
+ self::CONTEXT_ID
22
+ end
23
+
24
+ # @return [Lutaml::Model::Context, nil] the live context for this version,
25
+ # or `nil` if not yet populated.
26
+ def context
27
+ Lutaml::Model::GlobalContext.context(context_id)
28
+ end
29
+
30
+ # Create or replace a context. If `id` matches the version's canonical
31
+ # context id, the built-in context is rebuilt via `populate_context!`.
32
+ #
33
+ # @param id [Symbol, String] context name.
34
+ # @param registry [Lutaml::Model::TypeRegistry, nil] custom registry.
35
+ # @param fallback_to [Array<Symbol>] fallback chain for type lookup.
36
+ # @param substitutions [Array<Hash{from_type:, to_type:}>] type substitutions.
37
+ def create_context(id:, registry: nil, fallback_to: [context_id], substitutions: [])
38
+ normalized_id = ::Dcc::ContextOptions.normalize_context_reference(id)
39
+ return populate_context! if normalized_id == context_id
40
+
41
+ unregister_existing(normalized_id)
42
+ create_type_context(
43
+ id: normalized_id,
44
+ registry: registry || Lutaml::Model::TypeRegistry.new,
45
+ fallback_to: normalize_fallbacks(fallback_to),
46
+ substitutions: substitutions,
47
+ )
48
+ end
49
+
50
+ # Rebuild the version's built-in context from `registered_models`.
51
+ def populate_context!
52
+ unregister_existing(context_id)
53
+ register_models_in(base_type_context)
54
+ end
55
+
56
+ # Contexts that this one falls back to when type lookup fails.
57
+ # Override in version modules to pull in cross-namespace types
58
+ # (e.g. DCC contexts fall back to D-SI contexts for `:real`, `:hybrid`).
59
+ # @return [Array<Symbol>]
60
+ def fallback_contexts
61
+ [:default]
62
+ end
63
+
64
+ # Register a model for an XML element name and remember it for rebuilds.
65
+ #
66
+ # @param klass [Class] the model class.
67
+ # @param id [Symbol, String] XML element local name (e.g. `:digitalCalibrationCertificate`).
68
+ # @return [Class] the registered class.
69
+ def register_model(klass, id:)
70
+ normalized_id = id.to_sym
71
+ registered_models[normalized_id] = klass
72
+ (context || populate_base_context).registry.register(normalized_id, klass)
73
+ clear_cache(klass)
74
+ klass
75
+ end
76
+
77
+ # @return [Symbol] the context id used when none is supplied explicitly.
78
+ def default_context_id
79
+ @default_context_id || context_id
80
+ end
81
+
82
+ # Override the default context (used by `custom_models=`).
83
+ attr_writer :default_context_id
84
+
85
+ # Convenience: bulk-register model substitutions.
86
+ #
87
+ # @param models [Hash{Class => Class}] from_type => to_type.
88
+ def custom_models=(models)
89
+ substitutions = models.map do |from_type, to_type|
90
+ { from_type: from_type, to_type: to_type }
91
+ end
92
+ create_context(id: :custom_models, substitutions: substitutions)
93
+ @default_context_id = :custom_models
94
+ end
95
+
96
+ # Reset any custom default context.
97
+ def clear_custom_models
98
+ @default_context_id = nil
99
+ end
100
+
101
+ # Public read-only accessors for cross-context re-export.
102
+ # @return [Array<Symbol>] ids registered in this context.
103
+ def registered_model_ids
104
+ registered_models.keys
105
+ end
106
+
107
+ # @param id [Symbol] the model id.
108
+ # @return [Class, nil] the registered class.
109
+ def registered_model_class(id)
110
+ registered_models[id.to_sym]
111
+ end
112
+
113
+ private
114
+
115
+ def unregister_existing(id)
116
+ return unless Lutaml::Model::GlobalContext.context(id)
117
+
118
+ Lutaml::Model::GlobalContext.unregister_context(id)
119
+ end
120
+
121
+ def populate_base_context
122
+ base_type_context
123
+ end
124
+
125
+ def create_type_context(id:, registry:, fallback_to:, substitutions: [])
126
+ Lutaml::Model::GlobalContext.create_context(
127
+ id: id,
128
+ registry: registry,
129
+ fallback_to: fallback_to,
130
+ substitutions: substitutions,
131
+ ).tap { Lutaml::Model::GlobalContext.clear_caches }
132
+ end
133
+
134
+ def base_type_context
135
+ create_type_context(
136
+ id: context_id,
137
+ registry: Lutaml::Model::TypeRegistry.new,
138
+ fallback_to: fallback_contexts,
139
+ )
140
+ end
141
+
142
+ def register_models_in(type_context)
143
+ registered_models.each do |model_id, klass|
144
+ type_context.registry.register(model_id, klass)
145
+ clear_cache(klass)
146
+ end
147
+ Lutaml::Model::GlobalContext.clear_caches
148
+ type_context
149
+ end
150
+
151
+ def normalize_fallbacks(fallback_to)
152
+ Array(fallback_to).map { |f| ::Dcc::ContextOptions.normalize_context_reference(f) }
153
+ end
154
+
155
+ def registered_models
156
+ @registered_models ||= {}
157
+ end
158
+
159
+ def clear_cache(klass)
160
+ return unless klass.is_a?(Class)
161
+ return unless klass < ::Lutaml::Model::Serializable
162
+ return unless klass.method_defined?(:clear_cache)
163
+
164
+ klass.clear_cache(context_id)
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `Dcc::ContextOptions` normalizes the `context:` / `register:` options that
4
+ # callers can pass to `Dcc.parse`, `Dcc::V3.parse`, etc.
5
+ module Dcc
6
+ module ContextOptions
7
+ module_function
8
+
9
+ # Collapse the public `context:` and `register:` options into a single
10
+ # context id symbol (or `nil` to fall back to the caller's default).
11
+ #
12
+ # @param context [Symbol, String, nil, Dcc::UNSPECIFIED_CONTEXT]
13
+ # @param register [Symbol, String, nil] deprecated alias for `context:`.
14
+ # @param default_context [Symbol, nil] returned when neither is given.
15
+ # @param warning_source [String] caller name for deprecation warnings.
16
+ def normalize_context_option(context:, register:, default_context:, warning_source:)
17
+ raise_if_conflicting!(context, register)
18
+ return normalize_context_reference(register) || default_context if register
19
+ return default_context unless context_specified?(context)
20
+
21
+ normalize_context_reference(context) || default_context
22
+ end
23
+
24
+ # Coerce any acceptable context reference (Symbol, String, or
25
+ # `Lutaml::Xml::Namespace`) into a Symbol.
26
+ def normalize_context_reference(reference)
27
+ return nil if reference.nil?
28
+ return reference if reference.is_a?(Symbol)
29
+ return reference.to_sym if reference.is_a?(String)
30
+ return reference.id.to_sym if reference.is_a?(::Lutaml::Xml::Namespace)
31
+
32
+ raise ArgumentError, "Unsupported context/register reference: #{reference.inspect}"
33
+ end
34
+
35
+ def context_specified?(context)
36
+ !context.equal?(::Dcc::UNSPECIFIED_CONTEXT)
37
+ end
38
+
39
+ def raise_if_conflicting!(context, register)
40
+ return unless context_specified?(context) && register
41
+
42
+ raise ArgumentError, "Use either `context` or `register`, not both"
43
+ end
44
+
45
+ private_class_method :raise_if_conflicting!
46
+ end
47
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module Dcc
6
+ module Convert
7
+ # `Dcc::Convert::Csv` flattens a parsed DCC into a tabular CSV with
8
+ # one row per measurement quantity.
9
+ module Csv
10
+ HEADERS = %w[result_name quantity_name quantity_type value unit uncertainty coverage_factor].freeze
11
+
12
+ class << self
13
+ # @param dcc [Lutaml::Model::Serializable]
14
+ # @return [Dcc::Convert::Result]
15
+ def call(dcc)
16
+ rows = collect_quantities(dcc)
17
+ payload = ::CSV.generate do |csv|
18
+ csv << HEADERS
19
+ rows.each { |row| csv << row }
20
+ end
21
+
22
+ ::Dcc::Convert::Result.new(
23
+ format: :csv,
24
+ payload: payload,
25
+ source_class: dcc.class.name,
26
+ schema_version: dcc.schema_version.to_s,
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def collect_quantities(dcc)
33
+ rows = []
34
+ return rows unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results)
35
+
36
+ Array(dcc.measurement_results.measurement_result).each do |mr|
37
+ mr_name = name_of(mr)
38
+ next unless Dcc::TypeGuards.has_attribute?(mr, :results)
39
+
40
+ Array(mr.results.result).each do |r|
41
+ result_name = name_of(r)
42
+ next unless Dcc::TypeGuards.has_attribute?(r, :data)
43
+
44
+ Array(r.data).each do |d|
45
+ walk_data(d, mr_name, result_name, rows)
46
+ end
47
+ end
48
+ end
49
+ rows
50
+ end
51
+
52
+ def walk_data(data, mr_name, result_name, rows)
53
+ walk_quantities(Array(data.quantity), mr_name, result_name, rows)
54
+ Array(data.list).each do |list|
55
+ walk_quantities(Array(list.quantity), mr_name, result_name, rows)
56
+ Array(list.list).each { |sub| walk_data(sub, mr_name, result_name, rows) }
57
+ end
58
+ end
59
+
60
+ def walk_quantities(quantities, mr_name, result_name, rows)
61
+ quantities.each do |q|
62
+ push_quantity(q, mr_name, result_name, "real", rows)
63
+ end
64
+ end
65
+
66
+ def push_quantity(q, mr_name, result_name, kind, rows)
67
+ rows << [
68
+ mr_name, name_of(q), kind,
69
+ value_of(q), unit_of(q), uncertainty_of(q), k_factor_of(q),
70
+ ]
71
+ end
72
+
73
+ def name_of(node)
74
+ return "" unless node && Dcc::TypeGuards.has_attribute?(node, :name)
75
+ return "" unless node.name
76
+
77
+ content = Dcc::TypeGuards.has_attribute?(node.name, :content) ? node.name.content : []
78
+ first = Array(content).first
79
+ return "" unless first
80
+
81
+ vals = Dcc::TypeGuards.has_attribute?(first, :value) ? first.value : []
82
+ Array(vals).first.to_s
83
+ end
84
+
85
+ def value_of(q)
86
+ reals = Array(q.real)
87
+ return reals.first.value.to_s if reals.any?
88
+
89
+ lists = Array(q.real_list_xml_list)
90
+ return lists.first.value_xml_list.map(&:to_s).join("; ") if lists.any?
91
+
92
+ ""
93
+ end
94
+
95
+ def unit_of(q)
96
+ reals = Array(q.real)
97
+ return reals.first.unit.to_s if reals.any? && reals.first.unit
98
+
99
+ lists = Array(q.real_list_xml_list)
100
+ return lists.first.unit_xml_list.to_s if lists.any? && lists.first.unit_xml_list
101
+
102
+ ""
103
+ end
104
+
105
+ def uncertainty_of(q)
106
+ reals = Array(q.real)
107
+ return "" if reals.empty? || !reals.first.measurement_uncertainty_univariate
108
+
109
+ mu = reals.first.measurement_uncertainty_univariate
110
+ return mu.expanded_mu.value_expanded_mu.to_s if mu.expanded_mu
111
+ return mu.standard_mu.value_standard_mu.to_s if mu.standard_mu
112
+ return mu.coverage_interval_mu.value_standard_mu.to_s if mu.coverage_interval_mu
113
+
114
+ ""
115
+ end
116
+
117
+ def k_factor_of(q)
118
+ reals = Array(q.real)
119
+ return "" if reals.empty?
120
+
121
+ mu = reals.first.measurement_uncertainty_univariate
122
+ return "" unless mu&.expanded_mu
123
+
124
+ mu.expanded_mu.coverage_factor.to_s
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Convert
5
+ # `Dcc::Convert::Html` renders a parsed DCC into a human-readable HTML
6
+ # report with collapsible sections per administrative section and
7
+ # measurement result.
8
+ module Html
9
+ class << self
10
+ # @param dcc [Lutaml::Model::Serializable]
11
+ # @return [Dcc::Convert::Result]
12
+ def call(dcc)
13
+ payload = <<~HTML
14
+ <!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="utf-8">
18
+ <title>DCC Report #{escape(unique_identifier_of(dcc))}</title>
19
+ <style>
20
+ body { font-family: -apple-system, system-ui, sans-serif; margin: 2rem; }
21
+ h1, h2, h3 { color: #333; }
22
+ section { margin-bottom: 1.5rem; padding: 1rem; border: 1px solid #eee; border-radius: 4px; }
23
+ table { border-collapse: collapse; }
24
+ th, td { border: 1px solid #ddd; padding: 0.5rem 1rem; text-align: left; }
25
+ th { background: #f5f5f5; }
26
+ </style>
27
+ </head>
28
+ <body>
29
+ <h1>Digital Calibration Certificate</h1>
30
+ #{summary_table(dcc)}
31
+ #{administrative_section(dcc)}
32
+ #{measurement_section(dcc)}
33
+ </body>
34
+ </html>
35
+ HTML
36
+
37
+ ::Dcc::Convert::Result.new(
38
+ format: :html,
39
+ payload: payload,
40
+ source_class: dcc.class.name,
41
+ schema_version: dcc.schema_version.to_s,
42
+ )
43
+ end
44
+
45
+ private
46
+
47
+ def summary_table(dcc)
48
+ <<~HTML
49
+ <section>
50
+ <h2>Identity</h2>
51
+ <table>
52
+ <tr><th>Schema version</th><td>#{escape(dcc.schema_version)}</td></tr>
53
+ <tr><th>Unique identifier</th><td>#{escape(unique_identifier_of(dcc))}</td></tr>
54
+ <tr><th>Country</th><td>#{escape(country_of(dcc))}</td></tr>
55
+ </table>
56
+ </section>
57
+ HTML
58
+ end
59
+
60
+ def administrative_section(dcc)
61
+ return "" unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data) && dcc.administrative_data
62
+
63
+ admin = dcc.administrative_data
64
+ items = Dcc::TypeGuards.has_attribute?(admin, :items) && admin.items ? Array(admin.items.item) : []
65
+ <<~HTML
66
+ <section>
67
+ <h2>Items (#{items.size})</h2>
68
+ <ul>
69
+ #{items.map { |i| "<li>#{escape(name_of(i))}</li>" }.join("\n")}
70
+ </ul>
71
+ </section>
72
+ HTML
73
+ end
74
+
75
+ def measurement_section(dcc)
76
+ return "" unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results) && dcc.measurement_results
77
+
78
+ mrs = Array(dcc.measurement_results.measurement_result)
79
+ <<~HTML
80
+ <section>
81
+ <h2>Measurement Results (#{mrs.size})</h2>
82
+ <ul>
83
+ #{mrs.map { |mr| "<li>#{escape(name_of(mr))}</li>" }.join("\n")}
84
+ </ul>
85
+ </section>
86
+ HTML
87
+ end
88
+
89
+ def unique_identifier_of(dcc)
90
+ Dcc::TypeGuards.has_attribute?(dcc, :administrative_data) &&
91
+ Dcc::TypeGuards.has_attribute?(dcc.administrative_data, :core_data) &&
92
+ dcc.administrative_data.core_data &&
93
+ dcc.administrative_data.core_data.unique_identifier.to_s
94
+ end
95
+
96
+ def country_of(dcc)
97
+ Dcc::TypeGuards.has_attribute?(dcc, :administrative_data) &&
98
+ Dcc::TypeGuards.has_attribute?(dcc.administrative_data, :core_data) &&
99
+ dcc.administrative_data.core_data &&
100
+ dcc.administrative_data.core_data.country_code_iso_3166_1.to_s
101
+ end
102
+
103
+ def name_of(node)
104
+ return "" unless node && Dcc::TypeGuards.has_attribute?(node, :name)
105
+ return "" unless node.name
106
+
107
+ content = Dcc::TypeGuards.has_attribute?(node.name, :content) ? node.name.content : []
108
+ first = Array(content).first
109
+ return "" unless first
110
+
111
+ vals = Dcc::TypeGuards.has_attribute?(first, :value) ? first.value : []
112
+ Array(vals).first.to_s
113
+ end
114
+
115
+ def escape(s)
116
+ return "" if s.nil?
117
+
118
+ s.to_s
119
+ .gsub("&", "&amp;")
120
+ .gsub("<", "&lt;")
121
+ .gsub(">", "&gt;")
122
+ .gsub('"', "&quot;")
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Dcc
6
+ module Convert
7
+ # `Dcc::Convert::Json` serializes a parsed DCC to JSON by converting
8
+ # the `to_xml` output to a JSON-compatible hash.
9
+ module Json
10
+ class << self
11
+ def call(dcc, pretty: true)
12
+ hash = xml_to_hash(dcc.to_xml)
13
+ payload = pretty ? ::JSON.pretty_generate(hash) : ::JSON.generate(hash)
14
+ ::Dcc::Convert::Result.new(
15
+ format: :json,
16
+ payload: payload,
17
+ source_class: dcc.class.name,
18
+ schema_version: dcc.schema_version.to_s,
19
+ )
20
+ end
21
+
22
+ def xml_to_hash(xml_string)
23
+ doc = ::Lutaml::Model::Config.xml_adapter.parse(xml_string)
24
+ element_to_hash(doc.root)
25
+ end
26
+
27
+ private
28
+
29
+ def element_to_hash(element)
30
+ hash = {}
31
+
32
+ element.attributes&.each do |k, v|
33
+ hash[k.to_s] = v.value.to_s
34
+ end
35
+
36
+ children = element.children.to_a.reject(&:text?)
37
+ text_children = element.children.to_a.select(&:text?)
38
+ combined_text = text_children.map(&:text).join.strip
39
+
40
+ if children.empty?
41
+ return combined_text if hash.empty? && !combined_text.empty?
42
+ return hash if combined_text.empty?
43
+
44
+ hash["_text"] = combined_text
45
+ return hash
46
+ end
47
+
48
+ children.each do |child|
49
+ name = child.name.to_s.split(":").last
50
+ value = element_to_hash(child)
51
+ if hash.key?(name)
52
+ hash[name] = Array(hash[name]) << value
53
+ else
54
+ hash[name] = value
55
+ end
56
+ end
57
+ hash
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcc
4
+ module Convert
5
+ # Output of a `Dcc::Convert::*` converter. Carries the format and the
6
+ # string payload. Outputs are models per the user's directive:
7
+ # `to_s` returns the rendered payload, `to_json` / `to_yaml` return
8
+ # the formatted payload directly.
9
+ class Result
10
+ attr_reader :format, :payload, :source_class, :schema_version
11
+
12
+ # @param format [Symbol, String] the conversion target (`:json`, `:yaml`, etc.).
13
+ # @param payload [String] the rendered output.
14
+ # @param source_class [String, nil] the source model's class name.
15
+ # @param schema_version [String, nil] the DCC schema version.
16
+ def initialize(format:, payload:, source_class: nil, schema_version: nil)
17
+ @format = format.to_sym
18
+ @payload = payload.to_s
19
+ @source_class = source_class
20
+ @schema_version = schema_version
21
+ end
22
+
23
+ # `to_s` returns the rendered output.
24
+ def to_s
25
+ @payload
26
+ end
27
+
28
+ # Convenience: parse the payload back into Ruby data structures.
29
+ # @return [Object]
30
+ def parsed
31
+ case @format
32
+ when :json
33
+ ::JSON.parse(@payload)
34
+ when :yaml
35
+ ::YAML.safe_load(@payload)
36
+ else
37
+ @payload
38
+ end
39
+ end
40
+
41
+ # Already-rendered JSON payload (not a re-render).
42
+ def to_json(*_args)
43
+ @payload
44
+ end
45
+
46
+ def to_yaml(*_args)
47
+ @payload
48
+ end
49
+ end
50
+ end
51
+ end