dcc 0.2.0 → 0.2.1
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 +4 -4
- data/.github/workflows/ci.yml +19 -0
- data/.github/workflows/release.yml +28 -0
- data/.gitignore +4 -0
- data/.rubocop_todo.yml +560 -10
- data/CHANGELOG.adoc +34 -1
- data/CONTRIBUTING.adoc +8 -1
- data/Gemfile +5 -7
- data/README.adoc +162 -7
- data/dcc.gemspec +8 -2
- data/docs/schema-versions.adoc +20 -7
- data/examples/build_minimal_dcc.rb +0 -0
- data/examples/convert_all_formats.rb +2 -1
- data/examples/parse_and_inspect.rb +0 -0
- data/examples/quantity_math_demo.rb +7 -7
- data/examples/validate_full.rb +1 -1
- data/lib/dcc/base/calibration_laboratory.rb +2 -1
- data/lib/dcc/base/condition.rb +5 -2
- data/lib/dcc/base/core_data.rb +8 -3
- data/lib/dcc/base/formula.rb +3 -3
- data/lib/dcc/base/identification.rb +6 -3
- data/lib/dcc/base/mathml.rb +33 -0
- data/lib/dcc/base/quantity.rb +2 -1
- data/lib/dcc/base/resp_person.rb +4 -2
- data/lib/dcc/base/text.rb +1 -1
- data/lib/dcc/base.rb +2 -1
- data/lib/dcc/builder/dsl.rb +1 -1
- data/lib/dcc/builder/session.rb +16 -14
- data/lib/dcc/builder.rb +3 -3
- data/lib/dcc/cli/cli.rb +36 -18
- data/lib/dcc/cli/formatters.rb +35 -7
- data/lib/dcc/cli.rb +1 -1
- data/lib/dcc/context_configuration.rb +2 -1
- data/lib/dcc/context_options.rb +4 -2
- data/lib/dcc/convert/csv.rb +27 -9
- data/lib/dcc/convert/html.rb +26 -110
- data/lib/dcc/convert/json.rb +10 -7
- data/lib/dcc/convert/liquid_filters.rb +58 -0
- data/lib/dcc/convert/result.rb +1 -1
- data/lib/dcc/convert/templates/report.liquid +250 -0
- data/lib/dcc/convert/yaml.rb +1 -1
- data/lib/dcc/convert.rb +1 -0
- data/lib/dcc/diff/change.rb +1 -1
- data/lib/dcc/diff/result.rb +8 -4
- data/lib/dcc/diff.rb +43 -11
- data/lib/dcc/error.rb +7 -0
- data/lib/dcc/extract/file.rb +3 -4
- data/lib/dcc/extract/ring.rb +1 -1
- data/lib/dcc/extract.rb +1 -1
- data/lib/dcc/i18n/text_lookup.rb +8 -4
- data/lib/dcc/i18n.rb +1 -1
- data/lib/dcc/inspect/report.rb +51 -14
- data/lib/dcc/inspect.rb +1 -1
- data/lib/dcc/migrate/route.rb +44 -0
- data/lib/dcc/migrate/v2_to_v3.rb +445 -0
- data/lib/dcc/migrate.rb +130 -26
- data/lib/dcc/plugin/base.rb +64 -0
- data/lib/dcc/plugin/registry.rb +7 -2
- data/lib/dcc/plugin.rb +6 -2
- data/lib/dcc/quantity_format/formatter.rb +16 -10
- data/lib/dcc/quantity_format.rb +1 -1
- data/lib/dcc/quantity_math/quantity.rb +1 -1
- data/lib/dcc/quantity_math/real.rb +6 -6
- data/lib/dcc/quantity_math.rb +1 -1
- data/lib/dcc/schema/version.rb +2 -2
- data/lib/dcc/server/app.html +282 -0
- data/lib/dcc/server/app.rb +171 -87
- data/lib/dcc/server/demo_cert.xml +244 -0
- data/lib/dcc/server/storage/entry.rb +1 -1
- data/lib/dcc/server/storage/memory.rb +3 -2
- data/lib/dcc/server/storage.rb +1 -1
- data/lib/dcc/server.rb +1 -1
- data/lib/dcc/si/base/complex.rb +1 -1
- data/lib/dcc/si/base/complex_list_xml_list.rb +1 -1
- data/lib/dcc/si/base/constant.rb +1 -1
- data/lib/dcc/si/base/coverage_interval.rb +36 -0
- data/lib/dcc/si/base/coverage_interval_mu.rb +1 -1
- data/lib/dcc/si/base/expanded_mu.rb +1 -1
- data/lib/dcc/si/base/expanded_unc.rb +34 -0
- data/lib/dcc/si/base/expanded_unc_xml_list.rb +3 -2
- data/lib/dcc/si/base/hybrid.rb +3 -2
- data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +1 -1
- data/lib/dcc/si/base/real.rb +13 -3
- data/lib/dcc/si/base/real_list_xml_list.rb +5 -3
- data/lib/dcc/si/base/si_list.rb +3 -2
- data/lib/dcc/si/base/standard_mu.rb +1 -1
- data/lib/dcc/si/base.rb +5 -2
- data/lib/dcc/si/v1/coverage_interval.rb +8 -0
- data/lib/dcc/si/v1/expanded_unc.rb +1 -16
- data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +2 -1
- data/lib/dcc/si/v1.rb +5 -2
- data/lib/dcc/si/v2/coverage_interval.rb +8 -0
- data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +4 -2
- data/lib/dcc/si/v2/expanded_mu_xml_list.rb +2 -1
- data/lib/dcc/si/v2/expanded_unc.rb +8 -0
- data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +2 -1
- data/lib/dcc/si/v2.rb +8 -3
- data/lib/dcc/signature/result.rb +2 -2
- data/lib/dcc/signature/signer.rb +31 -18
- data/lib/dcc/signature/verifier.rb +23 -21
- data/lib/dcc/signature.rb +1 -1
- data/lib/dcc/transform/result.rb +1 -1
- data/lib/dcc/transform/xslt.rb +22 -12
- data/lib/dcc/transform.rb +5 -4
- data/lib/dcc/type/base64_binary.rb +5 -3
- data/lib/dcc/type/decimal_xml_list.rb +99 -13
- data/lib/dcc/type/iso_country_code.rb +3 -2
- data/lib/dcc/type/iso_language_code.rb +3 -2
- data/lib/dcc/type/schema_version.rb +3 -2
- data/lib/dcc/type/si_unit.rb +3 -2
- data/lib/dcc/type_guards.rb +3 -3
- data/lib/dcc/v2/calibration_laboratory.rb +2 -1
- data/lib/dcc/v2/condition.rb +22 -1
- data/lib/dcc/v2/configuration.rb +1 -1
- data/lib/dcc/v2/digital_calibration_certificate.rb +2 -1
- data/lib/dcc/v2/identification.rb +14 -1
- data/lib/dcc/v2/mathml.rb +8 -0
- data/lib/dcc/v2/measurement_meta_data_list.rb +2 -1
- data/lib/dcc/v2/quantity.rb +4 -2
- data/lib/dcc/v2.rb +4 -2
- data/lib/dcc/v3/calibration_laboratory.rb +2 -1
- data/lib/dcc/v3/configuration.rb +1 -1
- data/lib/dcc/v3/digital_calibration_certificate.rb +2 -1
- data/lib/dcc/v3/mathml.rb +8 -0
- data/lib/dcc/v3/measurement_meta_data_list.rb +2 -1
- data/lib/dcc/v3/quantity.rb +4 -2
- data/lib/dcc/v3.rb +12 -2
- data/lib/dcc/validate/business_rules.rb +23 -9
- data/lib/dcc/validate/issue.rb +2 -1
- data/lib/dcc/validate/result.rb +6 -4
- data/lib/dcc/validate/schematron/profile.rb +73 -18
- data/lib/dcc/validate/schematron/rule.rb +13 -3
- data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +11 -4
- data/lib/dcc/validate/schematron/rules/base.rb +1 -2
- data/lib/dcc/validate/schematron/rules/date_range_check.rb +11 -5
- data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +0 -3
- data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +22 -12
- data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +31 -14
- data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +12 -5
- data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +7 -4
- data/lib/dcc/validate/schematron/rules/release_format_check.rb +7 -4
- data/lib/dcc/validate/schematron/rules/schema_version_check.rb +13 -9
- data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +39 -10
- data/lib/dcc/validate/schematron/rules/unit_format_check.rb +2 -3
- data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +15 -10
- data/lib/dcc/validate/schematron/rules/used_software_placement.rb +15 -10
- data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +4 -3
- data/lib/dcc/validate/schematron/rules.rb +28 -14
- data/lib/dcc/validate/schematron.rb +1 -1
- data/lib/dcc/validate/xsd.rb +9 -3
- data/lib/dcc/validate.rb +1 -1
- data/lib/dcc/version.rb +1 -1
- data/lib/dcc/versioned_parser.rb +1 -1
- data/lib/dcc.rb +55 -7
- data/sample_dcc.xml +140 -0
- data/web/index.html +12 -0
- data/web/package-lock.json +1599 -0
- data/web/package.json +22 -0
- data/web/src/App.vue +349 -0
- data/web/src/lib/builder.ts +171 -0
- data/web/src/lib/dcc.ts +338 -0
- data/web/src/lib/units.json +5581 -0
- data/web/src/main.ts +5 -0
- data/web/src/style.css +27 -0
- data/web/tsconfig.json +15 -0
- data/web/vite.config.ts +14 -0
- metadata +125 -9
|
@@ -15,37 +15,92 @@ module Dcc
|
|
|
15
15
|
# result.ok? # => true
|
|
16
16
|
# result.issues.size # => 0
|
|
17
17
|
class Profile
|
|
18
|
+
# The rules shipped with the gem, in execution order.
|
|
19
|
+
DEFAULT_RULES = [
|
|
20
|
+
Rules::UsedMethodsPlacement,
|
|
21
|
+
Rules::UsedSoftwarePlacement,
|
|
22
|
+
Rules::InfluenceConditionsPlacement,
|
|
23
|
+
Rules::SchemaVersionCheck,
|
|
24
|
+
Rules::IdRefIdLinking,
|
|
25
|
+
Rules::IsoCodeValidation,
|
|
26
|
+
Rules::DateRangeCheck,
|
|
27
|
+
Rules::ReleaseFormatCheck,
|
|
28
|
+
Rules::UncertaintyConsistency,
|
|
29
|
+
Rules::UnitFormatCheck,
|
|
30
|
+
Rules::NonSiDeclaration,
|
|
31
|
+
Rules::LanguageCodeDedup,
|
|
32
|
+
Rules::XmlListSpacing,
|
|
33
|
+
].freeze
|
|
34
|
+
private_constant :DEFAULT_RULES
|
|
35
|
+
|
|
18
36
|
attr_reader :dcc, :rules
|
|
19
37
|
|
|
38
|
+
# Plugin validators are read here, not at class-definition time, so
|
|
39
|
+
# a plugin loaded after this class still takes effect. Frozen because
|
|
40
|
+
# `attr_reader :rules` hands the array straight to callers.
|
|
20
41
|
def initialize(dcc)
|
|
21
42
|
@dcc = dcc
|
|
22
|
-
@
|
|
23
|
-
|
|
24
|
-
Rules::UsedSoftwarePlacement,
|
|
25
|
-
Rules::InfluenceConditionsPlacement,
|
|
26
|
-
Rules::SchemaVersionCheck,
|
|
27
|
-
Rules::IdRefIdLinking,
|
|
28
|
-
Rules::IsoCodeValidation,
|
|
29
|
-
Rules::DateRangeCheck,
|
|
30
|
-
Rules::ReleaseFormatCheck,
|
|
31
|
-
Rules::UncertaintyConsistency,
|
|
32
|
-
Rules::UnitFormatCheck,
|
|
33
|
-
Rules::NonSiDeclaration,
|
|
34
|
-
Rules::LanguageCodeDedup,
|
|
35
|
-
Rules::XmlListSpacing,
|
|
36
|
-
]
|
|
43
|
+
@plugin_rules = ::Dcc::Plugin.all(:validators).freeze
|
|
44
|
+
@rules = (DEFAULT_RULES + @plugin_rules).freeze
|
|
37
45
|
end
|
|
38
46
|
|
|
39
47
|
# Run all rules and return a `Dcc::Validate::Result`.
|
|
48
|
+
#
|
|
49
|
+
# Built-in rules fail fast: a crash there is a bug in this gem. A
|
|
50
|
+
# plugin rule is third-party code, so its failure is contained and
|
|
51
|
+
# reported as an error issue naming the rule class — one broken
|
|
52
|
+
# plugin must not cost the caller every built-in finding.
|
|
40
53
|
def call
|
|
41
54
|
issues = []
|
|
42
55
|
rules.each do |rule_class|
|
|
43
|
-
issues.concat(
|
|
56
|
+
issues.concat(
|
|
57
|
+
if @plugin_rules.include?(rule_class)
|
|
58
|
+
run_plugin_rule(rule_class)
|
|
59
|
+
else
|
|
60
|
+
rule_class.new.check_on(dcc)
|
|
61
|
+
end,
|
|
62
|
+
)
|
|
44
63
|
end
|
|
45
64
|
|
|
46
65
|
::Dcc::Validate::Result.new(
|
|
47
66
|
issues: issues,
|
|
48
|
-
schema_version: Dcc::TypeGuards.has_attribute?(dcc,
|
|
67
|
+
schema_version: if Dcc::TypeGuards.has_attribute?(dcc,
|
|
68
|
+
:schema_version)
|
|
69
|
+
dcc.schema_version.to_s
|
|
70
|
+
end,
|
|
71
|
+
source: "schematron",
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Run one plugin-supplied rule with fault isolation. Instantiation
|
|
78
|
+
# and #check_on both run inside the rescue, and a non-Array return
|
|
79
|
+
# (nil included) is reported rather than passed to Array#concat.
|
|
80
|
+
#
|
|
81
|
+
# @param rule_class [Class]
|
|
82
|
+
# @return [Array<Dcc::Validate::Issue>]
|
|
83
|
+
def run_plugin_rule(rule_class)
|
|
84
|
+
result = rule_class.new.check_on(dcc)
|
|
85
|
+
return result if result.is_a?(::Array)
|
|
86
|
+
|
|
87
|
+
[plugin_failure_issue(
|
|
88
|
+
rule_class,
|
|
89
|
+
"returned #{result.inspect} instead of an Array of issues",
|
|
90
|
+
)]
|
|
91
|
+
rescue ::StandardError => e
|
|
92
|
+
[plugin_failure_issue(rule_class, "raised #{e.class}: #{e.message}")]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @param rule_class [Class]
|
|
96
|
+
# @param detail [String]
|
|
97
|
+
# @return [Dcc::Validate::Issue]
|
|
98
|
+
def plugin_failure_issue(rule_class, detail)
|
|
99
|
+
name = rule_class.name || rule_class.inspect
|
|
100
|
+
::Dcc::Validate::Issue.build(
|
|
101
|
+
severity: ::Dcc::Validate::Severity::ERROR,
|
|
102
|
+
message: "plugin validator #{name} #{detail}",
|
|
103
|
+
code: "dcc.schematron.plugin_failure",
|
|
49
104
|
source: "schematron",
|
|
50
105
|
)
|
|
51
106
|
end
|
|
@@ -61,4 +116,4 @@ module Dcc
|
|
|
61
116
|
end
|
|
62
117
|
end
|
|
63
118
|
end
|
|
64
|
-
end
|
|
119
|
+
end
|
|
@@ -13,9 +13,18 @@ module Dcc
|
|
|
13
13
|
::Dcc::Validate::Severity::ERROR
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# A plugin can register an anonymous rule class, whose `name` is nil.
|
|
17
|
+
# Falling back keeps one such rule from taking the whole run down and
|
|
18
|
+
# losing every issue the built-in rules already found.
|
|
19
|
+
#
|
|
16
20
|
# @return [String] rule code used in `Issue#code`.
|
|
17
21
|
def code
|
|
18
|
-
|
|
22
|
+
class_name = self.class.name
|
|
23
|
+
return "dcc.schematron.anonymous" unless class_name
|
|
24
|
+
|
|
25
|
+
"dcc.schematron.#{class_name.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(
|
|
26
|
+
/([a-z\d])([A-Z])/, '\1_\2'
|
|
27
|
+
).downcase}"
|
|
19
28
|
end
|
|
20
29
|
|
|
21
30
|
# @param dcc [Lutaml::Model::Serializable]
|
|
@@ -32,7 +41,8 @@ module Dcc
|
|
|
32
41
|
# Override in subclasses to traverse the model tree.
|
|
33
42
|
end
|
|
34
43
|
|
|
35
|
-
def issue(severity:, message:, line: nil, column: nil, path: nil,
|
|
44
|
+
def issue(severity:, message:, line: nil, column: nil, path: nil,
|
|
45
|
+
source: "schematron")
|
|
36
46
|
::Dcc::Validate::Issue.build(
|
|
37
47
|
severity: severity,
|
|
38
48
|
message: message,
|
|
@@ -46,4 +56,4 @@ module Dcc
|
|
|
46
56
|
end
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
|
-
end
|
|
59
|
+
end
|
|
@@ -19,13 +19,20 @@ module Dcc
|
|
|
19
19
|
|
|
20
20
|
def check_on(dcc)
|
|
21
21
|
issues = []
|
|
22
|
-
return issues unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
22
|
+
return issues unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
23
|
+
:administrative_data)
|
|
23
24
|
|
|
24
25
|
admin = dcc.administrative_data
|
|
25
|
-
|
|
26
|
+
unless admin
|
|
27
|
+
return [issue(severity: :error,
|
|
28
|
+
message: "administrativeData is missing")]
|
|
29
|
+
end
|
|
26
30
|
|
|
27
31
|
REQUIRED_SECTIONS.each do |attr, label|
|
|
28
|
-
value = Dcc::TypeGuards.has_attribute?(admin,
|
|
32
|
+
value = if Dcc::TypeGuards.has_attribute?(admin,
|
|
33
|
+
attr)
|
|
34
|
+
admin.public_send(attr)
|
|
35
|
+
end
|
|
29
36
|
next unless value.nil? || ((value.is_a?(::String) || value.is_a?(::Array)) && value.empty?)
|
|
30
37
|
|
|
31
38
|
issues << issue(
|
|
@@ -39,4 +46,4 @@ module Dcc
|
|
|
39
46
|
end
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
|
-
end
|
|
49
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -8,13 +7,20 @@ module Dcc
|
|
|
8
7
|
# Errors if `endPerformanceDate` precedes `beginPerformanceDate`.
|
|
9
8
|
class DateRangeCheck < Base
|
|
10
9
|
def check_on(dcc)
|
|
11
|
-
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
10
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
11
|
+
:administrative_data)
|
|
12
12
|
|
|
13
13
|
core = safe_attr(dcc.administrative_data, :core_data)
|
|
14
14
|
return [] if core.nil?
|
|
15
15
|
|
|
16
|
-
begin_d = Dcc::TypeGuards.has_attribute?(core,
|
|
17
|
-
|
|
16
|
+
begin_d = if Dcc::TypeGuards.has_attribute?(core,
|
|
17
|
+
:begin_performance_date)
|
|
18
|
+
core.begin_performance_date
|
|
19
|
+
end
|
|
20
|
+
end_d = if Dcc::TypeGuards.has_attribute?(core,
|
|
21
|
+
:end_performance_date)
|
|
22
|
+
core.end_performance_date
|
|
23
|
+
end
|
|
18
24
|
|
|
19
25
|
return [] if begin_d.nil? || end_d.nil?
|
|
20
26
|
return [] unless end_d < begin_d
|
|
@@ -38,4 +44,4 @@ module Dcc
|
|
|
38
44
|
end
|
|
39
45
|
end
|
|
40
46
|
end
|
|
41
|
-
end
|
|
47
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -9,25 +8,31 @@ module Dcc
|
|
|
9
8
|
# quantity level). Error if missing.
|
|
10
9
|
class InfluenceConditionsPlacement < Base
|
|
11
10
|
def check_on(dcc)
|
|
12
|
-
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
11
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
12
|
+
:measurement_results)
|
|
13
13
|
|
|
14
14
|
mr_list = safe_attr(dcc.measurement_results, :measurement_result)
|
|
15
15
|
return [] if mr_list.empty?
|
|
16
16
|
|
|
17
17
|
any_present = mr_list.any? do |mr|
|
|
18
|
-
next false unless Dcc::TypeGuards.has_attribute?(mr,
|
|
18
|
+
next false unless Dcc::TypeGuards.has_attribute?(mr,
|
|
19
|
+
:influence_conditions)
|
|
19
20
|
next true unless mr.influence_conditions.nil?
|
|
20
21
|
|
|
21
22
|
Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results &&
|
|
22
23
|
has_in_descendants?(mr.results)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
any_present
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
if any_present
|
|
27
|
+
[]
|
|
28
|
+
else
|
|
29
|
+
[
|
|
30
|
+
issue(
|
|
31
|
+
severity: :error,
|
|
32
|
+
message: "dcc:influenceConditions is missing everywhere",
|
|
33
|
+
),
|
|
34
|
+
]
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
private
|
|
@@ -35,13 +40,18 @@ module Dcc
|
|
|
35
40
|
def has_in_descendants?(node)
|
|
36
41
|
return false unless node.is_a?(::Lutaml::Model::Serializable)
|
|
37
42
|
|
|
38
|
-
if Dcc::TypeGuards.has_attribute?(node,
|
|
43
|
+
if Dcc::TypeGuards.has_attribute?(node,
|
|
44
|
+
:influence_conditions) && !node.influence_conditions.nil?
|
|
39
45
|
return true
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
node.class.attributes.each_key do |attr|
|
|
43
49
|
value = node.public_send(attr)
|
|
44
|
-
|
|
50
|
+
if value.is_a?(::Array) || value.is_a?(::Lutaml::Model::Serializable)
|
|
51
|
+
Array(value).any? do |c|
|
|
52
|
+
has_in_descendants?(c)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
45
55
|
end
|
|
46
56
|
false
|
|
47
57
|
end
|
|
@@ -55,4 +65,4 @@ module Dcc
|
|
|
55
65
|
end
|
|
56
66
|
end
|
|
57
67
|
end
|
|
58
|
-
end
|
|
68
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -10,13 +9,17 @@ module Dcc
|
|
|
10
9
|
# flag empties that escaped earlier casts.
|
|
11
10
|
class IsoCodeValidation < Base
|
|
12
11
|
def check_on(dcc)
|
|
13
|
-
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
12
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
13
|
+
:administrative_data)
|
|
14
14
|
|
|
15
15
|
core = safe_attr(dcc.administrative_data, :core_data)
|
|
16
16
|
return [] if core.nil?
|
|
17
17
|
|
|
18
18
|
issues = []
|
|
19
|
-
country = Dcc::TypeGuards.has_attribute?(core,
|
|
19
|
+
country = if Dcc::TypeGuards.has_attribute?(core,
|
|
20
|
+
:country_code_iso_3166_1)
|
|
21
|
+
core.country_code_iso_3166_1
|
|
22
|
+
end
|
|
20
23
|
if country.nil? || country.to_s.empty?
|
|
21
24
|
issues << issue(
|
|
22
25
|
severity: :error,
|
|
@@ -24,17 +27,31 @@ module Dcc
|
|
|
24
27
|
)
|
|
25
28
|
end
|
|
26
29
|
|
|
27
|
-
used = Dcc::TypeGuards.has_attribute?(core,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
used = if Dcc::TypeGuards.has_attribute?(core,
|
|
31
|
+
:used_lang_code_iso_639_1)
|
|
32
|
+
Array(core.used_lang_code_iso_639_1)
|
|
33
|
+
else
|
|
34
|
+
[]
|
|
35
|
+
end
|
|
36
|
+
if used.empty?
|
|
37
|
+
issues << issue(
|
|
38
|
+
severity: :error,
|
|
39
|
+
message: "dcc:usedLangCodeISO639_1 must have at least one entry",
|
|
40
|
+
)
|
|
41
|
+
end
|
|
32
42
|
|
|
33
|
-
mandatory = Dcc::TypeGuards.has_attribute?(core,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
mandatory = if Dcc::TypeGuards.has_attribute?(core,
|
|
44
|
+
:mandatory_lang_code_iso_639_1)
|
|
45
|
+
Array(core.mandatory_lang_code_iso_639_1)
|
|
46
|
+
else
|
|
47
|
+
[]
|
|
48
|
+
end
|
|
49
|
+
if mandatory.empty?
|
|
50
|
+
issues << issue(
|
|
51
|
+
severity: :error,
|
|
52
|
+
message: "dcc:mandatoryLangCodeISO639_1 must have at least one entry",
|
|
53
|
+
)
|
|
54
|
+
end
|
|
38
55
|
|
|
39
56
|
issues
|
|
40
57
|
end
|
|
@@ -50,4 +67,4 @@ module Dcc
|
|
|
50
67
|
end
|
|
51
68
|
end
|
|
52
69
|
end
|
|
53
|
-
end
|
|
70
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -8,14 +7,22 @@ module Dcc
|
|
|
8
7
|
# Errors on duplicate language codes in `dcc:usedLangCodeISO639_1`.
|
|
9
8
|
class LanguageCodeDedup < Base
|
|
10
9
|
def check_on(dcc)
|
|
11
|
-
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
10
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
11
|
+
:administrative_data)
|
|
12
12
|
|
|
13
13
|
core = safe_attr(dcc.administrative_data, :core_data)
|
|
14
14
|
return [] if core.nil?
|
|
15
15
|
|
|
16
|
-
used = Dcc::TypeGuards.has_attribute?(core,
|
|
16
|
+
used = if Dcc::TypeGuards.has_attribute?(core,
|
|
17
|
+
:used_lang_code_iso_639_1)
|
|
18
|
+
Array(core.used_lang_code_iso_639_1)
|
|
19
|
+
else
|
|
20
|
+
[]
|
|
21
|
+
end
|
|
17
22
|
used_strings = used.map(&:to_s)
|
|
18
|
-
duplicates = used_strings.group_by(&:itself).select
|
|
23
|
+
duplicates = used_strings.group_by(&:itself).select do |_k, v|
|
|
24
|
+
v.size > 1
|
|
25
|
+
end.keys
|
|
19
26
|
|
|
20
27
|
duplicates.map do |dup|
|
|
21
28
|
issue(
|
|
@@ -36,4 +43,4 @@ module Dcc
|
|
|
36
43
|
end
|
|
37
44
|
end
|
|
38
45
|
end
|
|
39
|
-
end
|
|
46
|
+
end
|
|
@@ -36,7 +36,10 @@ module Dcc
|
|
|
36
36
|
node.class.attributes.each_key do |attr_name|
|
|
37
37
|
value = node.public_send(attr_name)
|
|
38
38
|
Array(value).each do |child|
|
|
39
|
-
|
|
39
|
+
if child.is_a?(::Lutaml::Model::Serializable)
|
|
40
|
+
declared += collect_declared_non_si_units(child,
|
|
41
|
+
visited)
|
|
42
|
+
end
|
|
40
43
|
end
|
|
41
44
|
end
|
|
42
45
|
declared
|
|
@@ -57,7 +60,9 @@ module Dcc
|
|
|
57
60
|
extract_non_si_unit(node, accumulator)
|
|
58
61
|
node.class.attributes.each_key do |attr_name|
|
|
59
62
|
value = node.public_send(attr_name)
|
|
60
|
-
Array(value).each
|
|
63
|
+
Array(value).each do |child|
|
|
64
|
+
walk_for_used_units(child, accumulator, visited)
|
|
65
|
+
end
|
|
61
66
|
end
|
|
62
67
|
end
|
|
63
68
|
|
|
@@ -78,5 +83,3 @@ module Dcc
|
|
|
78
83
|
end
|
|
79
84
|
end
|
|
80
85
|
end
|
|
81
|
-
|
|
82
|
-
require "set"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -11,13 +10,17 @@ module Dcc
|
|
|
11
10
|
|
|
12
11
|
def check_on(dcc)
|
|
13
12
|
issues = []
|
|
14
|
-
return issues unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
13
|
+
return issues unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
14
|
+
:administrative_data)
|
|
15
15
|
|
|
16
16
|
software_list = safe_attr(dcc.administrative_data, :dcc_software)
|
|
17
17
|
return issues if software_list.nil?
|
|
18
18
|
|
|
19
19
|
Array(safe_attr(software_list, :software)).each do |sw|
|
|
20
|
-
release = Dcc::TypeGuards.has_attribute?(sw,
|
|
20
|
+
release = if Dcc::TypeGuards.has_attribute?(sw,
|
|
21
|
+
:release)
|
|
22
|
+
sw.release
|
|
23
|
+
end
|
|
21
24
|
next if release.nil? || release.empty?
|
|
22
25
|
next if release.match?(PATTERN)
|
|
23
26
|
|
|
@@ -41,4 +44,4 @@ module Dcc
|
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
|
-
end
|
|
47
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Dcc
|
|
5
4
|
module Validate
|
|
6
5
|
module Schematron
|
|
@@ -12,20 +11,25 @@ module Dcc
|
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def check_on(dcc)
|
|
15
|
-
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
14
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc,
|
|
15
|
+
:schema_version)
|
|
16
16
|
|
|
17
17
|
current = dcc.schema_version.to_s
|
|
18
18
|
latest = ::Dcc::Schema::Version::DCC_LATEST
|
|
19
19
|
|
|
20
|
-
current == latest
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if current == latest
|
|
21
|
+
[]
|
|
22
|
+
else
|
|
23
|
+
[
|
|
24
|
+
issue(
|
|
25
|
+
severity: :warning,
|
|
26
|
+
message: "schemaVersion '#{current}' is not the latest release (#{latest})",
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
end
|
|
26
30
|
end
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
|
-
end
|
|
35
|
+
end
|
|
@@ -5,9 +5,16 @@ module Dcc
|
|
|
5
5
|
module Schematron
|
|
6
6
|
module Rules
|
|
7
7
|
# Validates that for every `si:realListXMLList` paired with an
|
|
8
|
-
# `si:expandedUncXMLList`,
|
|
9
|
-
# of
|
|
8
|
+
# `si:expandedUncXMLList`, each uncertainty list holds either one
|
|
9
|
+
# entry per value or a single entry broadcast across all of them.
|
|
10
10
|
class UncertaintyConsistency < Base
|
|
11
|
+
UNCERTAINTY_LISTS = {
|
|
12
|
+
uncertainty_xml_list: "uncertaintyXMLList",
|
|
13
|
+
coverage_factor_xml_list: "coverageFactorXMLList",
|
|
14
|
+
coverage_probability_xml_list: "coverageProbabilityXMLList",
|
|
15
|
+
distribution_xml_list: "distributionXMLList",
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
11
18
|
def check_on(dcc)
|
|
12
19
|
issues = []
|
|
13
20
|
return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
|
|
@@ -24,7 +31,10 @@ module Dcc
|
|
|
24
31
|
|
|
25
32
|
visited << node.object_id
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
if node.class.name.end_with?("::RealListXmlList")
|
|
35
|
+
check_node(node,
|
|
36
|
+
issues)
|
|
37
|
+
end
|
|
28
38
|
descend(node, issues, visited)
|
|
29
39
|
end
|
|
30
40
|
|
|
@@ -33,16 +43,37 @@ module Dcc
|
|
|
33
43
|
unc = list_node.expanded_unc_xml_list
|
|
34
44
|
return unless unc && values
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
value_count = entry_count(values)
|
|
47
|
+
UNCERTAINTY_LISTS.each do |attribute, xml_name|
|
|
48
|
+
count = entry_count(unc.public_send(attribute))
|
|
49
|
+
next if consistent?(count, value_count)
|
|
50
|
+
|
|
51
|
+
issues << count_mismatch(xml_name, count, value_count)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
def count_mismatch(xml_name, count, value_count)
|
|
56
|
+
issue(
|
|
41
57
|
severity: :error,
|
|
42
|
-
message: "valueXMLList count (#{value_count}) does not
|
|
58
|
+
message: "valueXMLList count (#{value_count}) does not " \
|
|
59
|
+
"match #{xml_name} count (#{count})",
|
|
43
60
|
)
|
|
44
61
|
end
|
|
45
62
|
|
|
63
|
+
# Every list here is an xs:list, so its entries are whitespace
|
|
64
|
+
# separated whether the attribute holds a string or a decimal list.
|
|
65
|
+
def entry_count(list)
|
|
66
|
+
list.to_s.split.size
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# A list either carries one entry per value or a single entry that
|
|
70
|
+
# broadcasts across all of them, the way unitXMLList does. Siblings
|
|
71
|
+
# decide independently: PTB ships documents pairing nine
|
|
72
|
+
# uncertainties with one shared coverage factor.
|
|
73
|
+
def consistent?(count, value_count)
|
|
74
|
+
count.zero? || count == 1 || count == value_count
|
|
75
|
+
end
|
|
76
|
+
|
|
46
77
|
def descend(node, issues, visited)
|
|
47
78
|
node.class.attributes.each_key do |attr_name|
|
|
48
79
|
value = node.public_send(attr_name)
|
|
@@ -54,5 +85,3 @@ module Dcc
|
|
|
54
85
|
end
|
|
55
86
|
end
|
|
56
87
|
end
|
|
57
|
-
|
|
58
|
-
require "set"
|
|
@@ -29,7 +29,8 @@ module Dcc
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def check_single_unit(node, issues)
|
|
32
|
-
return unless node.class.name.end_with?("::Real", "::Complex",
|
|
32
|
+
return unless node.class.name.end_with?("::Real", "::Complex",
|
|
33
|
+
"::Constant")
|
|
33
34
|
return unless node.respond_to?(:unit)
|
|
34
35
|
|
|
35
36
|
unit = node.unit
|
|
@@ -70,5 +71,3 @@ module Dcc
|
|
|
70
71
|
end
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
|
-
|
|
74
|
-
require "set"
|