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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +10 -0
- data/CHANGELOG.adoc +54 -0
- data/CONTRIBUTING.adoc +64 -0
- data/Gemfile +25 -0
- data/LICENSE +21 -0
- data/README.adoc +69 -0
- data/Rakefile +13 -0
- data/dcc.gemspec +41 -0
- data/docs/cli-reference.adoc +67 -0
- data/docs/getting-started.adoc +117 -0
- data/docs/schema-versions.adoc +65 -0
- data/examples/build_minimal_dcc.rb +23 -0
- data/examples/convert_all_formats.rb +19 -0
- data/examples/parse_and_inspect.rb +19 -0
- data/examples/quantity_math_demo.rb +32 -0
- data/examples/validate_full.rb +27 -0
- data/exe/dcc +7 -0
- data/lib/dcc/base/administrative_data.rb +43 -0
- data/lib/dcc/base/byte_data.rb +36 -0
- data/lib/dcc/base/calibration_laboratory.rb +29 -0
- data/lib/dcc/base/comment.rb +23 -0
- data/lib/dcc/base/condition.rb +34 -0
- data/lib/dcc/base/contact.rb +38 -0
- data/lib/dcc/base/contact_not_strict.rb +38 -0
- data/lib/dcc/base/core_data.rb +44 -0
- data/lib/dcc/base/data.rb +42 -0
- data/lib/dcc/base/digital_calibration_certificate.rb +32 -0
- data/lib/dcc/base/equipment_class.rb +24 -0
- data/lib/dcc/base/formula.rb +33 -0
- data/lib/dcc/base/hash_type.rb +34 -0
- data/lib/dcc/base/identification.rb +27 -0
- data/lib/dcc/base/identifications.rb +27 -0
- data/lib/dcc/base/influence_condition.rb +16 -0
- data/lib/dcc/base/influence_condition_list.rb +40 -0
- data/lib/dcc/base/item.rb +38 -0
- data/lib/dcc/base/item_list.rb +38 -0
- data/lib/dcc/base/list.rb +44 -0
- data/lib/dcc/base/location.rb +36 -0
- data/lib/dcc/base/measurement_meta_data.rb +15 -0
- data/lib/dcc/base/measurement_meta_data_list.rb +27 -0
- data/lib/dcc/base/measurement_result.rb +41 -0
- data/lib/dcc/base/measurement_result_list.rb +28 -0
- data/lib/dcc/base/measuring_equipment.rb +41 -0
- data/lib/dcc/base/measuring_equipment_list.rb +38 -0
- data/lib/dcc/base/quantity.rb +61 -0
- data/lib/dcc/base/ref_type_definition.rb +36 -0
- data/lib/dcc/base/ref_type_definition_list.rb +21 -0
- data/lib/dcc/base/resp_person.rb +38 -0
- data/lib/dcc/base/resp_person_list.rb +27 -0
- data/lib/dcc/base/result.rb +31 -0
- data/lib/dcc/base/result_list.rb +27 -0
- data/lib/dcc/base/rich_content.rb +34 -0
- data/lib/dcc/base/software.rb +35 -0
- data/lib/dcc/base/software_list.rb +27 -0
- data/lib/dcc/base/statement.rb +50 -0
- data/lib/dcc/base/statement_list.rb +27 -0
- data/lib/dcc/base/string_with_lang.rb +24 -0
- data/lib/dcc/base/text.rb +33 -0
- data/lib/dcc/base/used_method.rb +31 -0
- data/lib/dcc/base/used_method_list.rb +27 -0
- data/lib/dcc/base/xml_blob.rb +20 -0
- data/lib/dcc/base.rb +58 -0
- data/lib/dcc/builder/dsl.rb +10 -0
- data/lib/dcc/builder/session.rb +170 -0
- data/lib/dcc/builder.rb +34 -0
- data/lib/dcc/cli/cli.rb +149 -0
- data/lib/dcc/cli/formatters.rb +77 -0
- data/lib/dcc/cli.rb +7 -0
- data/lib/dcc/common_elements.rb +20 -0
- data/lib/dcc/context_configuration.rb +167 -0
- data/lib/dcc/context_options.rb +47 -0
- data/lib/dcc/convert/csv.rb +129 -0
- data/lib/dcc/convert/html.rb +127 -0
- data/lib/dcc/convert/json.rb +62 -0
- data/lib/dcc/convert/result.rb +51 -0
- data/lib/dcc/convert/yaml.rb +21 -0
- data/lib/dcc/convert.rb +14 -0
- data/lib/dcc/diff/change.rb +21 -0
- data/lib/dcc/diff/result.rb +58 -0
- data/lib/dcc/diff.rb +83 -0
- data/lib/dcc/error.rb +54 -0
- data/lib/dcc/extract/file.rb +143 -0
- data/lib/dcc/extract/ring.rb +28 -0
- data/lib/dcc/extract.rb +9 -0
- data/lib/dcc/i18n/text_lookup.rb +67 -0
- data/lib/dcc/i18n.rb +12 -0
- data/lib/dcc/inspect/report.rb +139 -0
- data/lib/dcc/inspect.rb +9 -0
- data/lib/dcc/migrate.rb +41 -0
- data/lib/dcc/namespace/dcc.rb +30 -0
- data/lib/dcc/namespace/dsig.rb +15 -0
- data/lib/dcc/namespace/math_ml.rb +14 -0
- data/lib/dcc/namespace/qudt.rb +15 -0
- data/lib/dcc/namespace/si.rb +26 -0
- data/lib/dcc/namespace.rb +18 -0
- data/lib/dcc/plugin/registry.rb +45 -0
- data/lib/dcc/plugin.rb +42 -0
- data/lib/dcc/quantity_format/formatter.rb +90 -0
- data/lib/dcc/quantity_format.rb +10 -0
- data/lib/dcc/quantity_math/quantity.rb +46 -0
- data/lib/dcc/quantity_math/real.rb +116 -0
- data/lib/dcc/quantity_math.rb +14 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.0.1.xsd +415 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.3.0.xsd +814 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.3.1.xsd +814 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.0.0.xsd +869 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.1.0.xsd +1031 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.2.1.xsd +1574 -0
- data/lib/dcc/schema/resources/dcc/qudt/v2.2.1.xsd +44 -0
- data/lib/dcc/schema/resources/dcc/v2.1.0/dcc.xsd +650 -0
- data/lib/dcc/schema/resources/dcc/v2.1.1/dcc.xsd +669 -0
- data/lib/dcc/schema/resources/dcc/v2.2.0/dcc.xsd +730 -0
- data/lib/dcc/schema/resources/dcc/v2.3.0/dcc.xsd +708 -0
- data/lib/dcc/schema/resources/dcc/v2.4.0/dcc.xsd +725 -0
- data/lib/dcc/schema/resources/dcc/v3.0.0/dcc.xsd +749 -0
- data/lib/dcc/schema/resources/dcc/v3.1.0/dcc.xsd +843 -0
- data/lib/dcc/schema/resources/dcc/v3.1.1/dcc.xsd +843 -0
- data/lib/dcc/schema/resources/dcc/v3.1.2/dcc.xsd +844 -0
- data/lib/dcc/schema/resources/dcc/v3.2.0/dcc.xsd +940 -0
- data/lib/dcc/schema/resources/dcc/v3.2.1/dcc.xsd +963 -0
- data/lib/dcc/schema/resources/dcc/v3.3.0/dcc.xsd +1008 -0
- data/lib/dcc/schema/resources/dcc/xmldsig-core-schema.xsd +312 -0
- data/lib/dcc/schema/resources/dsi/qudt/v2.2.1.xsd +44 -0
- data/lib/dcc/schema/resources/dsi/v1.0.1/SI_Format.xsd +415 -0
- data/lib/dcc/schema/resources/dsi/v1.3.0/SI_Format.xsd +814 -0
- data/lib/dcc/schema/resources/dsi/v1.3.1/SI_Format.xsd +814 -0
- data/lib/dcc/schema/resources/dsi/v2.0.0/SI_Format.xsd +869 -0
- data/lib/dcc/schema/resources/dsi/v2.1.0/SI_Format.xsd +1031 -0
- data/lib/dcc/schema/resources/dsi/v2.2.1/SI_Format.xsd +1574 -0
- data/lib/dcc/schema/resources/qudt/qudt.xsd +44 -0
- data/lib/dcc/schema/resources/schematron/dcc.sch +523 -0
- data/lib/dcc/schema/resources/schematron/dcc.svrl +2302 -0
- data/lib/dcc/schema/resources/xmldsig/xmldsig-core-schema.xsd +312 -0
- data/lib/dcc/schema/version.rb +94 -0
- data/lib/dcc/schema.rb +35 -0
- data/lib/dcc/server/app.rb +133 -0
- data/lib/dcc/server/storage/entry.rb +15 -0
- data/lib/dcc/server/storage/memory.rb +57 -0
- data/lib/dcc/server/storage.rb +13 -0
- data/lib/dcc/server.rb +33 -0
- data/lib/dcc/si/base/complex.rb +43 -0
- data/lib/dcc/si/base/complex_list_xml_list.rb +39 -0
- data/lib/dcc/si/base/constant.rb +39 -0
- data/lib/dcc/si/base/coverage_interval_mu.rb +31 -0
- data/lib/dcc/si/base/expanded_mu.rb +29 -0
- data/lib/dcc/si/base/expanded_unc_xml_list.rb +30 -0
- data/lib/dcc/si/base/hybrid.rb +42 -0
- data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +28 -0
- data/lib/dcc/si/base/real.rb +48 -0
- data/lib/dcc/si/base/real_list_xml_list.rb +45 -0
- data/lib/dcc/si/base/si_list.rb +37 -0
- data/lib/dcc/si/base/standard_mu.rb +25 -0
- data/lib/dcc/si/base.rb +24 -0
- data/lib/dcc/si/common_elements.rb +13 -0
- data/lib/dcc/si/namespace.rb +7 -0
- data/lib/dcc/si/v1/common_elements.rb +13 -0
- data/lib/dcc/si/v1/complex.rb +8 -0
- data/lib/dcc/si/v1/complex_list_xml_list.rb +8 -0
- data/lib/dcc/si/v1/configuration.rb +13 -0
- data/lib/dcc/si/v1/constant.rb +8 -0
- data/lib/dcc/si/v1/coverage_interval_mu.rb +8 -0
- data/lib/dcc/si/v1/expanded_mu.rb +8 -0
- data/lib/dcc/si/v1/expanded_unc.rb +23 -0
- data/lib/dcc/si/v1/expanded_unc_xml_list.rb +8 -0
- data/lib/dcc/si/v1/hybrid.rb +8 -0
- data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +8 -0
- data/lib/dcc/si/v1/namespace.rb +9 -0
- data/lib/dcc/si/v1/real.rb +8 -0
- data/lib/dcc/si/v1/real_list_xml_list.rb +8 -0
- data/lib/dcc/si/v1/si_list.rb +8 -0
- data/lib/dcc/si/v1/standard_mu.rb +8 -0
- data/lib/dcc/si/v1.rb +46 -0
- data/lib/dcc/si/v2/common_elements.rb +13 -0
- data/lib/dcc/si/v2/complex.rb +8 -0
- data/lib/dcc/si/v2/complex_list_xml_list.rb +8 -0
- data/lib/dcc/si/v2/configuration.rb +13 -0
- data/lib/dcc/si/v2/constant.rb +8 -0
- data/lib/dcc/si/v2/coverage_interval_mu.rb +8 -0
- data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +24 -0
- data/lib/dcc/si/v2/expanded_mu.rb +8 -0
- data/lib/dcc/si/v2/expanded_mu_xml_list.rb +22 -0
- data/lib/dcc/si/v2/expanded_unc_xml_list.rb +8 -0
- data/lib/dcc/si/v2/hybrid.rb +8 -0
- data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +8 -0
- data/lib/dcc/si/v2/namespace.rb +9 -0
- data/lib/dcc/si/v2/real.rb +8 -0
- data/lib/dcc/si/v2/real_list_xml_list.rb +8 -0
- data/lib/dcc/si/v2/si_list.rb +8 -0
- data/lib/dcc/si/v2/standard_mu.rb +8 -0
- data/lib/dcc/si/v2/standard_mu_xml_list.rb +18 -0
- data/lib/dcc/si/v2.rb +49 -0
- data/lib/dcc/si.rb +34 -0
- data/lib/dcc/signature/result.rb +43 -0
- data/lib/dcc/signature/signer.rb +36 -0
- data/lib/dcc/signature/verifier.rb +41 -0
- data/lib/dcc/signature.rb +13 -0
- data/lib/dcc/transform/result.rb +24 -0
- data/lib/dcc/transform/xslt.rb +72 -0
- data/lib/dcc/transform.rb +12 -0
- data/lib/dcc/type/base64_binary.rb +55 -0
- data/lib/dcc/type/decimal_xml_list.rb +47 -0
- data/lib/dcc/type/iso_country_code.rb +23 -0
- data/lib/dcc/type/iso_language_code.rb +23 -0
- data/lib/dcc/type/schema_version.rb +37 -0
- data/lib/dcc/type/si_unit.rb +26 -0
- data/lib/dcc/type.rb +16 -0
- data/lib/dcc/type_guards.rb +140 -0
- data/lib/dcc/v2/administrative_data.rb +8 -0
- data/lib/dcc/v2/byte_data.rb +8 -0
- data/lib/dcc/v2/calibration_laboratory.rb +8 -0
- data/lib/dcc/v2/comment.rb +8 -0
- data/lib/dcc/v2/common_elements.rb +13 -0
- data/lib/dcc/v2/condition.rb +8 -0
- data/lib/dcc/v2/configuration.rb +17 -0
- data/lib/dcc/v2/contact.rb +8 -0
- data/lib/dcc/v2/contact_not_strict.rb +8 -0
- data/lib/dcc/v2/core_data.rb +8 -0
- data/lib/dcc/v2/data.rb +8 -0
- data/lib/dcc/v2/digital_calibration_certificate.rb +8 -0
- data/lib/dcc/v2/equipment_class.rb +8 -0
- data/lib/dcc/v2/formula.rb +8 -0
- data/lib/dcc/v2/hash_type.rb +8 -0
- data/lib/dcc/v2/identification.rb +8 -0
- data/lib/dcc/v2/identifications.rb +8 -0
- data/lib/dcc/v2/influence_condition.rb +7 -0
- data/lib/dcc/v2/influence_condition_list.rb +8 -0
- data/lib/dcc/v2/item.rb +8 -0
- data/lib/dcc/v2/item_list.rb +8 -0
- data/lib/dcc/v2/list.rb +8 -0
- data/lib/dcc/v2/location.rb +8 -0
- data/lib/dcc/v2/measurement_meta_data.rb +8 -0
- data/lib/dcc/v2/measurement_meta_data_list.rb +8 -0
- data/lib/dcc/v2/measurement_result.rb +8 -0
- data/lib/dcc/v2/measurement_result_list.rb +8 -0
- data/lib/dcc/v2/measuring_equipment.rb +8 -0
- data/lib/dcc/v2/measuring_equipment_list.rb +8 -0
- data/lib/dcc/v2/namespace.rb +8 -0
- data/lib/dcc/v2/quantity.rb +49 -0
- data/lib/dcc/v2/ref_type_definition.rb +11 -0
- data/lib/dcc/v2/ref_type_definition_list.rb +15 -0
- data/lib/dcc/v2/resp_person.rb +8 -0
- data/lib/dcc/v2/resp_person_list.rb +8 -0
- data/lib/dcc/v2/result.rb +8 -0
- data/lib/dcc/v2/result_list.rb +8 -0
- data/lib/dcc/v2/rich_content.rb +12 -0
- data/lib/dcc/v2/software.rb +8 -0
- data/lib/dcc/v2/software_list.rb +8 -0
- data/lib/dcc/v2/statement.rb +8 -0
- data/lib/dcc/v2/statement_list.rb +8 -0
- data/lib/dcc/v2/string_with_lang.rb +8 -0
- data/lib/dcc/v2/text.rb +8 -0
- data/lib/dcc/v2/used_method.rb +8 -0
- data/lib/dcc/v2/used_method_list.rb +8 -0
- data/lib/dcc/v2/xml_blob.rb +8 -0
- data/lib/dcc/v2.rb +84 -0
- data/lib/dcc/v3/administrative_data.rb +8 -0
- data/lib/dcc/v3/byte_data.rb +8 -0
- data/lib/dcc/v3/calibration_laboratory.rb +8 -0
- data/lib/dcc/v3/comment.rb +8 -0
- data/lib/dcc/v3/common_elements.rb +11 -0
- data/lib/dcc/v3/condition.rb +8 -0
- data/lib/dcc/v3/configuration.rb +17 -0
- data/lib/dcc/v3/contact.rb +8 -0
- data/lib/dcc/v3/contact_not_strict.rb +8 -0
- data/lib/dcc/v3/core_data.rb +8 -0
- data/lib/dcc/v3/data.rb +8 -0
- data/lib/dcc/v3/digital_calibration_certificate.rb +8 -0
- data/lib/dcc/v3/equipment_class.rb +8 -0
- data/lib/dcc/v3/formula.rb +8 -0
- data/lib/dcc/v3/hash_type.rb +8 -0
- data/lib/dcc/v3/identification.rb +8 -0
- data/lib/dcc/v3/identifications.rb +8 -0
- data/lib/dcc/v3/influence_condition.rb +7 -0
- data/lib/dcc/v3/influence_condition_list.rb +8 -0
- data/lib/dcc/v3/item.rb +8 -0
- data/lib/dcc/v3/item_list.rb +8 -0
- data/lib/dcc/v3/list.rb +8 -0
- data/lib/dcc/v3/location.rb +8 -0
- data/lib/dcc/v3/measurement_meta_data.rb +8 -0
- data/lib/dcc/v3/measurement_meta_data_list.rb +8 -0
- data/lib/dcc/v3/measurement_result.rb +8 -0
- data/lib/dcc/v3/measurement_result_list.rb +8 -0
- data/lib/dcc/v3/measuring_equipment.rb +8 -0
- data/lib/dcc/v3/measuring_equipment_list.rb +8 -0
- data/lib/dcc/v3/namespace.rb +7 -0
- data/lib/dcc/v3/quantity.rb +49 -0
- data/lib/dcc/v3/ref_type_definition.rb +8 -0
- data/lib/dcc/v3/ref_type_definition_list.rb +8 -0
- data/lib/dcc/v3/resp_person.rb +8 -0
- data/lib/dcc/v3/resp_person_list.rb +8 -0
- data/lib/dcc/v3/result.rb +8 -0
- data/lib/dcc/v3/result_list.rb +8 -0
- data/lib/dcc/v3/rich_content.rb +8 -0
- data/lib/dcc/v3/software.rb +8 -0
- data/lib/dcc/v3/software_list.rb +8 -0
- data/lib/dcc/v3/statement.rb +8 -0
- data/lib/dcc/v3/statement_list.rb +8 -0
- data/lib/dcc/v3/string_with_lang.rb +8 -0
- data/lib/dcc/v3/text.rb +8 -0
- data/lib/dcc/v3/used_method.rb +8 -0
- data/lib/dcc/v3/used_method_list.rb +8 -0
- data/lib/dcc/v3/xml_blob.rb +8 -0
- data/lib/dcc/v3.rb +111 -0
- data/lib/dcc/validate/business_rules.rb +121 -0
- data/lib/dcc/validate/issue.rb +56 -0
- data/lib/dcc/validate/result.rb +105 -0
- data/lib/dcc/validate/schematron/profile.rb +64 -0
- data/lib/dcc/validate/schematron/rule.rb +49 -0
- data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +42 -0
- data/lib/dcc/validate/schematron/rules/base.rb +15 -0
- data/lib/dcc/validate/schematron/rules/date_range_check.rb +41 -0
- data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +61 -0
- data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +58 -0
- data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +53 -0
- data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +39 -0
- data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +82 -0
- data/lib/dcc/validate/schematron/rules/release_format_check.rb +44 -0
- data/lib/dcc/validate/schematron/rules/schema_version_check.rb +31 -0
- data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +58 -0
- data/lib/dcc/validate/schematron/rules/unit_format_check.rb +74 -0
- data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +65 -0
- data/lib/dcc/validate/schematron/rules/used_software_placement.rb +43 -0
- data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +42 -0
- data/lib/dcc/validate/schematron/rules.rb +30 -0
- data/lib/dcc/validate/schematron.rb +22 -0
- data/lib/dcc/validate/severity.rb +39 -0
- data/lib/dcc/validate/xsd.rb +97 -0
- data/lib/dcc/validate.rb +15 -0
- data/lib/dcc/version.rb +5 -0
- data/lib/dcc/versioned_parser.rb +48 -0
- data/lib/dcc.rb +141 -0
- 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,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("&", "&")
|
|
120
|
+
.gsub("<", "<")
|
|
121
|
+
.gsub(">", ">")
|
|
122
|
+
.gsub('"', """)
|
|
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
|