pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.12
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/README.adoc +33 -11
- data/conformance/pending.yaml +4 -0
- data/lib/pubid/adobe/identifier.rb +1 -3
- data/lib/pubid/adobe/parser.rb +10 -2
- data/lib/pubid/adobe.rb +1 -0
- data/lib/pubid/amca/builder.rb +2 -2
- data/lib/pubid/amca/identifiers/base.rb +49 -27
- data/lib/pubid/amca/identifiers/interpretation.rb +17 -9
- data/lib/pubid/amca/identifiers/publication.rb +13 -9
- data/lib/pubid/amca/identifiers/standard.rb +2 -0
- data/lib/pubid/amca/parser.rb +1 -1
- data/lib/pubid/amca/renderer.rb +4 -4
- data/lib/pubid/amca/urn_generator.rb +2 -2
- data/lib/pubid/amca.rb +2 -1
- data/lib/pubid/ansi/builder.rb +2 -2
- data/lib/pubid/ansi/identifier.rb +18 -0
- data/lib/pubid/ansi/parser.rb +1 -1
- data/lib/pubid/ansi/renderer.rb +2 -2
- data/lib/pubid/ansi.rb +5 -5
- data/lib/pubid/api/builder.rb +16 -2
- data/lib/pubid/api/identifier.rb +25 -4
- data/lib/pubid/api/identifiers/mpms.rb +10 -8
- data/lib/pubid/api/parser.rb +1 -1
- data/lib/pubid/api/renderer.rb +16 -7
- data/lib/pubid/api/single_identifier.rb +5 -12
- data/lib/pubid/api.rb +1 -0
- data/lib/pubid/ashrae/builder.rb +31 -10
- data/lib/pubid/ashrae/identifiers/addenda_package.rb +6 -0
- data/lib/pubid/ashrae/identifiers/addendum.rb +8 -0
- data/lib/pubid/ashrae/identifiers/base.rb +81 -5
- data/lib/pubid/ashrae/identifiers/combined_addenda.rb +7 -0
- data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
- data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
- data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
- data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
- data/lib/pubid/ashrae/parser.rb +23 -8
- data/lib/pubid/ashrae/renderer.rb +6 -6
- data/lib/pubid/ashrae/supplement_identifier.rb +17 -2
- data/lib/pubid/ashrae/urn_generator.rb +8 -2
- data/lib/pubid/ashrae.rb +7 -1
- data/lib/pubid/asme/builder.rb +11 -2
- data/lib/pubid/asme/identifier.rb +9 -0
- data/lib/pubid/asme/identifiers/standard.rb +86 -2
- data/lib/pubid/asme/parser.rb +1 -1
- data/lib/pubid/asme/renderer.rb +3 -3
- data/lib/pubid/asme/single_identifier.rb +8 -1
- data/lib/pubid/asme/urn_generator.rb +2 -2
- data/lib/pubid/asme.rb +1 -0
- data/lib/pubid/astm/builder.rb +10 -3
- data/lib/pubid/astm/identifier.rb +9 -0
- data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
- data/lib/pubid/astm/identifiers/code_number.rb +81 -0
- data/lib/pubid/astm/identifiers/data_series.rb +2 -0
- data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
- data/lib/pubid/astm/identifiers/manual.rb +10 -0
- data/lib/pubid/astm/identifiers/monograph.rb +2 -0
- data/lib/pubid/astm/identifiers/research_report.rb +10 -0
- data/lib/pubid/astm/identifiers/standard.rb +10 -0
- data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
- data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
- data/lib/pubid/astm/identifiers.rb +1 -0
- data/lib/pubid/astm/parser.rb +1 -1
- data/lib/pubid/astm/renderer.rb +1 -1
- data/lib/pubid/astm/single_identifier.rb +31 -1
- data/lib/pubid/astm/urn_generator.rb +7 -5
- data/lib/pubid/astm.rb +1 -0
- data/lib/pubid/bipm/builder.rb +66 -10
- data/lib/pubid/bipm/identifier.rb +134 -9
- data/lib/pubid/bipm/identifiers/committee_document.rb +12 -0
- data/lib/pubid/bipm/identifiers/guide.rb +11 -0
- data/lib/pubid/bipm/identifiers/meeting.rb +12 -0
- data/lib/pubid/bipm/identifiers/mep.rb +12 -0
- data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
- data/lib/pubid/bipm/identifiers/si_brochure.rb +13 -0
- data/lib/pubid/bipm/parser.rb +65 -12
- data/lib/pubid/bipm/renderer.rb +8 -0
- data/lib/pubid/bipm/urn_parser.rb +11 -3
- data/lib/pubid/bipm.rb +7 -1
- data/lib/pubid/bsi/builder.rb +48 -38
- data/lib/pubid/bsi/components/date.rb +10 -4
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -2
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
- data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
- data/lib/pubid/bsi/identifiers/handbook.rb +1 -3
- data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -2
- data/lib/pubid/bsi/identifiers/set.rb +11 -0
- data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
- data/lib/pubid/bsi/parser.rb +1 -1
- data/lib/pubid/bsi/renderer.rb +63 -51
- data/lib/pubid/bsi/single_identifier.rb +27 -9
- data/lib/pubid/bsi/urn_generator.rb +11 -2
- data/lib/pubid/bsi.rb +7 -1
- data/lib/pubid/builder/base.rb +18 -8
- data/lib/pubid/bundled_identifier.rb +16 -6
- data/lib/pubid/calconnect/identifier.rb +9 -5
- data/lib/pubid/calconnect/parser.rb +1 -1
- data/lib/pubid/calconnect.rb +7 -1
- data/lib/pubid/ccsds/identifier.rb +13 -2
- data/lib/pubid/ccsds/identifiers/base.rb +4 -2
- data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/ccsds/parser.rb +1 -1
- data/lib/pubid/ccsds/single_identifier.rb +16 -12
- data/lib/pubid/ccsds.rb +1 -0
- data/lib/pubid/cen_cenelec/builder.rb +101 -76
- data/lib/pubid/cen_cenelec/identifier.rb +115 -3
- data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
- data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
- data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
- data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
- data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
- data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
- data/lib/pubid/cen_cenelec/parser.rb +1 -1
- data/lib/pubid/cen_cenelec/renderer.rb +55 -60
- data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
- data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
- data/lib/pubid/cen_cenelec.rb +28 -10
- data/lib/pubid/cie/builder.rb +10 -0
- data/lib/pubid/cie/identifier.rb +6 -1
- data/lib/pubid/cie/identifiers/bundle.rb +4 -2
- data/lib/pubid/cie/identifiers/conference.rb +2 -2
- data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
- data/lib/pubid/cie/identifiers/identical.rb +2 -2
- data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
- data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
- data/lib/pubid/cie/identifiers/standard.rb +22 -13
- data/lib/pubid/cie/identifiers/supplement.rb +2 -2
- data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
- data/lib/pubid/cie/parser.rb +1 -1
- data/lib/pubid/cie.rb +7 -1
- data/lib/pubid/conformance/checks.rb +72 -0
- data/lib/pubid/conformance/corpus/case.rb +55 -0
- data/lib/pubid/conformance/corpus.rb +36 -0
- data/lib/pubid/conformance/generator.rb +212 -0
- data/lib/pubid/conformance/pending.rb +63 -0
- data/lib/pubid/conformance/runner.rb +153 -0
- data/lib/pubid/conformance.rb +55 -0
- data/lib/pubid/core.rb +2 -0
- data/lib/pubid/csa/builder.rb +47 -47
- data/lib/pubid/csa/composite_identifier.rb +14 -19
- data/lib/pubid/csa/identifier.rb +143 -81
- data/lib/pubid/csa/identifiers/bundled.rb +23 -13
- data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
- data/lib/pubid/csa/identifiers/cec.rb +44 -4
- data/lib/pubid/csa/identifiers/combined.rb +95 -73
- data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
- data/lib/pubid/csa/identifiers/package.rb +2 -2
- data/lib/pubid/csa/parser.rb +6 -2
- data/lib/pubid/csa/renderer.rb +13 -5
- data/lib/pubid/csa/single_identifier.rb +93 -4
- data/lib/pubid/csa/urn_generator.rb +9 -2
- data/lib/pubid/csa/wrapper_identifier.rb +39 -23
- data/lib/pubid/csa.rb +7 -1
- data/lib/pubid/doi/identifier.rb +6 -3
- data/lib/pubid/doi/parser.rb +1 -1
- data/lib/pubid/doi.rb +1 -0
- data/lib/pubid/easc/identifier.rb +0 -2
- data/lib/pubid/easc/parser.rb +10 -2
- data/lib/pubid/easc.rb +1 -0
- data/lib/pubid/ecma/builder.rb +23 -9
- data/lib/pubid/ecma/identifier.rb +81 -10
- data/lib/pubid/ecma/parser.rb +39 -4
- data/lib/pubid/ecma/renderer.rb +29 -8
- data/lib/pubid/ecma/urn_generator.rb +34 -13
- data/lib/pubid/ecma/urn_parser.rb +30 -14
- data/lib/pubid/ecma.rb +1 -0
- data/lib/pubid/errors.rb +80 -0
- data/lib/pubid/etsi/builder.rb +6 -1
- data/lib/pubid/etsi/identifiers/base.rb +34 -20
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
- data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
- data/lib/pubid/etsi/parser.rb +1 -1
- data/lib/pubid/etsi.rb +1 -0
- data/lib/pubid/evs/builder.rb +26 -0
- data/lib/pubid/evs/identifier.rb +37 -0
- data/lib/pubid/evs/identifiers/national_adoption.rb +22 -0
- data/lib/pubid/evs/identifiers.rb +9 -0
- data/lib/pubid/evs/parser.rb +27 -0
- data/lib/pubid/evs/renderer.rb +30 -0
- data/lib/pubid/evs/urn_generator.rb +30 -0
- data/lib/pubid/evs/urn_parser.rb +80 -0
- data/lib/pubid/evs.rb +90 -0
- data/lib/pubid/export.rb +1 -0
- data/lib/pubid/format_detector.rb +1 -0
- data/lib/pubid/gb/builder.rb +14 -9
- data/lib/pubid/gb/identifier.rb +29 -7
- data/lib/pubid/gb/parser.rb +5 -1
- data/lib/pubid/gb/renderer.rb +4 -3
- data/lib/pubid/gb.rb +2 -0
- data/lib/pubid/gost/builder.rb +46 -9
- data/lib/pubid/gost/identifier.rb +0 -2
- data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
- data/lib/pubid/gost/parser.rb +10 -2
- data/lib/pubid/gost.rb +1 -0
- data/lib/pubid/iala/identifier.rb +9 -6
- data/lib/pubid/iala/parser.rb +10 -2
- data/lib/pubid/iala/urn_parser.rb +6 -2
- data/lib/pubid/iala.rb +1 -0
- data/lib/pubid/iana/builder.rb +3 -1
- data/lib/pubid/iana/identifier.rb +74 -6
- data/lib/pubid/iana/identifiers/registry.rb +36 -0
- data/lib/pubid/iana/parser.rb +1 -1
- data/lib/pubid/iana/renderer.rb +3 -0
- data/lib/pubid/iana/urn_generator.rb +5 -1
- data/lib/pubid/iana.rb +1 -0
- data/lib/pubid/identifier.rb +605 -13
- data/lib/pubid/identifier_metadata.rb +1 -0
- data/lib/pubid/idf/builder.rb +3 -3
- data/lib/pubid/idf/identifier.rb +25 -9
- data/lib/pubid/idf/identifiers/amendment.rb +1 -1
- data/lib/pubid/idf/identifiers/corrigendum.rb +1 -1
- data/lib/pubid/idf/identifiers/international_standard.rb +1 -1
- data/lib/pubid/idf/identifiers/reviewed_method.rb +1 -1
- data/lib/pubid/idf/parser.rb +1 -1
- data/lib/pubid/idf/renderer.rb +4 -4
- data/lib/pubid/idf/single_identifier.rb +1 -1
- data/lib/pubid/idf/urn_generator.rb +1 -1
- data/lib/pubid/idf.rb +7 -1
- data/lib/pubid/iec/builder.rb +14 -7
- data/lib/pubid/iec/components.rb +0 -1
- data/lib/pubid/iec/identifier.rb +73 -83
- data/lib/pubid/iec/identifiers/amendment.rb +6 -2
- data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
- data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
- data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
- data/lib/pubid/iec/identifiers/guide.rb +0 -16
- data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
- data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
- data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
- data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
- data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
- data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
- data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
- data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
- data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
- data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
- data/lib/pubid/iec/identifiers/working_document.rb +24 -10
- data/lib/pubid/iec/parser.rb +2 -18
- data/lib/pubid/iec/renderer.rb +13 -10
- data/lib/pubid/iec/single_identifier.rb +33 -10
- data/lib/pubid/iec/urn_generator.rb +227 -61
- data/lib/pubid/iec/urn_parser.rb +42 -4
- data/lib/pubid/iec.rb +1 -0
- data/lib/pubid/ieee/aiee/identifier.rb +2 -2
- data/lib/pubid/ieee/aiee/parser.rb +1 -1
- data/lib/pubid/ieee/builder.rb +87 -3
- data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
- data/lib/pubid/ieee/identifiers/base.rb +42 -5
- data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
- data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
- data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
- data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
- data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
- data/lib/pubid/ieee/identifiers/si_standard.rb +5 -2
- data/lib/pubid/ieee/ire/identifier.rb +2 -2
- data/lib/pubid/ieee/ire/parser.rb +20 -2
- data/lib/pubid/ieee/nesc/parser.rb +1 -1
- data/lib/pubid/ieee/parser.rb +208 -33
- data/lib/pubid/ieee/project_renderer.rb +46 -0
- data/lib/pubid/ieee/renderer.rb +11 -8
- data/lib/pubid/ieee/urn_generator.rb +32 -3
- data/lib/pubid/ieee.rb +9 -1
- data/lib/pubid/ieee_debug.rb +1 -0
- data/lib/pubid/ietf/builder.rb +24 -8
- data/lib/pubid/ietf/identifiers/base.rb +25 -28
- data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
- data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
- data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
- data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
- data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
- data/lib/pubid/ietf/identifiers/std.rb +11 -0
- data/lib/pubid/ietf/identifiers.rb +1 -0
- data/lib/pubid/ietf/parser.rb +27 -9
- data/lib/pubid/ietf/renderer.rb +44 -6
- data/lib/pubid/ietf/urn_generator.rb +20 -6
- data/lib/pubid/ietf/urn_parser.rb +10 -2
- data/lib/pubid/ietf.rb +12 -2
- data/lib/pubid/iho/identifiers/base.rb +10 -3
- data/lib/pubid/iho/parser.rb +1 -1
- data/lib/pubid/iho.rb +1 -0
- data/lib/pubid/isbn/identifier.rb +25 -7
- data/lib/pubid/isbn/parser.rb +1 -1
- data/lib/pubid/isbn.rb +1 -0
- data/lib/pubid/iso/builder.rb +10 -11
- data/lib/pubid/iso/bundled_identifier.rb +5 -3
- data/lib/pubid/iso/combined_identifier.rb +5 -3
- data/lib/pubid/iso/components.rb +0 -1
- data/lib/pubid/iso/identifier.rb +23 -11
- data/lib/pubid/iso/identifiers/directives.rb +7 -4
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
- data/lib/pubid/iso/identifiers/tc_document.rb +31 -46
- data/lib/pubid/iso/normalizer.rb +1 -1
- data/lib/pubid/iso/parser.rb +1 -1
- data/lib/pubid/iso/urn_generator.rb +10 -10
- data/lib/pubid/iso.rb +12 -5
- data/lib/pubid/itu/builder.rb +10 -0
- data/lib/pubid/itu/identifiers/addendum.rb +2 -2
- data/lib/pubid/itu/identifiers/amendment.rb +2 -2
- data/lib/pubid/itu/identifiers/base.rb +29 -5
- data/lib/pubid/itu/identifiers/contribution.rb +31 -0
- data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/itu/identifiers/errata.rb +2 -2
- data/lib/pubid/itu/identifiers/supplement.rb +2 -2
- data/lib/pubid/itu/identifiers.rb +1 -0
- data/lib/pubid/itu/parser.rb +20 -3
- data/lib/pubid/itu.rb +1 -0
- data/lib/pubid/jcgm/builder.rb +1 -1
- data/lib/pubid/jcgm/identifier.rb +10 -0
- data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
- data/lib/pubid/jcgm/parser.rb +10 -3
- data/lib/pubid/jcgm/renderer.rb +10 -3
- data/lib/pubid/jcgm/single_identifier.rb +24 -15
- data/lib/pubid/jcgm/urn_generator.rb +1 -1
- data/lib/pubid/jcgm/urn_parser.rb +156 -14
- data/lib/pubid/jcgm.rb +10 -0
- data/lib/pubid/jis/identifier.rb +10 -3
- data/lib/pubid/jis/parser.rb +1 -1
- data/lib/pubid/jis.rb +1 -0
- data/lib/pubid/nist/builder.rb +12 -12
- data/lib/pubid/nist/components/stage.rb +2 -2
- data/lib/pubid/nist/configuration.rb +6 -8
- data/lib/pubid/nist/identifiers/base.rb +22 -5
- data/lib/pubid/nist/identifiers/circular.rb +9 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
- data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
- data/lib/pubid/nist/identifiers/crpl_report.rb +12 -7
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +2 -2
- data/lib/pubid/nist/identifiers/handbook.rb +9 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +16 -8
- data/lib/pubid/nist/identifiers/monograph.rb +14 -7
- data/lib/pubid/nist/identifiers/report.rb +14 -6
- data/lib/pubid/nist/parser.rb +1 -1
- data/lib/pubid/nist/series/ir.rb +3 -7
- data/lib/pubid/nist/supplement_identifier.rb +16 -1
- data/lib/pubid/nist.rb +7 -1
- data/lib/pubid/oasis/builder.rb +12 -10
- data/lib/pubid/oasis/identifier.rb +89 -11
- data/lib/pubid/oasis/parser.rb +1 -1
- data/lib/pubid/oasis.rb +7 -1
- data/lib/pubid/ogc/identifier.rb +9 -5
- data/lib/pubid/ogc/parser.rb +1 -1
- data/lib/pubid/ogc.rb +1 -0
- data/lib/pubid/oiml/builder.rb +7 -3
- data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
- data/lib/pubid/oiml/identifiers/bulletin.rb +40 -10
- data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
- data/lib/pubid/oiml/identifiers/document.rb +2 -0
- data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
- data/lib/pubid/oiml/identifiers/guide.rb +2 -0
- data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
- data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
- data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
- data/lib/pubid/oiml/identifiers.rb +1 -0
- data/lib/pubid/oiml/parser.rb +8 -3
- data/lib/pubid/oiml/renderer.rb +3 -3
- data/lib/pubid/oiml/single_identifier.rb +26 -42
- data/lib/pubid/oiml/supplement_identifier.rb +27 -0
- data/lib/pubid/oiml/urn_generator.rb +4 -4
- data/lib/pubid/oiml.rb +7 -1
- data/lib/pubid/omg/builder.rb +1 -0
- data/lib/pubid/omg/identifier.rb +20 -3
- data/lib/pubid/omg/parser.rb +64 -11
- data/lib/pubid/omg/renderer.rb +13 -1
- data/lib/pubid/omg.rb +2 -1
- data/lib/pubid/parser/grammar.rb +74 -0
- data/lib/pubid/parser.rb +2 -0
- data/lib/pubid/parsers/mr_string.rb +19 -0
- data/lib/pubid/plateau/parser.rb +1 -1
- data/lib/pubid/plateau.rb +10 -0
- data/lib/pubid/prefixes_support.rb +1 -0
- data/lib/pubid/renderers/annotator.rb +233 -0
- data/lib/pubid/renderers/base.rb +13 -0
- data/lib/pubid/renderers/directives_renderer.rb +6 -4
- data/lib/pubid/renderers/human_readable.rb +3 -3
- data/lib/pubid/renderers/mr_string.rb +15 -9
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/rendering/numbering.rb +25 -7
- data/lib/pubid/rendering.rb +1 -0
- data/lib/pubid/sae/builder.rb +1 -1
- data/lib/pubid/sae/identifiers/base.rb +13 -3
- data/lib/pubid/sae/parser.rb +1 -1
- data/lib/pubid/sae/urn_generator.rb +1 -1
- data/lib/pubid/sae.rb +1 -0
- data/lib/pubid/schema/declaration.rb +33 -0
- data/lib/pubid/schema/error.rb +14 -0
- data/lib/pubid/schema/identifier_type.rb +23 -0
- data/lib/pubid/schema/loader.rb +117 -0
- data/lib/pubid/schema/typed_stage.rb +24 -0
- data/lib/pubid/schema.rb +25 -0
- data/lib/pubid/tgpp/builder.rb +1 -1
- data/lib/pubid/tgpp/identifier.rb +21 -5
- data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
- data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
- data/lib/pubid/tgpp/parser.rb +22 -6
- data/lib/pubid/tgpp/renderer.rb +21 -5
- data/lib/pubid/tgpp/urn_generator.rb +27 -8
- data/lib/pubid/tgpp/urn_parser.rb +8 -6
- data/lib/pubid/tgpp.rb +7 -1
- data/lib/pubid/type_resolver.rb +16 -1
- data/lib/pubid/un/identifier.rb +6 -3
- data/lib/pubid/un/parser.rb +1 -1
- data/lib/pubid/un.rb +1 -0
- data/lib/pubid/urn_parser/errors.rb +8 -1
- data/lib/pubid/urn_parser.rb +1 -0
- data/lib/pubid/utils.rb +1 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/builder.rb +5 -5
- data/lib/pubid/w3c/identifier.rb +38 -9
- data/lib/pubid/w3c/parser.rb +1 -1
- data/lib/pubid/w3c/renderer.rb +1 -1
- data/lib/pubid/w3c/urn_generator.rb +2 -2
- data/lib/pubid/w3c.rb +1 -0
- data/lib/pubid/xsf/identifier.rb +9 -5
- data/lib/pubid/xsf/parser.rb +17 -4
- data/lib/pubid/xsf.rb +7 -1
- data/lib/pubid.rb +399 -21
- data/lib/tasks/conformance.rake +34 -0
- data/lib/tasks/docs.rake +16 -14
- data/lib/tasks/schema.rake +88 -0
- data/schema/core/joint_prefixes.yaml +24 -0
- data/schema/iec.yaml +1017 -0
- data/schema/iso.yaml +1586 -0
- data/schema/schema.schema.yaml +96 -0
- metadata +40 -19
- data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
- data/archived-gems/pubid-iec/stages.yaml +0 -129
- data/archived-gems/pubid-iec/update_codes.yaml +0 -67
- data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
- data/archived-gems/pubid-iso/stages.yaml +0 -106
- data/archived-gems/pubid-iso/update_codes.yaml +0 -4
- data/archived-gems/pubid-itu/i18n.yaml +0 -13
- data/archived-gems/pubid-itu/series.yaml +0 -42
- data/archived-gems/pubid-nist/publishers.yaml +0 -6
- data/archived-gems/pubid-nist/series.yaml +0 -121
- data/archived-gems/pubid-nist/update_codes.yaml +0 -93
- data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
- data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +0 -70
- data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
- data/lib/pubid/iec/components/code.rb +0 -36
- data/lib/pubid/iso/components/code.rb +0 -24
- /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Conformance
|
|
5
|
+
# Migrates the ground-truth fixture library (spec/fixtures/{flavor}/
|
|
6
|
+
# identifiers/{pass,fail}/*.txt) into the neutral corpus by running the
|
|
7
|
+
# reference implementation. Fixture lines that normalize to the same
|
|
8
|
+
# identifier collapse into one canonical case carrying the old
|
|
9
|
+
# spellings as non_normalized_aliases (old => normalized, and the
|
|
10
|
+
# normalized form round-trips). Unparseable pass lines are recorded as
|
|
11
|
+
# visible debt; fail lines (stored as "#ID# Error: ..." comments in the
|
|
12
|
+
# fixture files) become negative cases. Nothing is sampled, filtered,
|
|
13
|
+
# or dropped.
|
|
14
|
+
class Generator
|
|
15
|
+
attr_reader :flavor
|
|
16
|
+
|
|
17
|
+
def initialize(flavor)
|
|
18
|
+
require "pubid"
|
|
19
|
+
|
|
20
|
+
@flavor = flavor.to_s
|
|
21
|
+
Pubid.eager_load_flavors!
|
|
22
|
+
@flavor_module = Pubid::Registry.get(@flavor)
|
|
23
|
+
raise ArgumentError, "unknown flavor #{@flavor}" unless @flavor_module
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def generate(output_dir:)
|
|
27
|
+
results = { files: 0, cases: 0, negative: 0, debt: 0, aliases: 0,
|
|
28
|
+
duplicates: 0, reclassify: 0, roundtrip_failures: 0 }
|
|
29
|
+
debt = []
|
|
30
|
+
pass_files.each do |path|
|
|
31
|
+
type = File.basename(path, ".txt")
|
|
32
|
+
cases, type_debt = build_pass_cases(path, type, results)
|
|
33
|
+
debt.concat(type_debt)
|
|
34
|
+
next if cases.empty?
|
|
35
|
+
|
|
36
|
+
write_yaml(File.join(output_dir, "#{type}.yaml"), cases)
|
|
37
|
+
results[:files] += 1
|
|
38
|
+
end
|
|
39
|
+
results[:debt] = debt.size
|
|
40
|
+
write_yaml(File.join(output_dir, "_debt.yaml"), debt) if debt.any?
|
|
41
|
+
negative = build_negative_cases(results)
|
|
42
|
+
if negative.any?
|
|
43
|
+
write_yaml(File.join(output_dir, "_negative.yaml"), negative)
|
|
44
|
+
end
|
|
45
|
+
results
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def pass_files
|
|
51
|
+
Dir[File.join(fixtures_dir, "identifiers", "pass", "*.txt")] +
|
|
52
|
+
Dir[File.join(fixtures_dir, "identifiers", "full", "*.txt")]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def fail_files
|
|
56
|
+
Dir[File.join(fixtures_dir, "identifiers", "fail", "*.txt")]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def fixtures_dir
|
|
60
|
+
File.join(tests_repo, "reference-docs", @flavor)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def tests_repo
|
|
64
|
+
@tests_repo ||= ENV.fetch("PUBID_TESTSUITE_PATH",
|
|
65
|
+
File.expand_path("../../../../pubid-testsuite",
|
|
66
|
+
__dir__))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fixture_lines(path)
|
|
70
|
+
File.readlines(path).map(&:strip).reject do |line|
|
|
71
|
+
line.empty? || line.start_with?("#")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Fail fixtures store identifiers as comment lines shaped
|
|
76
|
+
# "#IDENTIFIER# Parslet::ParseFailed: ...". Strip the leading # and
|
|
77
|
+
# the trailing historical annotation to recover the input.
|
|
78
|
+
def fail_fixture_lines(path)
|
|
79
|
+
File.readlines(path).filter_map do |raw|
|
|
80
|
+
line = raw.strip
|
|
81
|
+
next if line.empty?
|
|
82
|
+
next line unless line.start_with?("#")
|
|
83
|
+
|
|
84
|
+
input = line.sub(/\A#/, "").split("#", 2).first.to_s.strip
|
|
85
|
+
input unless input.empty?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def build_pass_cases(path, type, results)
|
|
90
|
+
groups = {}
|
|
91
|
+
debt = []
|
|
92
|
+
fixture_lines(path).each do |input|
|
|
93
|
+
record = build_record(input)
|
|
94
|
+
if record.key?(:debt)
|
|
95
|
+
debt << record[:debt]
|
|
96
|
+
next
|
|
97
|
+
end
|
|
98
|
+
key = JSON.generate(record[:case]["identifier"]) +
|
|
99
|
+
record[:case]["representations"]["human"]
|
|
100
|
+
(groups[key] ||= { record: record[:case],
|
|
101
|
+
inputs: [] })[:inputs] << input
|
|
102
|
+
end
|
|
103
|
+
cases = assign_ids(groups, type, results)
|
|
104
|
+
[cases, debt]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def assign_ids(groups, type, results)
|
|
108
|
+
groups.values.sort_by { |g| canonical_input(g) }.each_with_index
|
|
109
|
+
.map do |group, index|
|
|
110
|
+
record = group[:record]
|
|
111
|
+
record["id"] = format("%s.%s.%04d", @flavor, type, index + 1)
|
|
112
|
+
canonical = canonical_input(group)
|
|
113
|
+
record["style"] = Conformance.style_for(canonical)
|
|
114
|
+
inputs = group[:inputs]
|
|
115
|
+
duplicates = [inputs.count(canonical) - 1, 0].max
|
|
116
|
+
results[:duplicates] += duplicates
|
|
117
|
+
aliases = inputs.reject { |i| i == canonical }.uniq.sort
|
|
118
|
+
results[:aliases] += aliases.size
|
|
119
|
+
unless aliases.empty?
|
|
120
|
+
record["non_normalized_aliases"] = aliases.map do |a|
|
|
121
|
+
{ "input" => a, "style" => Conformance.style_for(a) }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
results[:roundtrip_failures] += 1 if record["roundtrip"] == false
|
|
125
|
+
results[:cases] += 1
|
|
126
|
+
record
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def canonical_input(group)
|
|
131
|
+
group.dig(:record, "representations", "human")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def build_record(input)
|
|
135
|
+
identifier = @flavor_module.parse(input)
|
|
136
|
+
hash = identifier.to_hash
|
|
137
|
+
representations = { "human" => identifier.to_s }
|
|
138
|
+
urn = safe_urn(identifier)
|
|
139
|
+
representations["urn"] = urn if urn
|
|
140
|
+
record = { "id" => nil,
|
|
141
|
+
"identifier" => Conformance.plainify(hash) }
|
|
142
|
+
record["representations"] = representations
|
|
143
|
+
record["roundtrip"] = false unless round_trips?(hash)
|
|
144
|
+
quarantine!(record) if bundled_month_bug?(hash)
|
|
145
|
+
{ case: record }
|
|
146
|
+
rescue StandardError => e
|
|
147
|
+
{ debt: { "id" => "#{@flavor}.debt.#{input.hash.abs}",
|
|
148
|
+
"input" => input,
|
|
149
|
+
"expect" => { "error" =>
|
|
150
|
+
{ "code" => Conformance.error_code_for(e) } },
|
|
151
|
+
"notes" => "unparsed ground-truth fixture: " \
|
|
152
|
+
"#{e.class}: #{e.message.to_s[0, 200]}" } }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Reference implementation parses bundled directive supplements with
|
|
156
|
+
# month-bearing dates nondeterministically across load orders (a
|
|
157
|
+
# spurious day component appears). Quarantine deterministically.
|
|
158
|
+
def bundled_month_bug?(hash)
|
|
159
|
+
hash.to_s.include?("bundled_identifier") && hash.to_s.include?("month")
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def quarantine!(record)
|
|
163
|
+
record.delete("identifier")
|
|
164
|
+
record.delete("representations")
|
|
165
|
+
record.delete("roundtrip")
|
|
166
|
+
record.delete("non_normalized_aliases")
|
|
167
|
+
record["notes"] = "nondeterministic parse in reference " \
|
|
168
|
+
"implementation (month/day divergence) - " \
|
|
169
|
+
"reference bug, quarantined from gates"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def round_trips?(hash)
|
|
173
|
+
@flavor_module::Identifier.from_hash(hash).to_hash == hash
|
|
174
|
+
rescue StandardError
|
|
175
|
+
false
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def safe_urn(identifier)
|
|
179
|
+
identifier.to_urn
|
|
180
|
+
rescue StandardError
|
|
181
|
+
nil
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def build_negative_cases(results)
|
|
185
|
+
cases = []
|
|
186
|
+
fail_files.each do |path|
|
|
187
|
+
type = File.basename(path, ".txt")
|
|
188
|
+
fail_fixture_lines(path).each_with_index do |input, index|
|
|
189
|
+
cases << negative_case(format("%s.neg.%s.%04d",
|
|
190
|
+
@flavor, type, index + 1), input)
|
|
191
|
+
results[:negative] += 1
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
cases
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def negative_case(id, input)
|
|
198
|
+
@flavor_module.parse(input)
|
|
199
|
+
{ "id" => id, "input" => input, "style" => Conformance.style_for(input),
|
|
200
|
+
"notes" => "fail fixture unexpectedly parsed - reclassify" }
|
|
201
|
+
rescue StandardError => e
|
|
202
|
+
{ "id" => id, "input" => input,
|
|
203
|
+
"expect" => { "error" =>
|
|
204
|
+
{ "code" => Conformance.error_code_for(e) } } }
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def write_yaml(path, entries)
|
|
208
|
+
File.write(path, YAML.dump(entries))
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Conformance
|
|
5
|
+
# Implementation-side PENDING markers: corpus cases this implementation
|
|
6
|
+
# explicitly cannot handle yet. The testsuite owns expectations; this
|
|
7
|
+
# file owns the admission that they are not met - so a pending case is
|
|
8
|
+
# visible debt, never a silent failure and never a hidden pass.
|
|
9
|
+
#
|
|
10
|
+
# Format (conformance/pending.yaml at the implementation repo root):
|
|
11
|
+
# "<case-id glob>":
|
|
12
|
+
# reason: <one line, the root cause>
|
|
13
|
+
# since: <YYYY-MM-DD>
|
|
14
|
+
# ref: <TODO.correct-test-suite PR queue entry or contract id>
|
|
15
|
+
#
|
|
16
|
+
# Rules enforced elsewhere: a pending case that passes raises the
|
|
17
|
+
# "pending satisfied - remove the marker" alarm; entries without a ref
|
|
18
|
+
# are rejected at load.
|
|
19
|
+
class Pending
|
|
20
|
+
PATH = File.expand_path("../../../conformance/pending.yaml", __dir__)
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def for(case_id)
|
|
24
|
+
entry = registry[case_id]
|
|
25
|
+
return entry if entry
|
|
26
|
+
|
|
27
|
+
registry.each do |pattern, meta|
|
|
28
|
+
next if pattern == case_id
|
|
29
|
+
|
|
30
|
+
return meta if File.fnmatch(pattern, case_id)
|
|
31
|
+
end
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def empty?
|
|
36
|
+
registry.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def registry
|
|
42
|
+
@registry ||= load_registry
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def load_registry
|
|
46
|
+
return {} unless File.exist?(PATH)
|
|
47
|
+
|
|
48
|
+
(YAML.safe_load_file(PATH) || {})
|
|
49
|
+
.to_h { |pattern, meta| [pattern, validated(meta, pattern)] }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def validated(meta, pattern)
|
|
53
|
+
unless meta.is_a?(Hash) && meta["reason"] && meta["ref"]
|
|
54
|
+
raise ArgumentError,
|
|
55
|
+
"pending entry #{pattern.inspect} needs reason and ref"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
meta
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Conformance
|
|
5
|
+
# Executes the pubid-testsuite corpus against this implementation.
|
|
6
|
+
# CLEAN flavors hard-gate (failures abort); DIRTY flavors report as
|
|
7
|
+
# the known reference-defect ledger.
|
|
8
|
+
class Runner
|
|
9
|
+
REGISTRY_KEYS = { "tgpp" => "3gpp" }.freeze
|
|
10
|
+
|
|
11
|
+
def run(flavors = corpus_flavors)
|
|
12
|
+
require "pubid"
|
|
13
|
+
|
|
14
|
+
if flavors.empty?
|
|
15
|
+
raise ArgumentError, "no corpus flavors found at #{corpus_dir} - " \
|
|
16
|
+
"refusing to report vacuous success"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Pubid.eager_load_flavors!
|
|
20
|
+
flavors.each_with_object([]) do |flavor, failures|
|
|
21
|
+
failures.concat(run_flavor(flavor))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def corpus_flavors
|
|
28
|
+
Dir[File.join(corpus_dir, "*")].select { |p| File.directory?(p) }
|
|
29
|
+
.map { |p| File.basename(p) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def corpus_dir
|
|
33
|
+
File.join(ENV.fetch("PUBID_TESTSUITE_PATH",
|
|
34
|
+
File.expand_path("../../../../pubid-testsuite",
|
|
35
|
+
__dir__)), "tests")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def run_flavor(flavor)
|
|
39
|
+
flavor_module = Pubid::Registry.get(
|
|
40
|
+
REGISTRY_KEYS.fetch(flavor, flavor),
|
|
41
|
+
)
|
|
42
|
+
raise ArgumentError, "unknown flavor #{flavor}" if flavor_module.nil?
|
|
43
|
+
|
|
44
|
+
stats = Hash.new(0)
|
|
45
|
+
failures = []
|
|
46
|
+
each_payload_case(flavor) do |test_case|
|
|
47
|
+
execute(test_case, flavor_module, stats, failures)
|
|
48
|
+
end
|
|
49
|
+
Corpus.negative_file(flavor, corpus_dir).each do |path|
|
|
50
|
+
Corpus.load_file(path).each do |test_case|
|
|
51
|
+
execute_negative(test_case, flavor_module, stats, failures)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
report(flavor, stats, failures)
|
|
55
|
+
known_dirty?(flavor) ? [] : failures
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def each_payload_case(flavor, &block)
|
|
59
|
+
Corpus.case_files(flavor, corpus_dir).each do |path|
|
|
60
|
+
Corpus.load_file(path).each(&block)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def known_dirty?(flavor)
|
|
65
|
+
status = File.join(corpus_dir, flavor, "_status.yaml")
|
|
66
|
+
File.exist?(status) && !YAML.safe_load_file(status)["clean"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Every corpus case lands in exactly one quadrant:
|
|
70
|
+
# pass | FAIL (not pending, breaks the CLEAN gate) | pending
|
|
71
|
+
# (explicitly not handled yet, see Conformance::Pending) | review
|
|
72
|
+
# (the expectation itself is flagged for human verification).
|
|
73
|
+
def execute(test_case, flavor_module, stats, failures)
|
|
74
|
+
id = test_case.id
|
|
75
|
+
return stats[:review] += 1 if test_case.review?
|
|
76
|
+
|
|
77
|
+
if Pending.for(id)
|
|
78
|
+
run_pending(id, test_case, flavor_module, stats, failures)
|
|
79
|
+
else
|
|
80
|
+
run_case(test_case, flavor_module, stats, failures)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Pending cases still run: a pending case that PASSES is reported as
|
|
85
|
+
# pending-satisfied - a cleanup alarm, the marker must be removed.
|
|
86
|
+
def run_pending(id, test_case, flavor_module, stats, failures)
|
|
87
|
+
stats[:pending] += 1
|
|
88
|
+
before = failures.size
|
|
89
|
+
run_case(test_case, flavor_module, stats, failures)
|
|
90
|
+
return failures.slice!(before..) if failures.size > before
|
|
91
|
+
|
|
92
|
+
stats[:pending_satisfied] += 1
|
|
93
|
+
puts " PENDING-SATISFIED #{id} - remove the marker"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def run_case(test_case, flavor_module, stats, failures)
|
|
97
|
+
if test_case.error_case?
|
|
98
|
+
execute_error_case(test_case, flavor_module, stats, failures)
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
return stats[:quarantined] += 1 if test_case.quarantined?
|
|
102
|
+
|
|
103
|
+
stats[:cases] += 1
|
|
104
|
+
Checks.check_case(test_case, flavor_module).each do |mismatch|
|
|
105
|
+
stat_for(mismatch, stats)
|
|
106
|
+
failures << mismatch
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def stat_for(mismatch, stats)
|
|
111
|
+
case mismatch
|
|
112
|
+
when / raised\z/ then stats[:fail_parse] += 1
|
|
113
|
+
when /canonical hash/ then stats[:fail_tree] += 1
|
|
114
|
+
when / human\z/, / urn\z/
|
|
115
|
+
stats[:"fail_#{mismatch.split.last}"] += 1
|
|
116
|
+
when / alias/ then stats[:fail_alias] += 1
|
|
117
|
+
else stats[:fail_roundtrip] += 1
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Negatives (fail fixtures decoded by the exporter). A row with
|
|
122
|
+
# expect.error must be rejected by the reference; a row without it
|
|
123
|
+
# is the exporter's reclassification alarm - the fail-fixture line
|
|
124
|
+
# now parses, so the fixture belongs in pass/ - reported, never
|
|
125
|
+
# gated, like the PENDING-SATISFIED alarm.
|
|
126
|
+
def execute_negative(test_case, flavor_module, stats, failures)
|
|
127
|
+
return stats[:reclass] += 1 unless test_case.error_case?
|
|
128
|
+
|
|
129
|
+
execute_error_case(test_case, flavor_module, stats, failures)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def execute_error_case(test_case, flavor_module, stats, failures)
|
|
133
|
+
stats[:error_cases] += 1
|
|
134
|
+
flavor_module.parse(test_case.input)
|
|
135
|
+
stats[:fail_error] += 1
|
|
136
|
+
failures << "#{test_case.id} unexpectedly parsed"
|
|
137
|
+
rescue StandardError
|
|
138
|
+
stats[:error_ok] += 1
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def report(flavor, stats, failures)
|
|
142
|
+
puts format(
|
|
143
|
+
"%-6s cases=%-6d err=%-4d quar=%-3d fail=%-4d " \
|
|
144
|
+
"pend=%-4d pendok=%-3d reclass=%-4d review=%d",
|
|
145
|
+
flavor, stats[:cases], stats[:error_cases], stats[:quarantined],
|
|
146
|
+
failures.size, stats[:pending], stats[:pending_satisfied],
|
|
147
|
+
stats[:reclass], stats[:review]
|
|
148
|
+
)
|
|
149
|
+
failures.first(10).each { |f| puts " FAIL #{f}" }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Pubid
|
|
7
|
+
# The shared, language-independent conformance corpus (conformance/).
|
|
8
|
+
# The identifier structure in each case is THE GEM'S OWN canonical
|
|
9
|
+
# to_hash, embedded verbatim (the same wire format relaton persists).
|
|
10
|
+
# Nothing is reinvented: the corpus adds only what the gem cannot know -
|
|
11
|
+
# representations, normalization aliases, styling, and neutral error
|
|
12
|
+
# codes for debt/negative records.
|
|
13
|
+
module Conformance
|
|
14
|
+
autoload :Checks, "pubid/conformance/checks"
|
|
15
|
+
autoload :Corpus, "pubid/conformance/corpus"
|
|
16
|
+
autoload :Generator, "pubid/conformance/generator"
|
|
17
|
+
autoload :Pending, "pubid/conformance/pending"
|
|
18
|
+
autoload :Runner, "pubid/conformance/runner"
|
|
19
|
+
|
|
20
|
+
# Neutral error vocabulary. Each implementation maps its native
|
|
21
|
+
# exceptions onto these codes; the corpus never records Ruby classes.
|
|
22
|
+
ERROR_CODES = {
|
|
23
|
+
"Parslet::ParseFailed" => "parse_failed",
|
|
24
|
+
"ArgumentError" => "invalid_argument",
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
def error_code_for(exception)
|
|
29
|
+
ERROR_CODES.fetch(exception.class.name, "unclassified")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Heuristic PubID styling version. v1 = legacy "ISO/R 2533/3-1975";
|
|
33
|
+
# v2 = dotted/uppercase ("AMD.1"); v3 = modern ("Amd 1"). Heuristic
|
|
34
|
+
# until the model exposes its parsed format (TODO.restructure/12).
|
|
35
|
+
def style_for(input)
|
|
36
|
+
return "v1" if /\bISO\/R\b|\bISO R\b/.match?(input)
|
|
37
|
+
return "v2" if /\b(?:Amd|AMD|Cor|COR|Suppl|SUPPL)\.\d/.match?(input)
|
|
38
|
+
|
|
39
|
+
"v3"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Hygiene only (not a redesign): guarantee the corpus is pure YAML -
|
|
43
|
+
# component objects leaking through serialization are reduced to
|
|
44
|
+
# their string rendering.
|
|
45
|
+
def plainify(value)
|
|
46
|
+
case value
|
|
47
|
+
when Hash then value.to_h { |key, entry| [key.to_s, plainify(entry)] }
|
|
48
|
+
when Array then value.map { |entry| plainify(entry) }
|
|
49
|
+
when String, Integer, Float, TrueClass, FalseClass, NilClass then value
|
|
50
|
+
else value.to_s
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/pubid/core.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "pubid"
|
|
3
4
|
module Pubid
|
|
4
5
|
# Core module for shared functionality across all flavors.
|
|
5
6
|
module Core
|
|
6
7
|
autoload :UpdateCodes, "#{__dir__}/core/update_codes"
|
|
8
|
+
autoload :PatternDocGenerator, "#{__dir__}/core/pattern_doc_generator"
|
|
7
9
|
end
|
|
8
10
|
end
|
data/lib/pubid/csa/builder.rb
CHANGED
|
@@ -101,7 +101,7 @@ module Pubid
|
|
|
101
101
|
else
|
|
102
102
|
begin
|
|
103
103
|
Pubid::Iso.parse(base_str)
|
|
104
|
-
rescue
|
|
104
|
+
rescue Parslet::ParseFailed
|
|
105
105
|
Pubid::Iec.parse(base_str)
|
|
106
106
|
end
|
|
107
107
|
end
|
|
@@ -128,17 +128,17 @@ module Pubid
|
|
|
128
128
|
end
|
|
129
129
|
amendment_str = "#{base_str}/Amd #{parsed_hash[:adoption_amendment]}:#{wrapped_amendment_year}"
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
base = if adoption_org.start_with?("ISO", "CEI")
|
|
132
|
+
Pubid::Iso.parse(amendment_str)
|
|
133
|
+
elsif adoption_org.start_with?("IEC")
|
|
134
|
+
Pubid::Iec.parse(amendment_str)
|
|
135
|
+
else
|
|
136
|
+
begin
|
|
137
|
+
Pubid::Iso.parse(amendment_str)
|
|
138
|
+
rescue Parslet::ParseFailed
|
|
139
|
+
Pubid::Iec.parse(amendment_str)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
142
|
else
|
|
143
143
|
# No amendment, simple base identifier
|
|
144
144
|
wrapped_id_str = "#{adoption_org} #{adoption_number}#{year_sep}#{wrapped_year}"
|
|
@@ -148,20 +148,20 @@ module Pubid
|
|
|
148
148
|
wrapped_id_str = wrapped_id_str.sub("CEI/IEC", "IEC")
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
151
|
+
base = if adoption_org.start_with?("ISO", "CEI")
|
|
152
|
+
Pubid::Iso.parse(wrapped_id_str)
|
|
153
|
+
elsif adoption_org.start_with?("IEC")
|
|
154
|
+
Pubid::Iec.parse(wrapped_id_str)
|
|
155
|
+
else
|
|
156
|
+
begin
|
|
157
|
+
Pubid::Iso.parse(wrapped_id_str)
|
|
158
|
+
rescue Parslet::ParseFailed
|
|
159
|
+
Pubid::Iec.parse(wrapped_id_str)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
adoption.
|
|
164
|
+
adoption.base = base
|
|
165
165
|
|
|
166
166
|
# Handle reaffirmation
|
|
167
167
|
if parsed_hash[:reaffirmation]
|
|
@@ -195,23 +195,25 @@ module Pubid
|
|
|
195
195
|
# SERIES matched - build Series identifier with CAN/CSA- prefix
|
|
196
196
|
# The Series.to_s will handle rendering as "CAN/CSA-A220 SERIES-06"
|
|
197
197
|
# (keeping the full prefix instead of "CAN/CSA-A220...")
|
|
198
|
-
|
|
198
|
+
base = build_series(wrapped_data)
|
|
199
199
|
# Set the full publisher_prefix on the wrapped Series for proper rendering
|
|
200
|
-
# The test expects
|
|
200
|
+
# The test expects base.publisher_prefix to be "CAN/CSA-"
|
|
201
201
|
elsif parsed_hash.key?(:cec_part)
|
|
202
202
|
# CEC matched - build Cec identifier
|
|
203
|
-
|
|
203
|
+
base = build_cec(wrapped_data)
|
|
204
204
|
else
|
|
205
205
|
# Standard CSA identifier
|
|
206
|
-
|
|
206
|
+
base = build_single(wrapped_data)
|
|
207
207
|
end
|
|
208
|
-
|
|
208
|
+
base.publisher_prefix = original_prefix if original_prefix && base.class.attributes.key?(:publisher_prefix)
|
|
209
209
|
|
|
210
|
-
canadian_adopted.
|
|
210
|
+
canadian_adopted.base = base
|
|
211
211
|
|
|
212
|
-
# Handle reaffirmation - supports both 2-digit and 4-digit years
|
|
213
|
-
#
|
|
214
|
-
#
|
|
212
|
+
# Handle reaffirmation - supports both 2-digit and 4-digit years.
|
|
213
|
+
# The wrapper's own original_reaffirmation_4digit is left at its
|
|
214
|
+
# default: CanadianAdopted#to_s only consults it when the wrapped id
|
|
215
|
+
# carries no reaffirmation of its own, and Series/Cec track the printed
|
|
216
|
+
# width themselves.
|
|
215
217
|
if parsed_hash[:reaffirmation_4digit]
|
|
216
218
|
# Original was 4-digit (e.g., "R2019")
|
|
217
219
|
canadian_adopted.reaffirmation = parsed_hash[:reaffirmation_4digit].to_s
|
|
@@ -251,7 +253,7 @@ module Pubid
|
|
|
251
253
|
|
|
252
254
|
# Code
|
|
253
255
|
if parsed_hash[:code]
|
|
254
|
-
series.
|
|
256
|
+
series.number = parsed_hash[:code].to_s
|
|
255
257
|
end
|
|
256
258
|
|
|
257
259
|
# Year format and year
|
|
@@ -451,10 +453,10 @@ module Pubid
|
|
|
451
453
|
def build_combined(parsed_hash)
|
|
452
454
|
combined = Identifiers::Combined.new
|
|
453
455
|
|
|
454
|
-
# Build each
|
|
455
|
-
combined.
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
# Build each designation, in printed order, into one collection.
|
|
457
|
+
combined.identifiers = %i[first second third]
|
|
458
|
+
.filter_map { |key| parsed_hash[key] }
|
|
459
|
+
.map { |part| build_single(part) }
|
|
458
460
|
|
|
459
461
|
# Detect separator from parser marker
|
|
460
462
|
combined.separator = if parsed_hash[:comma_separator]
|
|
@@ -495,15 +497,13 @@ module Pubid
|
|
|
495
497
|
identifier_class = select_identifier_class(data)
|
|
496
498
|
identifier = identifier_class.new
|
|
497
499
|
|
|
498
|
-
# Publisher prefix (CAN/CSA-, CAN3-, or CSA)
|
|
499
|
-
#
|
|
500
|
-
#
|
|
500
|
+
# Publisher prefix (CAN/CSA-, CAN3-, or CSA).
|
|
501
|
+
# A code with no prefix in the original is a code_only identifier; the
|
|
502
|
+
# flag stops rendering from supplying the default "CSA".
|
|
501
503
|
if data[:publisher_prefix]
|
|
502
504
|
identifier.publisher_prefix = data[:publisher_prefix].to_s
|
|
503
|
-
elsif data[:code]
|
|
504
|
-
|
|
505
|
-
# Use empty string to indicate "no prefix wanted"
|
|
506
|
-
identifier.publisher_prefix = ""
|
|
505
|
+
elsif data[:code]
|
|
506
|
+
identifier.code_only = true
|
|
507
507
|
end
|
|
508
508
|
|
|
509
509
|
# Publisher presence flag
|
|
@@ -520,13 +520,13 @@ module Pubid
|
|
|
520
520
|
# Pattern: "C22.1-15" should become code="C22.1", year="2015"
|
|
521
521
|
if !data[:year] && code_value =~ /^(.+)-(\d{2})$/
|
|
522
522
|
# Split code and year
|
|
523
|
-
identifier.
|
|
523
|
+
identifier.number = $1
|
|
524
524
|
# Convert 2-digit year to 4-digit
|
|
525
525
|
year_2digit = $2
|
|
526
526
|
identifier.year = "20#{year_2digit}"
|
|
527
527
|
identifier.year_format = "dash"
|
|
528
528
|
else
|
|
529
|
-
identifier.
|
|
529
|
+
identifier.number = code_value
|
|
530
530
|
end
|
|
531
531
|
end
|
|
532
532
|
|