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,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# `dcc:usedMethods` must appear somewhere (global, list, or quantity
|
|
9
|
+
# level). Error if missing everywhere.
|
|
10
|
+
class UsedMethodsPlacement < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
issues = []
|
|
13
|
+
return issues unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results)
|
|
14
|
+
|
|
15
|
+
mr_list = safe_attr(dcc.measurement_results, :measurement_result)
|
|
16
|
+
return issues if mr_list.empty?
|
|
17
|
+
|
|
18
|
+
any_used = mr_list.any? do |mr|
|
|
19
|
+
Dcc::TypeGuards.has_attribute?(mr, :used_methods) && !mr.used_methods.nil? ||
|
|
20
|
+
mr_has_descendant?(mr, :used_methods)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
issues << issue(
|
|
24
|
+
severity: :error,
|
|
25
|
+
message: "dcc:usedMethods is missing in every measurementResult and its descendants",
|
|
26
|
+
) unless any_used
|
|
27
|
+
|
|
28
|
+
issues
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def mr_has_descendant?(mr, attr_name)
|
|
34
|
+
return false unless Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results
|
|
35
|
+
|
|
36
|
+
result = safe_attr(mr.results, :result)
|
|
37
|
+
result.any? { |r| descendant_has?(r, attr_name) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def descendant_has?(node, attr_name)
|
|
41
|
+
return false unless node.is_a?(::Lutaml::Model::Serializable)
|
|
42
|
+
|
|
43
|
+
if Dcc::TypeGuards.has_attribute?(node, attr_name) && !node.public_send(attr_name).nil?
|
|
44
|
+
return true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
node.class.attributes.each_key do |attr|
|
|
48
|
+
value = node.public_send(attr)
|
|
49
|
+
next unless value.is_a?(::Array) || value.is_a?(::Lutaml::Model::Serializable)
|
|
50
|
+
|
|
51
|
+
Array(value).any? { |child| descendant_has?(child, attr_name) }
|
|
52
|
+
end
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def safe_attr(parent, attr)
|
|
57
|
+
return [] unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
58
|
+
|
|
59
|
+
Array(parent.public_send(attr))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# `dcc:usedSoftware` is recommended but only generates a warning.
|
|
9
|
+
class UsedSoftwarePlacement < Base
|
|
10
|
+
def severity
|
|
11
|
+
::Dcc::Validate::Severity::WARNING
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def check_on(dcc)
|
|
15
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results)
|
|
16
|
+
|
|
17
|
+
mr_list = safe_attr(dcc.measurement_results, :measurement_result)
|
|
18
|
+
return [] if mr_list.empty?
|
|
19
|
+
|
|
20
|
+
present = mr_list.any? do |mr|
|
|
21
|
+
Dcc::TypeGuards.has_attribute?(mr, :used_software) && !mr.used_software.nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
present ? [] : [
|
|
25
|
+
issue(
|
|
26
|
+
severity: :warning,
|
|
27
|
+
message: "dcc:usedSoftware is missing on every measurementResult",
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def safe_attr(parent, attr)
|
|
35
|
+
return [] unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
36
|
+
|
|
37
|
+
Array(parent.public_send(attr))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Validates spacing in `*XMLList` attributes and elements: single
|
|
9
|
+
# space between tokens, no leading/trailing space.
|
|
10
|
+
class XmlListSpacing < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
issues = []
|
|
13
|
+
check_string_list_attribute(dcc, issues, :ref_type, "refType")
|
|
14
|
+
issues
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def check_string_list_attribute(node, issues, attr, label)
|
|
20
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
21
|
+
|
|
22
|
+
if Dcc::TypeGuards.has_attribute?(node, attr)
|
|
23
|
+
value = node.public_send(attr)
|
|
24
|
+
value = value.to_s if value
|
|
25
|
+
if value && !value.empty? && (value.start_with?(" ") || value.end_with?(" ") || value.match?(/\s\s/))
|
|
26
|
+
issues << issue(
|
|
27
|
+
severity: :error,
|
|
28
|
+
message: "#{label} has invalid spacing: '#{value}'",
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
node.class.attributes.each_key do |a|
|
|
34
|
+
v = node.public_send(a)
|
|
35
|
+
Array(v).each { |child| check_string_list_attribute(child, issues, attr, label) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::Validate::Schematron::Rules` hosts the 14 pure-Ruby PTB Schematron
|
|
4
|
+
# rule classes. Each rule subclasses `Base` and overrides `#check_on(dcc)`.
|
|
5
|
+
#
|
|
6
|
+
# The parent module autoloads every rule lazily — no `require_relative`
|
|
7
|
+
# is used anywhere in this directory (project rule).
|
|
8
|
+
module Dcc
|
|
9
|
+
module Validate
|
|
10
|
+
module Schematron
|
|
11
|
+
module Rules
|
|
12
|
+
autoload :Base, "dcc/validate/schematron/rules/base"
|
|
13
|
+
autoload :UsedMethodsPlacement, "dcc/validate/schematron/rules/used_methods_placement"
|
|
14
|
+
autoload :UsedSoftwarePlacement, "dcc/validate/schematron/rules/used_software_placement"
|
|
15
|
+
autoload :InfluenceConditionsPlacement, "dcc/validate/schematron/rules/influence_conditions_placement"
|
|
16
|
+
autoload :SchemaVersionCheck, "dcc/validate/schematron/rules/schema_version_check"
|
|
17
|
+
autoload :IdRefIdLinking, "dcc/validate/schematron/rules/id_refid_linking"
|
|
18
|
+
autoload :IsoCodeValidation, "dcc/validate/schematron/rules/iso_code_validation"
|
|
19
|
+
autoload :DateRangeCheck, "dcc/validate/schematron/rules/date_range_check"
|
|
20
|
+
autoload :ReleaseFormatCheck, "dcc/validate/schematron/rules/release_format_check"
|
|
21
|
+
autoload :UncertaintyConsistency, "dcc/validate/schematron/rules/uncertainty_consistency"
|
|
22
|
+
autoload :UnitFormatCheck, "dcc/validate/schematron/rules/unit_format_check"
|
|
23
|
+
autoload :NonSiDeclaration, "dcc/validate/schematron/rules/non_si_declaration"
|
|
24
|
+
autoload :LanguageCodeDedup, "dcc/validate/schematron/rules/language_code_dedup"
|
|
25
|
+
autoload :XmlListSpacing, "dcc/validate/schematron/rules/xml_list_spacing"
|
|
26
|
+
autoload :AdministrativeDataCompleteness, "dcc/validate/schematron/rules/administrative_data_completeness"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::Validate::Schematron` is the public Schematron validator. Calling
|
|
4
|
+
# `Dcc::Validate::Schematron.call(dcc)` runs the entire PTB rule profile
|
|
5
|
+
# and returns a `Dcc::Validate::Result`.
|
|
6
|
+
module Dcc
|
|
7
|
+
module Validate
|
|
8
|
+
module Schematron
|
|
9
|
+
autoload :Rule, "dcc/validate/schematron/rule"
|
|
10
|
+
autoload :Profile, "dcc/validate/schematron/profile"
|
|
11
|
+
autoload :Rules, "dcc/validate/schematron/rules"
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
15
|
+
# @return [Dcc::Validate::Result]
|
|
16
|
+
def call(dcc)
|
|
17
|
+
Profile.call(dcc)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Validate
|
|
5
|
+
# Severity levels for validation issues. Matches PTB's Schematron roles
|
|
6
|
+
# plus the standard error/warning/info distinction.
|
|
7
|
+
module Severity
|
|
8
|
+
ERROR = :error
|
|
9
|
+
WARNING = :warning
|
|
10
|
+
INFO = :info
|
|
11
|
+
UNKNOWN = :unknown
|
|
12
|
+
|
|
13
|
+
ALL = [ERROR, WARNING, INFO, UNKNOWN].freeze
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
# Coerce a string/symbol to a canonical severity symbol.
|
|
17
|
+
# @return [Symbol]
|
|
18
|
+
def normalize(value)
|
|
19
|
+
return value if ALL.include?(value)
|
|
20
|
+
return UNKNOWN unless value
|
|
21
|
+
|
|
22
|
+
sym = value.to_s.downcase.sub(/\A(strict_)?/, "").to_sym
|
|
23
|
+
case sym
|
|
24
|
+
when :err then ERROR
|
|
25
|
+
when :warn then WARNING
|
|
26
|
+
when :information, :informational then INFO
|
|
27
|
+
else
|
|
28
|
+
ALL.include?(sym) ? sym : UNKNOWN
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [Boolean] whether issues at this severity fail validation.
|
|
33
|
+
def failing?(severity)
|
|
34
|
+
severity == ERROR
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
module Dcc
|
|
6
|
+
module Validate
|
|
7
|
+
# `Dcc::Validate::Xsd` validates DCC XML against one of the 12 bundled DCC
|
|
8
|
+
# schema versions. Auto-detects the version from the `schemaVersion`
|
|
9
|
+
# attribute when `version:` is `:auto` or nil.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# result = Dcc::Validate::Xsd.call(File.read("certificate.xml"))
|
|
13
|
+
# result.ok? # => true
|
|
14
|
+
# result.errors # => []
|
|
15
|
+
#
|
|
16
|
+
# result = Dcc::Validate::Xsd.call(xml, version: "3.3.0")
|
|
17
|
+
# result = Dcc::Validate::Xsd.call(xml, version: :auto)
|
|
18
|
+
module Xsd
|
|
19
|
+
SCHEMA_CACHE = {} # rubocop:disable Style/MutableConstant -- populated at runtime
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
# @param xml [String, IO] DCC XML to validate.
|
|
23
|
+
# @param version [String, Symbol, nil] DCC version or `:auto` for
|
|
24
|
+
# auto-detection. Defaults to `:auto`.
|
|
25
|
+
# @return [Dcc::Validate::Result]
|
|
26
|
+
def call(xml, version: :auto)
|
|
27
|
+
resolved = ::Dcc::Schema::Version.resolve_dcc(version, xml: xml)
|
|
28
|
+
schema = schema_for(resolved)
|
|
29
|
+
doc = parse_xml(xml)
|
|
30
|
+
errors = schema.validate(doc).map { |e| issue_from_nokogiri(e, resolved) }
|
|
31
|
+
|
|
32
|
+
::Dcc::Validate::Result.new(
|
|
33
|
+
issues: errors,
|
|
34
|
+
schema_version: resolved,
|
|
35
|
+
source: "xsd",
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def schema_for(version)
|
|
42
|
+
SCHEMA_CACHE[version] ||= load_schema(version)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def load_schema(version)
|
|
46
|
+
xsd_path = ::Dcc::Schema.path("dcc/v#{version}/dcc.xsd")
|
|
47
|
+
resolved = resolve_imports(xsd_path)
|
|
48
|
+
::Nokogiri::XML::Schema.new(resolved)
|
|
49
|
+
rescue ::Nokogiri::XML::SyntaxError => e
|
|
50
|
+
raise ::Dcc::SchemaError,
|
|
51
|
+
"Failed to load bundled DCC XSD v#{version}: #{e.message}",
|
|
52
|
+
e.backtrace
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Rewrite relative `schemaLocation` imports to absolute file:// URIs
|
|
56
|
+
# so libxml2 can resolve them regardless of the process CWD. Nokogiri
|
|
57
|
+
# does not expose a base-URI option for `Schema.new`.
|
|
58
|
+
def resolve_imports(xsd_path)
|
|
59
|
+
base_dir = ::File.dirname(xsd_path)
|
|
60
|
+
content = ::File.read(xsd_path)
|
|
61
|
+
content.gsub(/schemaLocation\s*=\s*"([^"]+)"/) do |_match|
|
|
62
|
+
relative = ::Regexp.last_match(1)
|
|
63
|
+
next %{schemaLocation="#{relative}"} if relative.start_with?("http", "file://")
|
|
64
|
+
|
|
65
|
+
absolute = ::File.expand_path(relative, base_dir)
|
|
66
|
+
%{schemaLocation="file://#{absolute}"}
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def parse_xml(xml)
|
|
71
|
+
xml_string = ::Dcc.read_input(xml)
|
|
72
|
+
::Nokogiri::XML(xml_string) { |c| c.strict }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def issue_from_nokogiri(nokogiri_error, version)
|
|
76
|
+
::Dcc::Validate::Issue.build(
|
|
77
|
+
severity: classify(nokogiri_error),
|
|
78
|
+
message: nokogiri_error.message,
|
|
79
|
+
code: "dcc.xsd.#{version}",
|
|
80
|
+
line: nokogiri_error.line,
|
|
81
|
+
column: nokogiri_error.column,
|
|
82
|
+
source: "xsd",
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def classify(nokogiri_error)
|
|
87
|
+
# libxml2 levels: 1 = WARNING, 2 = ERROR, 3 = FATAL.
|
|
88
|
+
case nokogiri_error.level
|
|
89
|
+
when 2, 3 then ::Dcc::Validate::Severity::ERROR
|
|
90
|
+
when 1 then ::Dcc::Validate::Severity::WARNING
|
|
91
|
+
else ::Dcc::Validate::Severity::INFO
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/dcc/validate.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::Validate` is the entry-point module for all validation services:
|
|
4
|
+
# XSD, Schematron, and Ruby-side business rules. Each service returns a
|
|
5
|
+
# `Dcc::Validate::Result` model that can be rendered as text, JSON, or YAML.
|
|
6
|
+
module Dcc
|
|
7
|
+
module Validate
|
|
8
|
+
autoload :Result, "dcc/validate/result"
|
|
9
|
+
autoload :Issue, "dcc/validate/issue"
|
|
10
|
+
autoload :Severity, "dcc/validate/severity"
|
|
11
|
+
autoload :Xsd, "dcc/validate/xsd"
|
|
12
|
+
autoload :Schematron, "dcc/validate/schematron"
|
|
13
|
+
autoload :BusinessRules, "dcc/validate/business_rules"
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/dcc/version.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# `Dcc::VersionedParser` is mixed into each major-version module
|
|
4
|
+
# (`Dcc::V2`, `Dcc::V3`, `Dcc::Si::V1`, `Dcc::Si::V2`) to provide a uniform
|
|
5
|
+
# `.parse(input, context:, register:)` entry point that delegates to
|
|
6
|
+
# `Lutaml::Model::GlobalContext` for type resolution.
|
|
7
|
+
#
|
|
8
|
+
# The version module must:
|
|
9
|
+
# 1. `extend Dcc::VersionedParser`
|
|
10
|
+
# 2. Define `self::ROOT_ELEMENT_TAG` — the XML element name to resolve
|
|
11
|
+
# (e.g. `"digitalCalibrationCertificate"`).
|
|
12
|
+
# 3. Define `self::Configuration` — a module that extends
|
|
13
|
+
# `Dcc::ContextConfiguration` and declares `CONTEXT_ID`.
|
|
14
|
+
module Dcc
|
|
15
|
+
module VersionedParser
|
|
16
|
+
# Parse an XML document into the version's typed object tree.
|
|
17
|
+
#
|
|
18
|
+
# @param input [String, IO] XML string or readable IO.
|
|
19
|
+
# @param context [Symbol, String, nil] substitution context.
|
|
20
|
+
# @param register [Symbol, String, nil] deprecated alias for `context`.
|
|
21
|
+
# @return [Lutaml::Model::Serializable] parsed root element.
|
|
22
|
+
def parse(input, context: ::Dcc::UNSPECIFIED_CONTEXT, register: nil)
|
|
23
|
+
context_id = resolve_context_id(context, register)
|
|
24
|
+
root_class = Lutaml::Model::GlobalContext.resolve_type(
|
|
25
|
+
root_element_symbol,
|
|
26
|
+
context_id,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
xml = ::Dcc.read_input(input)
|
|
30
|
+
root_class.from_xml(xml, register: context_id)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def resolve_context_id(context, register)
|
|
36
|
+
::Dcc::ContextOptions.normalize_context_option(
|
|
37
|
+
context: context,
|
|
38
|
+
register: register,
|
|
39
|
+
default_context: self::Configuration.default_context_id,
|
|
40
|
+
warning_source: "#{name}.parse",
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def root_element_symbol
|
|
45
|
+
self.const_get(:ROOT_ELEMENT_TAG).to_sym
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/dcc.rb
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require "lutaml/xml"
|
|
5
|
+
require "mml"
|
|
6
|
+
|
|
7
|
+
Lutaml::Model::Config.xml_adapter_type = :nokogiri
|
|
8
|
+
|
|
9
|
+
# Top-level namespace for the dcc gem.
|
|
10
|
+
#
|
|
11
|
+
# Dcc provides a fully typed Ruby object model for PTB Digital Calibration
|
|
12
|
+
# Certificates (DCC) and D-SI quantity documents. See README.adoc for an
|
|
13
|
+
# overview and QUICKSTART.
|
|
14
|
+
module Dcc
|
|
15
|
+
SUPPORTED_VERSIONS = [2, 3].freeze
|
|
16
|
+
|
|
17
|
+
# Sentinel value used to distinguish "no context supplied" from "context
|
|
18
|
+
# supplied as nil". Defined eagerly so callers can reference it without
|
|
19
|
+
# triggering autoload.
|
|
20
|
+
UNSPECIFIED_CONTEXT = Object.new.freeze
|
|
21
|
+
|
|
22
|
+
autoload :VERSION, "dcc/version"
|
|
23
|
+
# Errors are eagerly required so `Dcc::ParseError` etc. are always
|
|
24
|
+
# available without triggering autoload on first reference.
|
|
25
|
+
require "dcc/error"
|
|
26
|
+
|
|
27
|
+
autoload :Namespace, "dcc/namespace"
|
|
28
|
+
autoload :Type, "dcc/type"
|
|
29
|
+
autoload :ContextConfiguration, "dcc/context_configuration"
|
|
30
|
+
autoload :ContextOptions, "dcc/context_options"
|
|
31
|
+
autoload :VersionedParser, "dcc/versioned_parser"
|
|
32
|
+
autoload :CommonElements, "dcc/common_elements"
|
|
33
|
+
autoload :Base, "dcc/base"
|
|
34
|
+
autoload :Schema, "dcc/schema"
|
|
35
|
+
autoload :Builder, "dcc/builder"
|
|
36
|
+
autoload :Convert, "dcc/convert"
|
|
37
|
+
autoload :Diff, "dcc/diff"
|
|
38
|
+
autoload :Extract, "dcc/extract"
|
|
39
|
+
autoload :Inspect, "dcc/inspect"
|
|
40
|
+
autoload :Migrate, "dcc/migrate"
|
|
41
|
+
autoload :QuantityFormat, "dcc/quantity_format"
|
|
42
|
+
autoload :QuantityMath, "dcc/quantity_math"
|
|
43
|
+
autoload :Signature, "dcc/signature"
|
|
44
|
+
autoload :Transform, "dcc/transform"
|
|
45
|
+
autoload :Validate, "dcc/validate"
|
|
46
|
+
autoload :Server, "dcc/server"
|
|
47
|
+
autoload :I18n, "dcc/i18n"
|
|
48
|
+
autoload :Plugin, "dcc/plugin"
|
|
49
|
+
autoload :TypeGuards, "dcc/type_guards"
|
|
50
|
+
autoload :Si, "dcc/si"
|
|
51
|
+
|
|
52
|
+
autoload :V2, "dcc/v2"
|
|
53
|
+
autoload :V3, "dcc/v3"
|
|
54
|
+
|
|
55
|
+
module Cli
|
|
56
|
+
autoload :Cli, "dcc/cli/cli"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class << self
|
|
60
|
+
# Parse a DCC XML document and return a typed object tree.
|
|
61
|
+
#
|
|
62
|
+
# @param input [String, IO] XML string or readable IO.
|
|
63
|
+
# @param version [Integer, nil] Major DCC version (2 or 3). Auto-detected
|
|
64
|
+
# from the `schemaVersion` attribute when nil.
|
|
65
|
+
# @param context [Symbol, nil] Substitution context (e.g. `:dcc_v3_4`).
|
|
66
|
+
# @param register [Symbol, nil] Alias for `context` (mml-compatible API).
|
|
67
|
+
# @return [Dcc::V2::DigitalCalibrationCertificate, Dcc::V3::DigitalCalibrationCertificate]
|
|
68
|
+
def parse(input, version: nil, context: nil, register: nil)
|
|
69
|
+
load_all!
|
|
70
|
+
resolved = version || detect_version(input)
|
|
71
|
+
parser_for(resolved).parse(input, context: context, register: register)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Build a new DCC programmatically using the builder DSL.
|
|
75
|
+
# @yield [Dcc::Builder::Session] builder session
|
|
76
|
+
# @param version [Integer, nil] major DCC version (default: 3).
|
|
77
|
+
def build(version: 3, &block)
|
|
78
|
+
Builder.call(version: version, &block)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Migrate a parsed DCC object from one schema version to another.
|
|
82
|
+
# @param dcc [Dcc::V2::DigitalCalibrationCertificate, Dcc::V3::DigitalCalibrationCertificate]
|
|
83
|
+
# @param from [String] source version, e.g. "2.3.0".
|
|
84
|
+
# @param to [String] target version, e.g. "3.3.0".
|
|
85
|
+
def migrate(dcc, from:, to:)
|
|
86
|
+
Migrate.call(dcc, from: from, to: to)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Return the parser module for the given major version.
|
|
90
|
+
# @param version [Integer] 2 or 3.
|
|
91
|
+
# @return [Module] Dcc::V2 or Dcc::V3.
|
|
92
|
+
def parser_for(version)
|
|
93
|
+
case version.to_i
|
|
94
|
+
when 2 then V2
|
|
95
|
+
when 3 then V3
|
|
96
|
+
else
|
|
97
|
+
raise UnknownVersionError, "Unsupported DCC version: #{version.inspect} (expected 2 or 3)"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Detect the DCC major version from an XML document's `schemaVersion` attribute.
|
|
102
|
+
# @param input [String, IO]
|
|
103
|
+
# @return [Integer] 2 or 3.
|
|
104
|
+
def detect_version(input)
|
|
105
|
+
str = read_input(input)
|
|
106
|
+
match = str.match(/schemaVersion\s*=\s*["'](\d+)\./)
|
|
107
|
+
major = match && match[1] ? match[1].to_i : 3
|
|
108
|
+
major == 2 ? 2 : 3
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Read an input that may be a String or an IO-like object.
|
|
112
|
+
# Uses explicit type checks per project rule (no `respond_to?`).
|
|
113
|
+
# @param input [String, IO, StringIO, File, Tempfile]
|
|
114
|
+
# @return [String]
|
|
115
|
+
def read_input(input)
|
|
116
|
+
return input.read if io_like?(input)
|
|
117
|
+
|
|
118
|
+
input.to_s
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @return [Boolean] whether the input is an IO-like stream we support.
|
|
122
|
+
def io_like?(input)
|
|
123
|
+
!!(input.is_a?(::IO) ||
|
|
124
|
+
input.is_a?(::StringIO) ||
|
|
125
|
+
input.is_a?(::File) ||
|
|
126
|
+
(defined?(::Tempfile) && input.is_a?(::Tempfile)))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Eager-load every version context (DCC + D-SI) so symbol type
|
|
130
|
+
# references in the base modules resolve correctly. Called automatically
|
|
131
|
+
# on first `Dcc.parse`. Safe to call multiple times.
|
|
132
|
+
# @return [true]
|
|
133
|
+
def load_all!
|
|
134
|
+
V2.load_all!
|
|
135
|
+
V3.load_all!
|
|
136
|
+
Si::V1.load_all!
|
|
137
|
+
Si::V2.load_all!
|
|
138
|
+
true
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|