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,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module Dcc
|
|
6
|
+
module Convert
|
|
7
|
+
module Yaml
|
|
8
|
+
class << self
|
|
9
|
+
def call(dcc)
|
|
10
|
+
hash = ::Dcc::Convert::Json.xml_to_hash(dcc.to_xml)
|
|
11
|
+
::Dcc::Convert::Result.new(
|
|
12
|
+
format: :yaml,
|
|
13
|
+
payload: ::YAML.dump(hash),
|
|
14
|
+
source_class: dcc.class.name,
|
|
15
|
+
schema_version: dcc.schema_version.to_s,
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/dcc/convert.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::Convert` is the entry-point module for format converters. Each
|
|
4
|
+
# converter accepts a parsed DCC object tree and returns a `Dcc::Convert::Result`
|
|
5
|
+
# model that can be rendered as text, JSON, or YAML.
|
|
6
|
+
module Dcc
|
|
7
|
+
module Convert
|
|
8
|
+
autoload :Result, "dcc/convert/result"
|
|
9
|
+
autoload :Json, "dcc/convert/json"
|
|
10
|
+
autoload :Yaml, "dcc/convert/yaml"
|
|
11
|
+
autoload :Csv, "dcc/convert/csv"
|
|
12
|
+
autoload :Html, "dcc/convert/html"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Diff
|
|
5
|
+
# A single structural change between two DCC object trees.
|
|
6
|
+
Change = ::Struct.new(:path, :kind, :before, :after) do
|
|
7
|
+
def added? = kind == :add
|
|
8
|
+
def removed? = kind == :remove
|
|
9
|
+
def changed? = kind == :change
|
|
10
|
+
|
|
11
|
+
def to_s
|
|
12
|
+
case kind
|
|
13
|
+
when :add then "+ #{path}: #{after}"
|
|
14
|
+
when :remove then "- #{path}: #{before}"
|
|
15
|
+
when :change then "~ #{path}: #{before} -> #{after}"
|
|
16
|
+
else path
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Diff
|
|
5
|
+
# Result of comparing two DCC object trees.
|
|
6
|
+
class Result
|
|
7
|
+
attr_reader :changes
|
|
8
|
+
|
|
9
|
+
def initialize(changes:)
|
|
10
|
+
@changes = changes
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def additions
|
|
14
|
+
changes.select(&:added?)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def removals
|
|
18
|
+
changes.select(&:removed?)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def modifications
|
|
22
|
+
changes.select(&:changed?)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def empty?
|
|
26
|
+
changes.empty?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
if empty?
|
|
31
|
+
"(no structural changes)"
|
|
32
|
+
else
|
|
33
|
+
header = "#{changes.size} change(s): " \
|
|
34
|
+
"#{additions.size} added, #{removals.size} removed, #{modifications.size} changed"
|
|
35
|
+
([header] + changes.map(&:to_s)).join("\n")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_json(*_args)
|
|
40
|
+
require "json"
|
|
41
|
+
::JSON.pretty_generate(
|
|
42
|
+
additions: additions.map { |c| { path: c.path, value: c.after } },
|
|
43
|
+
removals: removals.map { |c| { path: c.path, value: c.before } },
|
|
44
|
+
modifications: modifications.map { |c| { path: c.path, before: c.before, after: c.after } },
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_yaml(*_args)
|
|
49
|
+
require "yaml"
|
|
50
|
+
{
|
|
51
|
+
additions: additions.map { |c| { path: c.path, value: c.after } },
|
|
52
|
+
removals: removals.map { |c| { path: c.path, value: c.before } },
|
|
53
|
+
modifications: modifications.map { |c| { path: c.path, before: c.before, after: c.after } },
|
|
54
|
+
}.to_yaml
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/dcc/diff.rb
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bigdecimal"
|
|
4
|
+
require "lutaml/model"
|
|
5
|
+
|
|
6
|
+
module Dcc
|
|
7
|
+
# `Dcc::Diff` compares two parsed DCC object trees and returns a
|
|
8
|
+
# `Dcc::Diff::Result` describing structural changes (counts, additions,
|
|
9
|
+
# removals, modifications). Identity is determined by `uniqueIdentifier`
|
|
10
|
+
# for the top-level DCC and by element `@id` / `@refId` for nested items.
|
|
11
|
+
module Diff
|
|
12
|
+
autoload :Result, "dcc/diff/result"
|
|
13
|
+
autoload :Change, "dcc/diff/change"
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
# @param a [Lutaml::Model::Serializable]
|
|
17
|
+
# @param b [Lutaml::Model::Serializable]
|
|
18
|
+
# @return [Dcc::Diff::Result]
|
|
19
|
+
def call(a, b)
|
|
20
|
+
changes = []
|
|
21
|
+
collect_differences(a, b, "", changes)
|
|
22
|
+
Result.new(changes: changes)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def collect_differences(a, b, path, changes)
|
|
28
|
+
# Both nil - no diff
|
|
29
|
+
return if a.nil? && b.nil?
|
|
30
|
+
# One is nil - add/remove
|
|
31
|
+
if a.nil?
|
|
32
|
+
changes << Change.new(path: path, kind: :add, before: nil, after: summarize(b))
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
if b.nil?
|
|
36
|
+
changes << Change.new(path: path, kind: :remove, before: summarize(a), after: nil)
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Both primitives - compare values
|
|
41
|
+
if primitive?(a) || primitive?(b)
|
|
42
|
+
if a != b
|
|
43
|
+
changes << Change.new(path: path, kind: :change, before: a, after: b)
|
|
44
|
+
end
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Both arrays
|
|
49
|
+
if a.is_a?(::Array) || b.is_a?(::Array)
|
|
50
|
+
max = [a.size, b.size].max
|
|
51
|
+
max.times do |i|
|
|
52
|
+
collect_differences(a[i], b[i], "#{path}[#{i}]", changes)
|
|
53
|
+
end
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Both objects
|
|
58
|
+
keys = (a.class.attributes.keys | b.class.attributes.keys)
|
|
59
|
+
keys.each do |key|
|
|
60
|
+
av = Dcc::TypeGuards.has_attribute?(a, key) ? a.public_send(key) : nil
|
|
61
|
+
bv = Dcc::TypeGuards.has_attribute?(b, key) ? b.public_send(key) : nil
|
|
62
|
+
collect_differences(av, bv, "#{path}/#{key}", changes)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def primitive?(value)
|
|
67
|
+
return true if value.nil?
|
|
68
|
+
return true if value.is_a?(::String) || value.is_a?(::Numeric) || value.is_a?(::Symbol)
|
|
69
|
+
return true if value == true || value == false
|
|
70
|
+
return true if value.is_a?(::Time) || value.is_a?(::Date) || value.is_a?(::DateTime)
|
|
71
|
+
return true if value.is_a?(::BigDecimal)
|
|
72
|
+
|
|
73
|
+
false
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def summarize(node)
|
|
77
|
+
return node.to_s if primitive?(node)
|
|
78
|
+
|
|
79
|
+
"#{node.class.name.split('::').last}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/dcc/error.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
# Base error class for all dcc gem errors. Subclasses live directly under
|
|
5
|
+
# `Dcc::Error::*` (e.g. `Dcc::ParseError`).
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
# Raised when an XML document cannot be parsed (malformed XML, encoding
|
|
9
|
+
# issues, IO errors).
|
|
10
|
+
class ParseError < Error; end
|
|
11
|
+
|
|
12
|
+
# Base class for all validation failures (XSD, Schematron, business rules).
|
|
13
|
+
class ValidationError < Error
|
|
14
|
+
attr_reader :issues
|
|
15
|
+
|
|
16
|
+
def initialize(message, issues: [])
|
|
17
|
+
@issues = issues
|
|
18
|
+
super(message)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Raised when an XSD validation fails or the XSD itself cannot be loaded.
|
|
23
|
+
class SchemaError < ValidationError; end
|
|
24
|
+
|
|
25
|
+
# Raised when XMLDSig signing or verification fails.
|
|
26
|
+
class SignatureError < Error; end
|
|
27
|
+
|
|
28
|
+
# Raised when a converter cannot produce the requested output format.
|
|
29
|
+
class ConversionError < Error; end
|
|
30
|
+
|
|
31
|
+
# Raised when an extractor encounters malformed content.
|
|
32
|
+
class ExtractionError < Error; end
|
|
33
|
+
|
|
34
|
+
# Raised when an XSLT transform fails.
|
|
35
|
+
class TransformError < Error; end
|
|
36
|
+
|
|
37
|
+
# Raised when an unsupported schema version is requested.
|
|
38
|
+
class UnknownVersionError < Error; end
|
|
39
|
+
|
|
40
|
+
# Raised when the builder DSL is used incorrectly.
|
|
41
|
+
class BuilderError < Error; end
|
|
42
|
+
|
|
43
|
+
# Raised when a soft dependency (`xmldsig`, `sinatra`, etc.) is required
|
|
44
|
+
# but not installed.
|
|
45
|
+
class MissingDependencyError < Error
|
|
46
|
+
attr_reader :gem_name, :feature
|
|
47
|
+
|
|
48
|
+
def initialize(gem_name:, feature:)
|
|
49
|
+
@gem_name = gem_name
|
|
50
|
+
@feature = feature
|
|
51
|
+
super("The '#{gem_name}' gem is required for #{feature}. Add it to your Gemfile or run: gem install #{gem_name}")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
require "set"
|
|
5
|
+
|
|
6
|
+
module Dcc
|
|
7
|
+
module Extract
|
|
8
|
+
# `Dcc::Extract::File` enumerates embedded files (`dcc:byteDataType`
|
|
9
|
+
# elements) inside a parsed DCC. Each entry carries the decoded binary
|
|
10
|
+
# payload, MIME type, file name, and the surrounding ring.
|
|
11
|
+
class File
|
|
12
|
+
attr_reader :name, :file_name, :mime_type, :data, :ring
|
|
13
|
+
|
|
14
|
+
# @param name [String, nil] human-readable name (typically from `dcc:name`).
|
|
15
|
+
# @param file_name [String, nil] original file name.
|
|
16
|
+
# @param mime_type [String, nil] MIME type (e.g. `text/plain`).
|
|
17
|
+
# @param data [String] binary payload (decoded from base64).
|
|
18
|
+
# @param ring [Symbol] one of `Dcc::Extract::Ring::ALL`.
|
|
19
|
+
def initialize(name:, file_name:, mime_type:, data:, ring:)
|
|
20
|
+
@name = name
|
|
21
|
+
@file_name = file_name
|
|
22
|
+
@mime_type = mime_type
|
|
23
|
+
@data = data
|
|
24
|
+
@ring = ring
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Boolean] true if the embedded payload is textual (text/*).
|
|
28
|
+
def text?
|
|
29
|
+
mime_type.to_s.start_with?("text/")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_s
|
|
33
|
+
"File #{file_name || '(unnamed)'} [#{ring}] (#{mime_type}, #{data.bytesize} bytes)"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
# Walk a parsed DCC and yield each embedded file in document order.
|
|
38
|
+
# Detects cycles (recursive list) via object_id tracking so the walk
|
|
39
|
+
# terminates for self-referential subtrees.
|
|
40
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
41
|
+
# @yieldparam [Dcc::Extract::File]
|
|
42
|
+
# @return [Array<Dcc::Extract::File>] the list when no block given.
|
|
43
|
+
def each(dcc, &block)
|
|
44
|
+
list = []
|
|
45
|
+
visited = ::Set.new
|
|
46
|
+
|
|
47
|
+
collect = lambda do |node, ring|
|
|
48
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
49
|
+
return if visited.include?(node.object_id)
|
|
50
|
+
|
|
51
|
+
visited << node.object_id
|
|
52
|
+
|
|
53
|
+
new_ring =
|
|
54
|
+
if admin_data?(node)
|
|
55
|
+
Ring::ADMINISTRATIVE_DATA
|
|
56
|
+
elsif measurement_list?(node)
|
|
57
|
+
Ring::MEASUREMENT_RESULTS
|
|
58
|
+
else
|
|
59
|
+
ring
|
|
60
|
+
end
|
|
61
|
+
list << build_file(node, new_ring) if byte_data?(node)
|
|
62
|
+
walk_children(node, new_ring, collect)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
collect.call(dcc, nil)
|
|
66
|
+
return list unless block_given?
|
|
67
|
+
|
|
68
|
+
list.each(&block)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
72
|
+
# @param index [Integer] zero-based index.
|
|
73
|
+
# @return [Dcc::Extract::File, nil]
|
|
74
|
+
def at(dcc, index)
|
|
75
|
+
each(dcc)[index]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
79
|
+
# @param ring [Symbol] one of Ring::ALL.
|
|
80
|
+
# @return [Array<Dcc::Extract::File>]
|
|
81
|
+
def in_ring(dcc, ring:)
|
|
82
|
+
each(dcc).select { |f| f.ring == ring }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def admin_data?(node)
|
|
88
|
+
node.class.name.end_with?("::AdministrativeData")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def measurement_list?(node)
|
|
92
|
+
node.class.name.end_with?("::MeasurementResultList")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def byte_data?(node)
|
|
96
|
+
node.class.name.end_with?("::ByteData")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Recursive walk: for each attribute, get its value and descend.
|
|
100
|
+
# Handles both single objects and collection arrays.
|
|
101
|
+
def walk_children(node, ring, walker)
|
|
102
|
+
node.class.attributes.each_key do |attr_name|
|
|
103
|
+
values = node.public_send(attr_name)
|
|
104
|
+
next if values.nil?
|
|
105
|
+
|
|
106
|
+
if values.is_a?(::Array)
|
|
107
|
+
walk_values(values, ring, walker)
|
|
108
|
+
elsif values.is_a?(::Lutaml::Model::Serializable)
|
|
109
|
+
walker.call(values, ring)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def walk_values(values, ring, walker)
|
|
115
|
+
Array(values).each do |v|
|
|
116
|
+
walker.call(v, ring) if v.is_a?(::Lutaml::Model::Serializable)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def build_file(byte_data, ring)
|
|
121
|
+
name = extract_name(byte_data.name)
|
|
122
|
+
new(
|
|
123
|
+
name: name,
|
|
124
|
+
file_name: byte_data.file_name,
|
|
125
|
+
mime_type: byte_data.mime_type,
|
|
126
|
+
data: ::Dcc::Type::Base64Binary.decode(byte_data.data_base64),
|
|
127
|
+
ring: ring || Ring::ADMINISTRATIVE_DATA,
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def extract_name(name_obj)
|
|
132
|
+
return nil unless name_obj
|
|
133
|
+
|
|
134
|
+
first = name_obj.content.first
|
|
135
|
+
return nil unless first
|
|
136
|
+
|
|
137
|
+
values = first.value
|
|
138
|
+
values.is_a?(::Array) ? values.first : values
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Extract
|
|
5
|
+
# The "Ring" of a `dcc:byteDataType` element: which section of the DCC
|
|
6
|
+
# document contained it. PTB defines these as `administrativeData`,
|
|
7
|
+
# `measurementResults`, `comment`, and `document`.
|
|
8
|
+
module Ring
|
|
9
|
+
ADMINISTRATIVE_DATA = :administrativeData
|
|
10
|
+
MEASUREMENT_RESULTS = :measurementResults
|
|
11
|
+
COMMENT = :comment
|
|
12
|
+
DOCUMENT = :document
|
|
13
|
+
|
|
14
|
+
ALL = [ADMINISTRATIVE_DATA, MEASUREMENT_RESULTS, COMMENT, DOCUMENT].freeze
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# @param symbol_or_string [Symbol, String, nil]
|
|
18
|
+
# @return [Symbol, nil] the canonical ring symbol.
|
|
19
|
+
def normalize(symbol_or_string)
|
|
20
|
+
return nil if symbol_or_string.nil?
|
|
21
|
+
|
|
22
|
+
sym = symbol_or_string.to_sym
|
|
23
|
+
ALL.include?(sym) ? sym : nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/dcc/extract.rb
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module I18n
|
|
5
|
+
# `Dcc::I18n::TextLookup` extracts the best-matching localized string
|
|
6
|
+
# from a `dcc:textType` block.
|
|
7
|
+
#
|
|
8
|
+
# Selection order:
|
|
9
|
+
# 1. Exact match for the requested language
|
|
10
|
+
# 2. First mandatory language declared in the DCC coreData
|
|
11
|
+
# 3. First used language declared in the DCC coreData
|
|
12
|
+
# 4. First content element regardless of language
|
|
13
|
+
# 5. nil if no content at all
|
|
14
|
+
module TextLookup
|
|
15
|
+
class << self
|
|
16
|
+
# @param text_obj [Object, nil] a parsed `dcc:textType` block.
|
|
17
|
+
# @param dcc [Object, nil] the parent DCC (used to read declared langs).
|
|
18
|
+
# @param lang [String, nil] requested ISO 639-1 code.
|
|
19
|
+
# @return [String, nil]
|
|
20
|
+
def call(text_obj, dcc: nil, lang: nil)
|
|
21
|
+
return nil unless text_obj && Dcc::TypeGuards.has_attribute?(text_obj, :content)
|
|
22
|
+
|
|
23
|
+
contents = Array(text_obj.content)
|
|
24
|
+
return nil if contents.empty?
|
|
25
|
+
|
|
26
|
+
return content_value(contents, lang) if lang
|
|
27
|
+
|
|
28
|
+
dcc_langs = declared_languages(dcc)
|
|
29
|
+
dcc_langs.each do |fallback|
|
|
30
|
+
val = content_value(contents, fallback)
|
|
31
|
+
return val if val
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
content_value(contents, nil)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def content_value(contents, lang)
|
|
40
|
+
match = if lang
|
|
41
|
+
contents.find { |c| c.lang.to_s == lang.to_s }
|
|
42
|
+
else
|
|
43
|
+
contents.first
|
|
44
|
+
end
|
|
45
|
+
return nil unless match
|
|
46
|
+
|
|
47
|
+
values = Array(match.value)
|
|
48
|
+
values.first&.to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def declared_languages(dcc)
|
|
52
|
+
return [] unless dcc && Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
53
|
+
|
|
54
|
+
admin = dcc.administrative_data
|
|
55
|
+
return [] unless admin && Dcc::TypeGuards.has_attribute?(admin, :core_data)
|
|
56
|
+
|
|
57
|
+
core = admin.core_data
|
|
58
|
+
return [] unless core
|
|
59
|
+
|
|
60
|
+
mandatory = Array(core.mandatory_lang_code_iso_639_1).map(&:to_s)
|
|
61
|
+
used = Array(core.used_lang_code_iso_639_1).map(&:to_s)
|
|
62
|
+
(mandatory + used).uniq
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/dcc/i18n.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::I18n` provides helpers for navigating multilingual DCC content.
|
|
4
|
+
# PTB DCC documents carry `usedLangCodeISO639_1` and
|
|
5
|
+
# `mandatoryLangCodeISO639_1` attributes; text blocks (`dcc:textType`)
|
|
6
|
+
# contain one `dcc:content` element per language. These helpers pick the
|
|
7
|
+
# best-matching language with a configurable fallback chain.
|
|
8
|
+
module Dcc
|
|
9
|
+
module I18n
|
|
10
|
+
autoload :TextLookup, "dcc/i18n/text_lookup"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Dcc
|
|
6
|
+
module Inspect
|
|
7
|
+
# `Dcc::Inspect::Report` summarizes a parsed DCC: counts, key
|
|
8
|
+
# identifiers, signature presence, and a human-readable `to_s` /
|
|
9
|
+
# `to_json` / `to_yaml`.
|
|
10
|
+
class Report < Lutaml::Model::Serializable
|
|
11
|
+
attribute :schema_version, :string
|
|
12
|
+
attribute :unique_identifier, :string
|
|
13
|
+
attribute :country_code, :string
|
|
14
|
+
attribute :item_count, :integer
|
|
15
|
+
attribute :measurement_result_count, :integer
|
|
16
|
+
attribute :quantity_count, :integer
|
|
17
|
+
attribute :list_count, :integer
|
|
18
|
+
attribute :embedded_file_count, :integer
|
|
19
|
+
attribute :languages, :string, collection: true
|
|
20
|
+
attribute :signer_count, :integer
|
|
21
|
+
attribute :has_signature, :boolean
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
lines = []
|
|
25
|
+
lines << "DCC Inspection Report"
|
|
26
|
+
lines << "=" * 50
|
|
27
|
+
lines << "Schema version: #{schema_version}"
|
|
28
|
+
lines << "Unique identifier: #{unique_identifier}"
|
|
29
|
+
lines << "Country: #{country_code}"
|
|
30
|
+
lines << "Languages: #{languages.join(', ')}" if languages.any?
|
|
31
|
+
lines << "Items: #{item_count}"
|
|
32
|
+
lines << "Measurement results: #{measurement_result_count}"
|
|
33
|
+
lines << "Quantities: #{quantity_count}"
|
|
34
|
+
lines << "Lists: #{list_count}"
|
|
35
|
+
lines << "Embedded files: #{embedded_file_count}"
|
|
36
|
+
lines << "Signers: #{signer_count}"
|
|
37
|
+
lines << "Has signature: #{has_signature ? 'yes' : 'no'}"
|
|
38
|
+
lines.join("\n")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_json(*_args)
|
|
42
|
+
require "json"
|
|
43
|
+
payload = {}
|
|
44
|
+
self.class.attributes.each_key { |k| payload[k] = public_send(k) }
|
|
45
|
+
::JSON.pretty_generate(payload)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_yaml(*_args)
|
|
49
|
+
require "yaml"
|
|
50
|
+
payload = {}
|
|
51
|
+
self.class.attributes.each_key { |k| payload[k] = public_send(k) }
|
|
52
|
+
payload.to_yaml
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class << self
|
|
56
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
57
|
+
# @return [Dcc::Inspect::Report]
|
|
58
|
+
def call(dcc)
|
|
59
|
+
admin = admin_data(dcc)
|
|
60
|
+
mr_list = measurement_results(dcc)
|
|
61
|
+
new(
|
|
62
|
+
schema_version: dcc.schema_version.to_s,
|
|
63
|
+
unique_identifier: core_data(dcc)&.unique_identifier,
|
|
64
|
+
country_code: core_data(dcc)&.country_code_iso_3166_1.to_s,
|
|
65
|
+
item_count: items(dcc).size,
|
|
66
|
+
measurement_result_count: mr_list.size,
|
|
67
|
+
quantity_count: count_quantities(mr_list),
|
|
68
|
+
list_count: count_lists(mr_list),
|
|
69
|
+
embedded_file_count: ::Dcc::Extract::File.each(dcc).size,
|
|
70
|
+
languages: lang_codes(dcc),
|
|
71
|
+
signer_count: resp_persons(dcc).size,
|
|
72
|
+
has_signature: signature_present?(dcc),
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def admin_data(dcc)
|
|
79
|
+
Dcc::TypeGuards.has_attribute?(dcc, :administrative_data) ? dcc.administrative_data : nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def core_data(dcc)
|
|
83
|
+
ad = admin_data(dcc)
|
|
84
|
+
ad && Dcc::TypeGuards.has_attribute?(ad, :core_data) ? ad.core_data : nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def items(dcc)
|
|
88
|
+
ad = admin_data(dcc)
|
|
89
|
+
return [] unless ad && Dcc::TypeGuards.has_attribute?(ad, :items) && ad.items && Dcc::TypeGuards.has_attribute?(ad.items, :item)
|
|
90
|
+
|
|
91
|
+
Array(ad.items.item)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def measurement_results(dcc)
|
|
95
|
+
Dcc::TypeGuards.has_attribute?(dcc, :measurement_results) && dcc.measurement_results && Dcc::TypeGuards.has_attribute?(dcc.measurement_results, :measurement_result) ?
|
|
96
|
+
Array(dcc.measurement_results.measurement_result) : []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def count_quantities(mr_list)
|
|
100
|
+
mr_list.sum do |mr|
|
|
101
|
+
next 0 unless Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results && Dcc::TypeGuards.has_attribute?(mr.results, :result)
|
|
102
|
+
|
|
103
|
+
Array(mr.results.result).sum do |r|
|
|
104
|
+
Dcc::TypeGuards.has_attribute?(r, :data) && r.data && Dcc::TypeGuards.has_attribute?(r.data, :quantity) ? Array(r.data.quantity).size : 0
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def count_lists(mr_list)
|
|
110
|
+
mr_list.sum do |mr|
|
|
111
|
+
next 0 unless Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results && Dcc::TypeGuards.has_attribute?(mr.results, :result)
|
|
112
|
+
|
|
113
|
+
Array(mr.results.result).sum do |r|
|
|
114
|
+
Dcc::TypeGuards.has_attribute?(r, :data) && r.data && Dcc::TypeGuards.has_attribute?(r.data, :list) ? Array(r.data.list).size : 0
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def lang_codes(dcc)
|
|
120
|
+
cd = core_data(dcc)
|
|
121
|
+
return [] unless cd
|
|
122
|
+
|
|
123
|
+
[cd.used_lang_code_iso_639_1, cd.mandatory_lang_code_iso_639_1].flatten.compact.map(&:to_s)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def resp_persons(dcc)
|
|
127
|
+
ad = admin_data(dcc)
|
|
128
|
+
return [] unless ad && Dcc::TypeGuards.has_attribute?(ad, :resp_persons) && ad.resp_persons && Dcc::TypeGuards.has_attribute?(ad.resp_persons, :resp_person)
|
|
129
|
+
|
|
130
|
+
Array(ad.resp_persons.resp_person)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def signature_present?(dcc)
|
|
134
|
+
Dcc::TypeGuards.has_attribute?(dcc, :document) && dcc.document
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|