pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.11
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/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 +0 -1
- 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 +0 -2
- data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
- 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 +16 -7
- 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 +9 -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 +2 -2
- 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 +17 -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/identifier.rb +6 -3
- data/lib/pubid/gb/parser.rb +1 -1
- data/lib/pubid/gb.rb +1 -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 +594 -10
- data/lib/pubid/identifier_metadata.rb +1 -0
- data/lib/pubid/idf/builder.rb +3 -3
- data/lib/pubid/idf/identifier.rb +18 -9
- data/lib/pubid/idf/parser.rb +1 -1
- data/lib/pubid/idf/renderer.rb +4 -4
- 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 +45 -1
- 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/ire/identifier.rb +2 -2
- data/lib/pubid/ieee/ire/parser.rb +1 -1
- data/lib/pubid/ieee/nesc/parser.rb +1 -1
- data/lib/pubid/ieee/parser.rb +1 -1
- data/lib/pubid/ieee/renderer.rb +5 -1
- data/lib/pubid/ieee/urn_generator.rb +32 -3
- data/lib/pubid/ieee.rb +7 -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/bundled_identifier.rb +5 -3
- data/lib/pubid/iso/combined_identifier.rb +5 -3
- data/lib/pubid/iso/identifier.rb +12 -7
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
- data/lib/pubid/iso/parser.rb +1 -1
- data/lib/pubid/iso.rb +7 -1
- 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 +19 -5
- 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/parser.rb +1 -1
- 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/components/stage.rb +2 -2
- data/lib/pubid/nist/configuration.rb +6 -8
- data/lib/pubid/nist/identifiers/base.rb +12 -2
- 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_standards_monthly.rb +7 -1
- data/lib/pubid/nist/identifiers/crpl_report.rb +7 -1
- 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 +14 -6
- 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/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 +5 -1
- data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
- data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
- 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 +1 -1
- data/lib/pubid/oiml/single_identifier.rb +26 -42
- data/lib/pubid/oiml/supplement_identifier.rb +27 -0
- 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 +3 -3
- 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/identifiers/base.rb +9 -2
- data/lib/pubid/sae/parser.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 +3 -3
- 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 +38 -17
- 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/cen_cenelec/supplement_identifier.rb +0 -48
- data/lib/pubid/iec/components/code.rb +0 -36
- /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
|
@@ -15,13 +15,42 @@ module Pubid
|
|
|
15
15
|
# Type is stored in @type attribute from Identifier
|
|
16
16
|
# All rendering handled by Identifier class
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
18
|
+
# --- Index columns -------------------------------------------------
|
|
19
|
+
#
|
|
20
|
+
# relaton-index sorts and bsearches every row on `id.root.number.to_s`,
|
|
21
|
+
# so the document number must be reachable as `number`. ETSI used to
|
|
22
|
+
# keep it inside an Etsi::Components::Code under a `code` attribute,
|
|
23
|
+
# leaving the inherited `number` nil and every index row keyed "".
|
|
24
|
+
#
|
|
25
|
+
# The three Code fields are now plain sibling attributes, which is the
|
|
26
|
+
# shape the serialized hash ALREADY had — the converters below merely
|
|
27
|
+
# read them directly instead of reaching through `code`, so the wire
|
|
28
|
+
# format is byte-identical and relaton-data-etsi's published index-v2
|
|
29
|
+
# needs no regeneration.
|
|
30
|
+
#
|
|
31
|
+
# `number` holds the BARE number ("300 175"), never the part, so all
|
|
32
|
+
# parts of a document share one index bucket and a part-less reference
|
|
33
|
+
# finds them all — the IEEE/ISO semantics documented in CLAUDE.md.
|
|
34
|
+
#
|
|
35
|
+
# LANDMINE: these redeclare attributes inherited from ::Pubid::Identifier
|
|
36
|
+
# (`number` is a Components::Code there, and Etsi::Components::Code is
|
|
37
|
+
# NOT a subclass of it). That resolves nondeterministically under
|
|
38
|
+
# multi-flavor load when declared on a class others inherit from, so it
|
|
39
|
+
# is confined to this LEAF — EtsiStandard has no subclasses, while the
|
|
40
|
+
# shared Pubid::Etsi::Identifier is also SupplementIdentifier's parent
|
|
41
|
+
# and must stay untouched. spec/pubid/etsi/root_number_spec.rb carries
|
|
42
|
+
# the tripwire and is only meaningful under the full `rake` suite.
|
|
43
|
+
attribute :number, :string
|
|
44
|
+
attribute :minor, :string
|
|
45
|
+
attribute :parts, :string, collection: true, default: -> { [] }
|
|
46
|
+
|
|
47
|
+
# Compact serialization (mirrors ISO/JCGM/OIML): the code fields are
|
|
48
|
+
# bare scalars (`number`, a `parts` array and, rarely, a `minor`);
|
|
49
|
+
# Version flattens to a scalar `version` string with an `is_edition`
|
|
50
|
+
# boolean flag (omitted when false); Date flattens to top-level
|
|
51
|
+
# year/month/day. The constant `publisher` ("ETSI") is intentionally
|
|
52
|
+
# NOT mapped — it is reconstructed on load from its attribute default,
|
|
53
|
+
# keeping the hash compact.
|
|
25
54
|
#
|
|
26
55
|
# This block lives on EtsiStandard (a leaf) rather than the shared Identifier:
|
|
27
56
|
# SupplementIdentifier is a sibling that DELEGATES type/code/version and
|
|
@@ -30,9 +59,9 @@ module Pubid
|
|
|
30
59
|
key_value do
|
|
31
60
|
map "_type", to: :_type
|
|
32
61
|
map "type", to: :type
|
|
33
|
-
map "number",
|
|
34
|
-
map "parts",
|
|
35
|
-
map "minor",
|
|
62
|
+
map "number", to: :number
|
|
63
|
+
map "parts", to: :parts
|
|
64
|
+
map "minor", to: :minor
|
|
36
65
|
map "version", with: { to: :version_to_kv, from: :version_from_kv }
|
|
37
66
|
map "is_edition", with: { to: :edition_to_kv, from: :edition_from_kv }
|
|
38
67
|
map "year", with: { to: :year_to_kv, from: :year_from_kv }
|
|
@@ -40,36 +69,90 @@ module Pubid
|
|
|
40
69
|
map "day", with: { to: :day_to_kv, from: :day_from_kv }
|
|
41
70
|
end
|
|
42
71
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def parts_to_kv(model, doc)
|
|
61
|
-
parts = model.code&.parts
|
|
62
|
-
return if parts.nil? || parts.empty?
|
|
63
|
-
|
|
64
|
-
doc.add_child(
|
|
65
|
-
Lutaml::KeyValue::DataModel::Element.new(
|
|
66
|
-
"parts", parts.map(&:to_s)
|
|
67
|
-
),
|
|
72
|
+
# The composed document code, rebuilt on demand from the split columns
|
|
73
|
+
# so the renderer, the URN generator and #== keep one place to ask for
|
|
74
|
+
# the printed form ("300 175-1"). Deliberately NOT an attribute and NOT
|
|
75
|
+
# memoised: `number`/`parts` are writable (the base #exclude rebuilds
|
|
76
|
+
# through them), so a cached Code would go stale.
|
|
77
|
+
#
|
|
78
|
+
# nil when there is no number, preserving the old nil-`code` semantics
|
|
79
|
+
# the URN generator branches on.
|
|
80
|
+
def code
|
|
81
|
+
return nil if number.nil?
|
|
82
|
+
|
|
83
|
+
Pubid::Etsi::Components::Code.new(
|
|
84
|
+
number: number,
|
|
85
|
+
minor: minor,
|
|
86
|
+
parts: parts || [],
|
|
68
87
|
)
|
|
69
88
|
end
|
|
70
89
|
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
# MR slug number segment.
|
|
91
|
+
#
|
|
92
|
+
# The base hook reads the inherited `number` and `part`; ETSI kept
|
|
93
|
+
# neither, so before the index columns landed every ETSI slug was just
|
|
94
|
+
# `etsi.<date>` — 454 distinct slugs for 24,724 documents, and
|
|
95
|
+
# `to_slug` is what consumers use as an output FILENAME.
|
|
96
|
+
#
|
|
97
|
+
# Two things the base hook cannot do for ETSI:
|
|
98
|
+
# * the parts live in the `parts` collection, not the inherited
|
|
99
|
+
# scalar `part`, so they must be appended here or every part of a
|
|
100
|
+
# document collapses onto one slug;
|
|
101
|
+
# * an ETSI number legitimately contains a SPACE ("300 175", "GSM
|
|
102
|
+
# 02.01"), which is outside the [a-z0-9.-] charset Renderers::MrString
|
|
103
|
+
# documents and guarantees. Sanitize BY CHARSET rather than by an
|
|
104
|
+
# enumerated escape list (the BIPM `mr_slug` precedent in
|
|
105
|
+
# CLAUDE.md), so a character added later cannot reach a filename.
|
|
106
|
+
# `minor` is included because it is identity-bearing everywhere else —
|
|
107
|
+
# Code#== compares it, Code#to_s renders it and the URN carries it — so
|
|
108
|
+
# omitting it here would let two distinct documents share one filename.
|
|
109
|
+
# No fixture populates it today; it is in the grammar, so it is here.
|
|
110
|
+
def mr_number_with_part
|
|
111
|
+
return nil if number.nil?
|
|
112
|
+
|
|
113
|
+
mr_sanitize([number, minor, *Array(parts)].compact.join("-"))
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# ETSI's identity is type + code + version + date (see
|
|
117
|
+
# Pubid::Etsi::Identifier#==), so all four must reach the slug —
|
|
118
|
+
# CLAUDE.md's rule that an identity-bearing marker has to appear on
|
|
119
|
+
# every identity surface, not just in `==`. The base hooks find
|
|
120
|
+
# neither: `mr_type` reads `typed_stage` (ETSI has none) and
|
|
121
|
+
# `mr_edition` reads `edition.number` (ETSI models the edition as
|
|
122
|
+
# `version`). Without these, "ETSI EN 300 729 V6.1.1 (2000-04)",
|
|
123
|
+
# "…V7.1.1 (2000-04)" and "ETSI ETS 300 729 ed.2 (2000-04)" all share
|
|
124
|
+
# one slug — i.e. one output filename.
|
|
125
|
+
def mr_type
|
|
126
|
+
type&.to_s&.downcase
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def mr_edition
|
|
130
|
+
mr_sanitize(version&.version)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Segment sanitizer. Renderers::MrString joins SEGMENTS with ".", so a
|
|
134
|
+
# dot inside one would break that structure — hence "." is replaced
|
|
135
|
+
# here even though it is inside the renderer's overall charset (the
|
|
136
|
+
# BIPM `bipm.si-brochure.9e-v3-01.e` precedent in CLAUDE.md). Filtering
|
|
137
|
+
# by charset rather than by an enumerated escape list keeps a character
|
|
138
|
+
# introduced later from leaking into a filename.
|
|
139
|
+
#
|
|
140
|
+
# Public purely to keep this file's surface flat, next to the
|
|
141
|
+
# lutaml-invoked converters below — it has no external callers and
|
|
142
|
+
# would work as well private.
|
|
143
|
+
#
|
|
144
|
+
# The emptiness check is on the OUTPUT, not just the input: a value
|
|
145
|
+
# made entirely of characters outside the charset collapses to "-" and
|
|
146
|
+
# then to "", and an empty string is truthy in Ruby, so it would reach
|
|
147
|
+
# Renderers::MrString as a blank segment and produce a double dot in
|
|
148
|
+
# the joined slug. Unreachable from today's grammar, which only feeds
|
|
149
|
+
# digit/alnum captures here — but not structurally prevented.
|
|
150
|
+
def mr_sanitize(value)
|
|
151
|
+
return nil if value.nil? || value.to_s.empty?
|
|
152
|
+
|
|
153
|
+
sanitized = value.to_s.downcase
|
|
154
|
+
.gsub(/[^a-z0-9-]+/, "-").gsub(/\A-+|-+\z/, "")
|
|
155
|
+
sanitized.empty? ? nil : sanitized
|
|
73
156
|
end
|
|
74
157
|
|
|
75
158
|
# --- Version flattened to scalar version + is_edition flag ---
|
|
@@ -126,10 +209,6 @@ module Pubid
|
|
|
126
209
|
)
|
|
127
210
|
end
|
|
128
211
|
|
|
129
|
-
def code_for(model)
|
|
130
|
-
model.code ||= Pubid::Etsi::Components::Code.new
|
|
131
|
-
end
|
|
132
|
-
|
|
133
212
|
def version_for(model)
|
|
134
213
|
model.version ||= Pubid::Etsi::Components::Version.new
|
|
135
214
|
end
|
|
@@ -88,6 +88,16 @@ module Pubid
|
|
|
88
88
|
raise NotImplementedError
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
# Make Renderers::MrString recurse into `base` instead of slugging the
|
|
92
|
+
# supplement flat. Without this the flat path reads the supplement's own
|
|
93
|
+
# `number` — its ordinal, 1 — and the base document is dropped entirely,
|
|
94
|
+
# so every "/C1" corrigendum published in one month shared the slug
|
|
95
|
+
# `etsi.1.<date>`. `to_slug` is an output FILENAME, so that is an
|
|
96
|
+
# overwrite. Same fix as ITU's AnnexOfRecommendation (see CLAUDE.md).
|
|
97
|
+
def mr_supplement_suffix
|
|
98
|
+
[supplement_notation.to_s.downcase, number].compact.join(".")
|
|
99
|
+
end
|
|
100
|
+
|
|
91
101
|
def ==(other)
|
|
92
102
|
return false unless other.is_a?(SupplementIdentifier)
|
|
93
103
|
return false unless other.class == self.class
|
data/lib/pubid/etsi/parser.rb
CHANGED
data/lib/pubid/etsi.rb
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
# Builds an EVS national adoption from the composed parse tree: the
|
|
6
|
+
# structured :adopted subtree (produced by the embedded CEN grammar) goes
|
|
7
|
+
# straight to the CEN/CENELEC builder as data — no string
|
|
8
|
+
# re-serialization anywhere.
|
|
9
|
+
class Builder < Pubid::Builder::Base
|
|
10
|
+
def self.build(parsed_data)
|
|
11
|
+
new.build(parsed_data)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def build(data)
|
|
15
|
+
data = flatten_array(data) if data.is_a?(Array)
|
|
16
|
+
|
|
17
|
+
adopted = Pubid::CenCenelec::Builder.build(data[:adopted])
|
|
18
|
+
|
|
19
|
+
Identifiers::NationalAdoption.new(
|
|
20
|
+
adopted_identifier: adopted,
|
|
21
|
+
separator: data[:evs_separator] || "-",
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
# An EVS national adoption wraps a CEN identifier the same way BSI's
|
|
6
|
+
# AdoptedEuropeanNorm does — polymorphic `adopted_identifier` so the
|
|
7
|
+
# wrapped object stays a real Pubid::CenCenelec identifier.
|
|
8
|
+
#
|
|
9
|
+
# Examples:
|
|
10
|
+
# "EVS-EN 18216:2026" (adopted_identifier: EN 18216:2026)
|
|
11
|
+
# "EVS-EN ISO 14001:2026" (adopted_identifier: EN ISO 14001:2026)
|
|
12
|
+
# "EVS-EN ISO/IEC 27017:2026" (adopted_identifier: EN ISO/IEC 27017:2026)
|
|
13
|
+
# "EVS-EN ISO 9001:2015/A1:2024" (adopted_identifier: EN ISO 9001:2015/A1:2024)
|
|
14
|
+
class Identifier < ::Pubid::Identifier
|
|
15
|
+
attribute :adopted_identifier, ::Pubid::Identifier, polymorphic: true
|
|
16
|
+
# "-" or " " — preserves the printed separator ("EVS-EN" vs "EVS EN")
|
|
17
|
+
attribute :separator, :string, default: -> { "-" }
|
|
18
|
+
|
|
19
|
+
def to_s(**opts)
|
|
20
|
+
render(format: :human, **opts)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.parse(string)
|
|
24
|
+
unless string.is_a?(String)
|
|
25
|
+
raise Pubid::Errors::InvalidInputError,
|
|
26
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if string.length > Pubid::MAX_INPUT_LENGTH
|
|
30
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Pubid::Evs.parse(string)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
module Identifiers
|
|
6
|
+
# The EVS national adoption of a European Standard.
|
|
7
|
+
# Example: "EVS-EN 18216:2026"
|
|
8
|
+
class NationalAdoption < ::Pubid::Evs::Identifier
|
|
9
|
+
attribute :type, Components::Type, default: -> { self.class.type[:key] }
|
|
10
|
+
|
|
11
|
+
def self.type
|
|
12
|
+
{ key: :evs_en, title: "EVS National Adoption of a European Standard" }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parslet"
|
|
4
|
+
|
|
5
|
+
module Pubid
|
|
6
|
+
module Evs
|
|
7
|
+
# Grammar for the printed EVS national-adoption reference, composed with
|
|
8
|
+
# the CEN/CENELEC parser as an embedded atom (the same pattern ISO uses
|
|
9
|
+
# for IDF joint identifiers, and IEEE for AIEE/IRE/NESC):
|
|
10
|
+
#
|
|
11
|
+
# "EVS" ("-" | " ") <CEN identifier>
|
|
12
|
+
#
|
|
13
|
+
# The adopted portion is parsed by the real CEN grammar — publisher,
|
|
14
|
+
# adopted org, number, parts, year, supplements, edition — and captured
|
|
15
|
+
# as a structured :adopted subtree for the CEN builder.
|
|
16
|
+
#
|
|
17
|
+
# "EVS-EN 18216:2026" → {evs_separator, adopted: {publisher, number, year}}
|
|
18
|
+
# "EVS-EN ISO 9001:2015/A1:2024" → {evs_separator, adopted: {publisher, adopted_string, supplements}}
|
|
19
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
20
|
+
rule(:root) do
|
|
21
|
+
str("EVS") >>
|
|
22
|
+
(str("-") | str(" ")).as(:evs_separator) >>
|
|
23
|
+
::Pubid::CenCenelec::Parser.new.identifier.as(:adopted)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
# Human-readable renderer for EVS identifiers.
|
|
6
|
+
#
|
|
7
|
+
# Produces strings like:
|
|
8
|
+
# "EVS-EN 18216:2026"
|
|
9
|
+
# "EVS-EN ISO 14001:2026"
|
|
10
|
+
# "EVS-EN ISO/IEC 27017:2026"
|
|
11
|
+
# "EVS-EN ISO 9001:2015/A1:2024"
|
|
12
|
+
class Renderer < ::Pubid::Renderers::Base
|
|
13
|
+
def render(context: nil, **_opts)
|
|
14
|
+
# The adopted identifier renders with its own "EN …" prefix, so the
|
|
15
|
+
# national prefix composes as "EVS" + separator + adopted.
|
|
16
|
+
"EVS#{separator}#{adopted}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def separator
|
|
22
|
+
@id.separator || "-"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def adopted
|
|
26
|
+
@id.adopted_identifier.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
# URNs mirror the CEN adoption namespace with the national-body prefix:
|
|
6
|
+
#
|
|
7
|
+
# "EVS-EN 18216:2026" → urn:evs:en:18216:2026
|
|
8
|
+
# "EVS-EN ISO 14001:2026" → urn:evs:en:iso:14001:2026
|
|
9
|
+
# "EVS-EN ISO/IEC 27017:2026" → urn:evs:en:iso-iec:27017:2026
|
|
10
|
+
# "EVS-EN ISO 9001:2015/A1:2024" → urn:evs:en:iso:9001:2015:amd:1:2024
|
|
11
|
+
#
|
|
12
|
+
# Generation delegates to the adopted CEN identifier's URN and swaps the
|
|
13
|
+
# `urn:cen:` namespace for `urn:evs:`, so the two stay consistent by
|
|
14
|
+
# construction.
|
|
15
|
+
class UrnGenerator < Pubid::UrnGenerator::Base
|
|
16
|
+
CEN_NAMESPACE = "urn:cen:"
|
|
17
|
+
EVS_NAMESPACE = "urn:evs:"
|
|
18
|
+
|
|
19
|
+
def generate
|
|
20
|
+
adopted_urn = identifier.adopted_identifier.to_urn
|
|
21
|
+
unless adopted_urn.start_with?(CEN_NAMESPACE)
|
|
22
|
+
raise Errors::ParseError,
|
|
23
|
+
"expected adopted CEN URN, got #{adopted_urn.inspect}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
adopted_urn.sub(/\A#{Regexp.escape(CEN_NAMESPACE)}/o, EVS_NAMESPACE)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Evs
|
|
5
|
+
# Parses `urn:evs:…` URNs back into identifiers, following the same
|
|
6
|
+
# pattern as Pubid::CenCenelec::UrnParser: reassemble the adopted
|
|
7
|
+
# identifier's human text and delegate to the real grammar so every
|
|
8
|
+
# structural check happens in parsers, not in this class.
|
|
9
|
+
#
|
|
10
|
+
# urn:evs:en:18216:2026 → EVS-EN 18216:2026
|
|
11
|
+
# urn:evs:en:iso:14001:2026 → EVS-EN ISO 14001:2026
|
|
12
|
+
# urn:evs:en:iso-iec:27017:2026 → EVS-EN ISO/IEC 27017:2026
|
|
13
|
+
# urn:evs:en:iso:9001:2015:amd:1:2024 → EVS-EN ISO 9001:2015/A1:2024
|
|
14
|
+
class UrnParser < Pubid::UrnParser::Base
|
|
15
|
+
ORGS = {
|
|
16
|
+
"iso" => "ISO",
|
|
17
|
+
"iso-iec" => "ISO/IEC",
|
|
18
|
+
"iec" => "IEC",
|
|
19
|
+
"cispr" => "CISPR",
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# UrnGenerator emits "urn:evs:" (national-body namespace).
|
|
23
|
+
def flavor_name
|
|
24
|
+
"evs"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parse_urn(urn)
|
|
28
|
+
parts = split_parts(strip_namespace(urn))
|
|
29
|
+
|
|
30
|
+
type = parts.shift
|
|
31
|
+
unless /\Aen\z/i.match?(type)
|
|
32
|
+
raise Errors::ParseError, "unsupported type in #{urn.inspect}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
text = +"EN"
|
|
36
|
+
org_parts = []
|
|
37
|
+
org_parts << parts.shift while parts.first&.match?(/\A[a-z][a-z-]*\z/)
|
|
38
|
+
if org_parts.any?
|
|
39
|
+
org = ORGS.fetch(org_parts.join("-")) do
|
|
40
|
+
raise Errors::ParseError, "unknown adopted org in #{urn.inspect}"
|
|
41
|
+
end
|
|
42
|
+
text << " #{org}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
number = parts.shift
|
|
46
|
+
year = parts.shift
|
|
47
|
+
unless number
|
|
48
|
+
raise Errors::ParseError,
|
|
49
|
+
"missing number in #{urn.inspect}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
text << " #{number}"
|
|
53
|
+
text << ":#{year}" if year
|
|
54
|
+
|
|
55
|
+
append_supplement(text, parts, urn) unless parts.empty?
|
|
56
|
+
|
|
57
|
+
adopted = Pubid::CenCenelec.parse(text)
|
|
58
|
+
::Pubid::Evs::Identifiers::NationalAdoption.new(
|
|
59
|
+
adopted_identifier: adopted,
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# Appends the trailing `amd|cor : iteration [: year]` in human form.
|
|
66
|
+
def append_supplement(text, parts, urn)
|
|
67
|
+
year = parts.last&.match?(/\A\d{4}\z/) ? parts.pop : nil
|
|
68
|
+
kind = parts.shift
|
|
69
|
+
iteration = parts.shift
|
|
70
|
+
unless %w[amd cor].include?(kind) && iteration && parts.empty?
|
|
71
|
+
raise Errors::ParseError, "malformed supplement in #{urn.inspect}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
text << (kind == "amd" ? "/A#{iteration}" : "/AC#{iteration}")
|
|
75
|
+
text << ":#{year}" if year
|
|
76
|
+
text
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/pubid/evs.rb
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pubid"
|
|
4
|
+
module Pubid
|
|
5
|
+
module Evs
|
|
6
|
+
extend Pubid::PrefixesSupport
|
|
7
|
+
|
|
8
|
+
# Leading tokens a printed EVS reference can start with, drawn from the
|
|
9
|
+
# reference PDFs in metanorma/mn-samples-evs-private. Longest first so
|
|
10
|
+
# prefix routing picks the most specific claim. Deliberately EXCLUDES the
|
|
11
|
+
# bare adopted forms ("EN …" alone routes to Pubid::CenCenelec).
|
|
12
|
+
PREFIXES = [
|
|
13
|
+
"EVS-EN ISO/IEC", "EVS-EN ISO", "EVS-EN",
|
|
14
|
+
"EVS EN ISO/IEC", "EVS EN ISO", "EVS EN",
|
|
15
|
+
"EVS"
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
autoload :Builder, "#{__dir__}/evs/builder"
|
|
19
|
+
autoload :Identifier, "#{__dir__}/evs/identifier"
|
|
20
|
+
autoload :Identifiers, "#{__dir__}/evs/identifiers"
|
|
21
|
+
autoload :Parser, "#{__dir__}/evs/parser"
|
|
22
|
+
autoload :Renderer, "#{__dir__}/evs/renderer"
|
|
23
|
+
autoload :UrnGenerator, "#{__dir__}/evs/urn_generator"
|
|
24
|
+
autoload :UrnParser, "#{__dir__}/evs/urn_parser"
|
|
25
|
+
|
|
26
|
+
def self.parse(identifier)
|
|
27
|
+
unless identifier.is_a?(String)
|
|
28
|
+
raise Pubid::Errors::InvalidInputError,
|
|
29
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
33
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
parsed = Parser.new.parse(identifier)
|
|
37
|
+
Builder.new.build(parsed)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Build an EVS identifier from a parse-tree hash.
|
|
41
|
+
# @param hash [Hash] parse tree
|
|
42
|
+
# @return [Pubid::Evs::Identifier]
|
|
43
|
+
def self.build_from_parse(hash)
|
|
44
|
+
Builder.new.build(hash)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Per-flavor format registry: inherits global formats, overrides :human.
|
|
48
|
+
Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
|
|
49
|
+
Identifier.format_registry.register(:human, renderer: Evs::Renderer)
|
|
50
|
+
|
|
51
|
+
# Auto-discover all identifier types from the Identifiers namespace.
|
|
52
|
+
# @return [Array<Class>]
|
|
53
|
+
def self.identifier_types
|
|
54
|
+
@identifier_types ||= Identifiers.constants.filter_map do |c|
|
|
55
|
+
begin
|
|
56
|
+
Identifiers.const_get(c)
|
|
57
|
+
rescue NameError
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
.select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
|
|
62
|
+
.select { |c| c.type.is_a?(Hash) }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# EVS identifiers have no typed stages.
|
|
66
|
+
# @return [Array<Pubid::Components::TypedStage>]
|
|
67
|
+
def self.all_typed_stages
|
|
68
|
+
@all_typed_stages ||= identifier_types.flat_map do |klass|
|
|
69
|
+
klass.const_defined?(:TYPED_STAGES) ? klass.const_get(:TYPED_STAGES) : []
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Lookup: type code -> identifier class
|
|
74
|
+
# @param code [String, Symbol]
|
|
75
|
+
# @return [Class, nil]
|
|
76
|
+
def self.locate_type(code)
|
|
77
|
+
identifier_types.find { |t| t.type[:key].to_s == code.to_s }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Lookup: abbreviation -> typed stage
|
|
81
|
+
# @param _abbr [String, Symbol]
|
|
82
|
+
# @return [nil] EVS identifiers have no typed stages
|
|
83
|
+
def self.locate_stage(_abbr)
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Register EVS flavor with the registry
|
|
90
|
+
Pubid::Registry.register(:evs, Pubid::Evs)
|
data/lib/pubid/export.rb
CHANGED
data/lib/pubid/gb/identifier.rb
CHANGED
|
@@ -50,14 +50,17 @@ module Pubid
|
|
|
50
50
|
# @param identifier [String]
|
|
51
51
|
# @return [Pubid::Gb::Identifier]
|
|
52
52
|
def self.parse(identifier)
|
|
53
|
+
unless identifier.is_a?(String)
|
|
54
|
+
raise Pubid::Errors::InvalidInputError,
|
|
55
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
56
|
+
end
|
|
57
|
+
|
|
53
58
|
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
54
|
-
raise
|
|
59
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
parsed = Parser.parse(identifier)
|
|
58
63
|
Builder.build(parsed)
|
|
59
|
-
rescue Parslet::ParseFailed => e
|
|
60
|
-
raise "Failed to parse Chinese Standard identifier '#{identifier}': #{e.message}"
|
|
61
64
|
end
|
|
62
65
|
end
|
|
63
66
|
end
|
data/lib/pubid/gb/parser.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Pubid
|
|
|
14
14
|
# T/GZAEPI, ...). TYPE is T (recommended), Z (guideline), or omitted.
|
|
15
15
|
# YEAR is 4 digits, separated by either ASCII dash or em-dash (Chinese
|
|
16
16
|
# typography uses the em-dash form).
|
|
17
|
-
class Parser <
|
|
17
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
18
18
|
rule(:space) { str(" ") }
|
|
19
19
|
rule(:dot) { str(".") }
|
|
20
20
|
rule(:dash) { str("-") | str("—") }
|