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
data/lib/pubid/easc.rb
CHANGED
data/lib/pubid/ecma/builder.rb
CHANGED
|
@@ -10,21 +10,35 @@ module Pubid
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def build(data)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
klass, attrs =
|
|
14
|
+
if data[:tr_number]
|
|
15
|
+
[Identifiers::TechnicalReport, { number: data[:tr_number].to_s }]
|
|
16
|
+
elsif data[:mem_number]
|
|
17
|
+
[Identifiers::Memento, { number: data[:mem_number].to_s }]
|
|
18
|
+
else
|
|
19
|
+
[Identifiers::Standard, standard_attrs(data)]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
klass.new(**attrs, **suffix_attrs(data))
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
private
|
|
23
26
|
|
|
24
|
-
def
|
|
27
|
+
def standard_attrs(data)
|
|
25
28
|
attrs = { number: data[:number].to_s }
|
|
26
29
|
attrs[:part] = data[:part].to_s if data[:part]
|
|
27
|
-
|
|
30
|
+
attrs
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# ` ed<N>` / ` vol<N>` attach after the type alternation, so a technical
|
|
34
|
+
# report and a memento carry them exactly as a standard does. An absent
|
|
35
|
+
# suffix produces no parse key at all, so the attribute stays unset and
|
|
36
|
+
# drops out of the canonical hash.
|
|
37
|
+
def suffix_attrs(data)
|
|
38
|
+
attrs = {}
|
|
39
|
+
attrs[:edition] = data[:edition].to_s if data[:edition]
|
|
40
|
+
attrs[:volume] = data[:volume].to_s if data[:volume]
|
|
41
|
+
attrs
|
|
28
42
|
end
|
|
29
43
|
end
|
|
30
44
|
end
|
|
@@ -6,17 +6,32 @@ module Pubid
|
|
|
6
6
|
# mirrors Pubid::Jis::Identifier. Concrete identifiers under
|
|
7
7
|
# Pubid::Ecma::Identifiers descend from this class, so a parsed ECMA id is
|
|
8
8
|
# an instance of Pubid::Ecma::Identifier. ECMA has no supplement layer.
|
|
9
|
+
# KEEP THIS CLASS BODY IN ONE FILE, AND NEVER REOPEN IT. `number`, `part`
|
|
10
|
+
# and `edition` below redeclare attributes the parent ::Pubid::Identifier
|
|
11
|
+
# types as components, which resolves nondeterministically under
|
|
12
|
+
# multi-flavor load if a subclass can snapshot a half-built attribute
|
|
13
|
+
# table. lutaml deep-dups the parent table into each subclass at
|
|
14
|
+
# class-definition time, and Ruby resolves this superclass constant to
|
|
15
|
+
# completion before opening any leaf body — so a single, never-reopened
|
|
16
|
+
# body is what makes the redeclaration safe. (The W3C precedent; IEEE's
|
|
17
|
+
# split base is the counter-shape.)
|
|
9
18
|
class Identifier < ::Pubid::Identifier
|
|
10
19
|
# The document number as a string (preserves any leading zeros). `part`
|
|
11
20
|
# is only present for standards that split into parts (e.g. ECMA-418-1).
|
|
12
21
|
attribute :number, :string
|
|
13
22
|
attribute :part, :string
|
|
14
|
-
# Edition is
|
|
15
|
-
# has edition.content)
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
23
|
+
# Edition is relaton's `:ed:` (the index stores {:id, :ed, :vol} and the
|
|
24
|
+
# YAML has edition.content). It is part of the printed identifier: the
|
|
25
|
+
# relaton index keys on a bare `to_s`, so without it all 22 editions of
|
|
26
|
+
# ECMA-74 collapse onto one key. An optional string, because decimal
|
|
27
|
+
# editions like "5.1" occur. No default, so it drops from the hash when
|
|
28
|
+
# unset.
|
|
19
29
|
attribute :edition, :string
|
|
30
|
+
# Volume is relaton's `:vol:`. Only ECMA-269 edition 3 uses it: its four
|
|
31
|
+
# volumes share one docidentifier AND one title, so the volume is the only
|
|
32
|
+
# thing that distinguishes those four index rows. A plain string, the
|
|
33
|
+
# `number`/`edition` precedent, so it round-trips verbatim.
|
|
34
|
+
attribute :volume, :string
|
|
20
35
|
|
|
21
36
|
# Polymorphic type map for lutaml::Model key_value (de)serialization:
|
|
22
37
|
# maps each subclass's polymorphic_name to its class name so a stored
|
|
@@ -33,6 +48,7 @@ module Pubid
|
|
|
33
48
|
map "number", to: :number
|
|
34
49
|
map "part", to: :part
|
|
35
50
|
map "edition", to: :edition
|
|
51
|
+
map "volume", to: :volume
|
|
36
52
|
end
|
|
37
53
|
|
|
38
54
|
# Publisher is always "ECMA". A plain constant (not a `publisher` method)
|
|
@@ -45,6 +61,11 @@ module Pubid
|
|
|
45
61
|
|
|
46
62
|
# Basic string representation. Delegates to renderer. `with_publisher:
|
|
47
63
|
# false` drops the ECMA token (e.g. "-411", "TR/84").
|
|
64
|
+
#
|
|
65
|
+
# The edition and volume suffixes are rendered by DEFAULT and are opted
|
|
66
|
+
# out of with `to_s(with_edition: false, with_volume: false)`. Both flags
|
|
67
|
+
# ride in `opts` to the renderer, which owns their defaults — see
|
|
68
|
+
# Pubid::Ecma::Renderer for why the default is "with".
|
|
48
69
|
def to_s(with_publisher: true, **opts)
|
|
49
70
|
@with_publisher = with_publisher
|
|
50
71
|
render(format: :human, **opts)
|
|
@@ -56,20 +77,70 @@ module Pubid
|
|
|
56
77
|
nil
|
|
57
78
|
end
|
|
58
79
|
|
|
80
|
+
# ECMA keeps its publisher in the PUBLISHER constant rather than the
|
|
81
|
+
# inherited `publisher` attribute, so the base hook — `publisher&.to_s` —
|
|
82
|
+
# is nil and every ECMA slug would lose its "ecma." segment.
|
|
83
|
+
def mr_publisher
|
|
84
|
+
PUBLISHER.downcase
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The Builder picks an identifier class; it never sets a `typed_stage`,
|
|
88
|
+
# so the base hook is always nil. Without this, "ECMA-101" and
|
|
89
|
+
# "ECMA TR/101" produce the same slug — and `to_slug` is an output
|
|
90
|
+
# filename, so one document would overwrite the other.
|
|
91
|
+
def mr_type
|
|
92
|
+
type_prefix&.downcase
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# ECMA's `edition` is a plain :string ("3", "5.1"), not a
|
|
96
|
+
# Components::Edition, so the base hook's `edition&.number` raises
|
|
97
|
+
# NoMethodError on every edition-bearing identifier.
|
|
98
|
+
def mr_edition
|
|
99
|
+
mr_marker("ed", edition)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Volume is identity-bearing (ECMA-269 ed3 vol1..vol4 are four distinct
|
|
103
|
+
# documents), so it must reach the MR string as well as `to_s` and the
|
|
104
|
+
# URN. Fills the shared `mr_volume` slot in Renderers::MrString.
|
|
105
|
+
def mr_volume
|
|
106
|
+
mr_marker("vol", volume)
|
|
107
|
+
end
|
|
108
|
+
|
|
59
109
|
# Parse an ECMA identifier string into an identifier object.
|
|
60
110
|
# @param identifier [String] The ECMA identifier string to parse
|
|
61
111
|
# @return [Identifier] The appropriate identifier object
|
|
62
|
-
# @raise [
|
|
63
|
-
#
|
|
112
|
+
# @raise [Pubid::Errors::InvalidInputError]
|
|
113
|
+
# If the input exceeds MAX_INPUT_LENGTH
|
|
114
|
+
# @raise [Pubid::Errors::ParseError] If parsing fails
|
|
64
115
|
def self.parse(identifier)
|
|
116
|
+
unless identifier.is_a?(String)
|
|
117
|
+
raise Pubid::Errors::InvalidInputError,
|
|
118
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
119
|
+
end
|
|
120
|
+
|
|
65
121
|
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
66
|
-
raise
|
|
122
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
67
123
|
end
|
|
68
124
|
|
|
69
125
|
parsed = Parser.parse(identifier)
|
|
70
126
|
Builder.build(parsed)
|
|
71
|
-
|
|
72
|
-
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
# Renderers::MrString joins SEGMENTS with ".", so a dot inside one would
|
|
132
|
+
# break the documented segment structure — hence "ed5-1" for edition
|
|
133
|
+
# "5.1". Sanitising by CHARSET rather than by an enumerated escape list,
|
|
134
|
+
# so a value added later cannot leak an unsafe character (the BIPM
|
|
135
|
+
# `mr_slug` precedent).
|
|
136
|
+
#
|
|
137
|
+
# The MR may be lossy here because nothing parses an ECMA MR back
|
|
138
|
+
# (`Parsers::MrString::FLAVOR_MAP` has no ECMA entry). The URN, which
|
|
139
|
+
# UrnParser inverts, keeps the dot instead.
|
|
140
|
+
def mr_marker(label, value)
|
|
141
|
+
return nil if value.nil? || value.to_s.empty?
|
|
142
|
+
|
|
143
|
+
"#{label}#{value.to_s.downcase.gsub(/[^a-z0-9]+/, '-')}"
|
|
73
144
|
end
|
|
74
145
|
end
|
|
75
146
|
end
|
data/lib/pubid/ecma/parser.rb
CHANGED
|
@@ -6,16 +6,21 @@ module Pubid
|
|
|
6
6
|
module Ecma
|
|
7
7
|
# Parslet grammar for ECMA identifiers.
|
|
8
8
|
#
|
|
9
|
-
# Four printed forms
|
|
9
|
+
# Four printed forms:
|
|
10
10
|
# ECMA-411 standard
|
|
11
11
|
# ECMA-418-1 standard with part
|
|
12
12
|
# ECMA TR/101 technical report
|
|
13
13
|
# ECMA MEM/1970 memento
|
|
14
14
|
#
|
|
15
|
+
# Any of them may carry an edition and a volume, in that order:
|
|
16
|
+
# ECMA-269 ed3 third edition
|
|
17
|
+
# ECMA-402 ed5.1 decimal edition (real: ECMA-402)
|
|
18
|
+
# ECMA-269 ed3 vol2 second volume of the third edition
|
|
19
|
+
#
|
|
15
20
|
# Each branch captures its number under a distinct key so the builder can
|
|
16
21
|
# pick the identifier class without a separate type token. Numbers are kept
|
|
17
22
|
# as strings to preserve any leading zeros.
|
|
18
|
-
class Parser <
|
|
23
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
19
24
|
rule(:digits) { match["0-9"].repeat(1) }
|
|
20
25
|
|
|
21
26
|
rule(:prefix) { str("ECMA") }
|
|
@@ -24,12 +29,42 @@ module Pubid
|
|
|
24
29
|
|
|
25
30
|
rule(:mem) { str(" MEM/") >> digits.as(:mem_number) }
|
|
26
31
|
|
|
32
|
+
# Standards print with a hyphen ("ECMA-6"), but references are commonly
|
|
33
|
+
# written with a space ("ECMA 6"). Both parse; the renderer normalises to
|
|
34
|
+
# the hyphen, so the space form round-trips as "ECMA-6" by design and must
|
|
35
|
+
# never enter the byte-exact `pass` fixtures.
|
|
36
|
+
rule(:standard_separator) { str("-") | str(" ") }
|
|
37
|
+
|
|
27
38
|
rule(:standard) do
|
|
28
|
-
|
|
39
|
+
standard_separator >> digits.as(:number) >>
|
|
29
40
|
(str("-") >> digits.as(:part)).maybe
|
|
30
41
|
end
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
# Editions are not all integers: ECMA-402 ed5.1 is a real document. The
|
|
44
|
+
# value is stored verbatim so it renders and serializes unchanged.
|
|
45
|
+
rule(:edition_number) { digits >> (str(".") >> digits).repeat(0) }
|
|
46
|
+
|
|
47
|
+
rule(:edition) { str(" ed") >> edition_number.as(:edition) }
|
|
48
|
+
|
|
49
|
+
rule(:volume) { str(" vol") >> digits.as(:volume) }
|
|
50
|
+
|
|
51
|
+
# The suffixes attach AFTER the type alternation, so a technical report
|
|
52
|
+
# and a memento carry them exactly as a standard does.
|
|
53
|
+
#
|
|
54
|
+
# Two PEG facts this arrangement depends on:
|
|
55
|
+
#
|
|
56
|
+
# 1. `standard` cannot shadow " TR/" or " MEM/", because after the space
|
|
57
|
+
# it demands a digit and "T"/"M" are not digits. Keeping tr|mem first
|
|
58
|
+
# is belt-and-braces; the DISJOINT FIRST CHARACTER is the load-bearing
|
|
59
|
+
# invariant.
|
|
60
|
+
# 2. Appending a sequence moves the alternation out of tail position, so
|
|
61
|
+
# Parslet no longer threads consume_all into it and will not backtrack
|
|
62
|
+
# into an alternative that already succeeded. A future branch that
|
|
63
|
+
# could match a proper prefix of another branch's input would now fail
|
|
64
|
+
# the whole parse instead of being rescued by the next alternative.
|
|
65
|
+
rule(:identifier) do
|
|
66
|
+
prefix >> (tr | mem | standard) >> edition.maybe >> volume.maybe
|
|
67
|
+
end
|
|
33
68
|
|
|
34
69
|
rule(:root) { identifier }
|
|
35
70
|
|
data/lib/pubid/ecma/renderer.rb
CHANGED
|
@@ -5,28 +5,49 @@ module Pubid
|
|
|
5
5
|
# Human-readable renderer for ECMA identifiers.
|
|
6
6
|
#
|
|
7
7
|
# Produces strings like:
|
|
8
|
-
# "ECMA-411"
|
|
9
|
-
# "ECMA-418-1"
|
|
10
|
-
# "ECMA TR/101"
|
|
11
|
-
# "ECMA MEM/1970"
|
|
8
|
+
# "ECMA-411" standard
|
|
9
|
+
# "ECMA-418-1" standard with part
|
|
10
|
+
# "ECMA TR/101" technical report
|
|
11
|
+
# "ECMA MEM/1970" memento
|
|
12
|
+
# "ECMA-269 ed3 vol2" with the edition and volume suffixes
|
|
12
13
|
#
|
|
13
14
|
# With `with_publisher: false` the leading ECMA token is dropped, yielding
|
|
14
|
-
# "-411" / "TR/101" / "MEM/1970".
|
|
15
|
-
# separate metadata carried only in `to_hash`.
|
|
15
|
+
# "-411" / "TR/101" / "MEM/1970".
|
|
16
16
|
class Renderer < ::Pubid::Renderers::Base
|
|
17
17
|
PUBLISHER = "ECMA"
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
# `with_edition` and `with_volume` default to TRUE — the inverse of
|
|
20
|
+
# pubid's usual opt-in, deliberately. `Relaton::Index::Type#add_or_update`
|
|
21
|
+
# keys on a BARE `id.to_s` and cannot pass options, so the default
|
|
22
|
+
# rendering is what the index keys on, and it has to be unique per row.
|
|
23
|
+
# With the edition omitted, all 22 editions of ECMA-74 collapsed onto one
|
|
24
|
+
# key and 383 of the 804 published rows were dropped silently.
|
|
25
|
+
#
|
|
26
|
+
# Per-flavor divergence in these defaults is the established pattern:
|
|
27
|
+
# Pubid::Tgpp defaults `with_publisher` to false and Pubid::W3c to true,
|
|
28
|
+
# each for its own consumer's reason.
|
|
29
|
+
def render(context: nil, with_edition: true, with_volume: true, **_opts)
|
|
20
30
|
id = @id
|
|
21
31
|
# Standard joins the publisher directly ("ECMA-411"); TR/MEM separate it
|
|
22
32
|
# with a space ("ECMA TR/101"). type_prefix is nil only for standards.
|
|
23
33
|
sep = id.type_prefix.nil? ? "" : " "
|
|
24
34
|
core = id.type_prefix.nil? ? standard_core(id) : typed_core(id)
|
|
25
|
-
with_publisher?(id) ? "#{PUBLISHER}#{sep}#{core}" : core
|
|
35
|
+
result = with_publisher?(id) ? "#{PUBLISHER}#{sep}#{core}" : core
|
|
36
|
+
result + suffixes(id, with_edition, with_volume)
|
|
26
37
|
end
|
|
27
38
|
|
|
28
39
|
private
|
|
29
40
|
|
|
41
|
+
# " ed<edition>" then " vol<volume>", each only when the identifier
|
|
42
|
+
# carries it and the caller has not opted out. The order is canonical:
|
|
43
|
+
# the grammar accepts the volume only after the edition.
|
|
44
|
+
def suffixes(id, with_edition, with_volume)
|
|
45
|
+
out = +""
|
|
46
|
+
out << " ed#{id.edition}" if with_edition && id.edition
|
|
47
|
+
out << " vol#{id.volume}" if with_volume && id.volume
|
|
48
|
+
out
|
|
49
|
+
end
|
|
50
|
+
|
|
30
51
|
# Standard: "-<number>[-<part>]".
|
|
31
52
|
def standard_core(id)
|
|
32
53
|
core = "-#{id.number}"
|
|
@@ -2,23 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
module Pubid
|
|
4
4
|
module Ecma
|
|
5
|
-
# Emits
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# ECMA
|
|
10
|
-
# ECMA
|
|
5
|
+
# Emits
|
|
6
|
+
# `urn:ecma:<tag>:<number>[:part-<part>][:ed-<edition>][:vol-<volume>]`,
|
|
7
|
+
# where the tag is bare for standards, "tr" for technical reports and "mem"
|
|
8
|
+
# for mementos:
|
|
9
|
+
# ECMA-411 -> urn:ecma:411
|
|
10
|
+
# ECMA-418-1 -> urn:ecma:418:part-1
|
|
11
|
+
# ECMA TR/101 -> urn:ecma:tr:101
|
|
12
|
+
# ECMA MEM/1970 -> urn:ecma:mem:1970
|
|
13
|
+
# ECMA-269 ed3 vol2 -> urn:ecma:269:ed-3:vol-2
|
|
14
|
+
# ECMA-402 ed5.1 -> urn:ecma:402:ed-5.1
|
|
15
|
+
#
|
|
16
|
+
# The edition and volume segments are additive: they only ever split a
|
|
17
|
+
# collision, so a URN minted before they existed still reads back (UrnParser
|
|
18
|
+
# probes for the labelled prefix). They are needed because edition and
|
|
19
|
+
# volume are identity-bearing — without them 804 published documents share
|
|
20
|
+
# 421 URNs.
|
|
21
|
+
#
|
|
22
|
+
# The dot of a decimal edition is KEPT: "." is `unreserved` in RFC 8141, and
|
|
23
|
+
# the URN has an inverse, so it must be lossless. (The MR string, which has
|
|
24
|
+
# no inverse, collapses it to "ed5-1" instead.)
|
|
11
25
|
class UrnGenerator < Pubid::UrnGenerator::Base
|
|
12
26
|
def generate
|
|
13
|
-
parts = ["urn", "ecma"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
parts
|
|
27
|
+
parts = ["urn", "ecma", identifier.type_prefix&.downcase,
|
|
28
|
+
identifier.number.to_s]
|
|
29
|
+
parts.concat(labelled_segments)
|
|
30
|
+
parts.compact.join(":")
|
|
31
|
+
end
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
parts << "part-#{identifier.part}" if identifier.part
|
|
33
|
+
private
|
|
20
34
|
|
|
21
|
-
|
|
35
|
+
# Every optional field carries its own label, so a URN written before a
|
|
36
|
+
# given label existed still reads back (UrnParser probes for the prefix).
|
|
37
|
+
def labelled_segments
|
|
38
|
+
{
|
|
39
|
+
"part" => identifier.part,
|
|
40
|
+
"ed" => identifier.edition,
|
|
41
|
+
"vol" => identifier.volume,
|
|
42
|
+
}.filter_map { |label, value| "#{label}-#{value}" if value }
|
|
22
43
|
end
|
|
23
44
|
end
|
|
24
45
|
end
|
|
@@ -5,30 +5,46 @@ module Pubid
|
|
|
5
5
|
# Parses ECMA URNs back into identifiers, inverting {UrnGenerator}.
|
|
6
6
|
#
|
|
7
7
|
# Examples:
|
|
8
|
-
# urn:ecma:411
|
|
9
|
-
# urn:ecma:418:part-1
|
|
10
|
-
# urn:ecma:tr:101
|
|
11
|
-
# urn:ecma:mem:1970
|
|
8
|
+
# urn:ecma:411 -> ECMA-411
|
|
9
|
+
# urn:ecma:418:part-1 -> ECMA-418-1
|
|
10
|
+
# urn:ecma:tr:101 -> ECMA TR/101
|
|
11
|
+
# urn:ecma:mem:1970 -> ECMA MEM/1970
|
|
12
|
+
# urn:ecma:269:ed-3:vol-2 -> ECMA-269 ed3 vol2
|
|
13
|
+
#
|
|
14
|
+
# Every trailing segment is consumed only if it carries its own label, so a
|
|
15
|
+
# URN written before the edition and volume segments existed still reads
|
|
16
|
+
# back with both nil.
|
|
12
17
|
class UrnParser < Pubid::UrnParser::Base
|
|
13
18
|
def parse_urn(urn)
|
|
14
19
|
parts = split_parts(strip_namespace(urn))
|
|
15
20
|
tag = %w[tr mem].include?(parts.first) ? parts.shift : nil
|
|
16
21
|
number = parts.shift
|
|
17
|
-
part =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
flavor_parse(reconstruct(tag, number, part))
|
|
22
|
+
part = shift_labelled(parts, "part-")
|
|
23
|
+
edition = shift_labelled(parts, "ed-")
|
|
24
|
+
volume = shift_labelled(parts, "vol-")
|
|
25
|
+
flavor_parse(reconstruct(tag, number, part, edition, volume))
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
private
|
|
24
29
|
|
|
30
|
+
# Consume the next segment only if it carries `label`. `delete_prefix`,
|
|
31
|
+
# not `sub`, so a label-shaped substring later in the value is untouched.
|
|
32
|
+
def shift_labelled(parts, label)
|
|
33
|
+
return nil unless parts.first&.start_with?(label)
|
|
34
|
+
|
|
35
|
+
parts.shift.delete_prefix(label)
|
|
36
|
+
end
|
|
37
|
+
|
|
25
38
|
# Rebuild the printed identifier string from the URN fields.
|
|
26
|
-
def reconstruct(tag, number, part)
|
|
27
|
-
case tag
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
def reconstruct(tag, number, part, edition, volume)
|
|
40
|
+
base = case tag
|
|
41
|
+
when "tr" then "ECMA TR/#{number}"
|
|
42
|
+
when "mem" then "ECMA MEM/#{number}"
|
|
43
|
+
else part ? "ECMA-#{number}-#{part}" : "ECMA-#{number}"
|
|
44
|
+
end
|
|
45
|
+
base += " ed#{edition}" if edition
|
|
46
|
+
base += " vol#{volume}" if volume
|
|
47
|
+
base
|
|
32
48
|
end
|
|
33
49
|
end
|
|
34
50
|
end
|
data/lib/pubid/ecma.rb
CHANGED
data/lib/pubid/errors.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pubid"
|
|
4
|
+
require "parslet"
|
|
5
|
+
|
|
6
|
+
module Pubid
|
|
7
|
+
# Every failure pubid raises.
|
|
8
|
+
#
|
|
9
|
+
# The three classes below have three different superclasses, chosen so that
|
|
10
|
+
# code written against the old contract keeps working: relaton-cli rescues
|
|
11
|
+
# `Parslet::ParseFailed`, and the input guards have always raised
|
|
12
|
+
# `ArgumentError`. What unifies them is the marker module
|
|
13
|
+
# {Pubid::Errors::Error}, which every one of them includes, so a caller that
|
|
14
|
+
# wants "pubid could not do this" writes one rescue:
|
|
15
|
+
#
|
|
16
|
+
# begin
|
|
17
|
+
# Pubid::Iso.parse(reference)
|
|
18
|
+
# rescue Pubid::Errors::Error => e
|
|
19
|
+
# warn e.message
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# A URN failure deliberately does not inherit `Parslet::ParseFailed`: no
|
|
23
|
+
# grammar runs, so there is no parse failure to report.
|
|
24
|
+
module Errors
|
|
25
|
+
# Marker module included by every pubid error. Rescue this to catch all
|
|
26
|
+
# of them, whatever their superclass.
|
|
27
|
+
module Error; end
|
|
28
|
+
|
|
29
|
+
# A printed identifier could not be turned into an identifier object.
|
|
30
|
+
#
|
|
31
|
+
# Raised for a grammar rejection, and also for the few flavors that reject
|
|
32
|
+
# an input before the grammar runs (a CSA comment line, a bad ISBN check
|
|
33
|
+
# digit). Those synthetic failures carry no parslet cause, so
|
|
34
|
+
# {#parse_failure_cause} is nillable — check it before calling
|
|
35
|
+
# `ascii_tree` on it.
|
|
36
|
+
#
|
|
37
|
+
# v1's `Pubid::Core::Errors::ParseError` flattened the cause into the
|
|
38
|
+
# message and threw the object away. This one keeps it.
|
|
39
|
+
class ParseError < ::Parslet::ParseFailed
|
|
40
|
+
include Error
|
|
41
|
+
|
|
42
|
+
# The string that could not be parsed, when it is known.
|
|
43
|
+
# @return [String, nil]
|
|
44
|
+
attr_reader :input
|
|
45
|
+
|
|
46
|
+
# The flavor whose grammar rejected the input, lowercased ("iso").
|
|
47
|
+
#
|
|
48
|
+
# This is the flavor that actually ran, which is not always the one the
|
|
49
|
+
# caller named: `Pubid::Iso.parse("ITU-T G.711")` routes through the
|
|
50
|
+
# MR-string parser into ITU, and reports "itu".
|
|
51
|
+
# @return [String, nil]
|
|
52
|
+
attr_reader :flavor
|
|
53
|
+
|
|
54
|
+
# @param message [String]
|
|
55
|
+
# @param parse_failure_cause [Parslet::Cause, nil] parslet's structured
|
|
56
|
+
# cause, nil for a failure raised without running a grammar
|
|
57
|
+
# @param input [String, nil]
|
|
58
|
+
# @param flavor [String, nil]
|
|
59
|
+
def initialize(message, parse_failure_cause = nil, input: nil,
|
|
60
|
+
flavor: nil)
|
|
61
|
+
super(message, parse_failure_cause)
|
|
62
|
+
@input = input
|
|
63
|
+
@flavor = flavor
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# A URN could not be turned into an identifier object.
|
|
68
|
+
class UrnParseError < ::StandardError
|
|
69
|
+
include Error
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The input was not a String, or was longer than {Pubid::MAX_INPUT_LENGTH}.
|
|
73
|
+
#
|
|
74
|
+
# Inherits `ArgumentError` because that is what the guards have always
|
|
75
|
+
# raised, and because the input is wrong in kind rather than unparseable.
|
|
76
|
+
class InvalidInputError < ::ArgumentError
|
|
77
|
+
include Error
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/pubid/etsi/builder.rb
CHANGED
|
@@ -52,9 +52,14 @@ module Pubid
|
|
|
52
52
|
version = build_version(data)
|
|
53
53
|
date = build_date(data)
|
|
54
54
|
|
|
55
|
+
# The code fields are stored as flat index columns on the leaf (see
|
|
56
|
+
# EtsiStandard) — `number` is what relaton-index keys on — so the Code
|
|
57
|
+
# object built above is unpacked rather than assigned.
|
|
55
58
|
Identifiers::EtsiStandard.new(
|
|
56
59
|
type: data[:type].to_s,
|
|
57
|
-
|
|
60
|
+
number: code.number,
|
|
61
|
+
minor: code.minor,
|
|
62
|
+
parts: code.parts || [],
|
|
58
63
|
version: version,
|
|
59
64
|
date: date,
|
|
60
65
|
)
|
|
@@ -9,12 +9,20 @@ module Pubid
|
|
|
9
9
|
# relaton-cli's `rescue Parslet::ParseFailed` fetch handler catches it
|
|
10
10
|
# instead of a bare RuntimeError.
|
|
11
11
|
def self.parse(identifier)
|
|
12
|
+
unless identifier.is_a?(String)
|
|
13
|
+
raise Pubid::Errors::InvalidInputError,
|
|
14
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
18
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
parsed = Parser.parse(identifier)
|
|
13
22
|
Builder.build(parsed)
|
|
14
23
|
end
|
|
15
24
|
|
|
16
25
|
attribute :type, :string
|
|
17
|
-
attribute :code, Pubid::Etsi::Components::Code
|
|
18
26
|
attribute :version, Pubid::Etsi::Components::Version
|
|
19
27
|
attribute :date, Pubid::Components::Date
|
|
20
28
|
# Stored as a plain string (always "ETSI") so it round-trips through
|
|
@@ -32,27 +40,33 @@ module Pubid
|
|
|
32
40
|
date == other.date
|
|
33
41
|
end
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
43
|
+
# The document code is composed from the split index columns declared on
|
|
44
|
+
# EtsiStandard (`number`/`minor`/`parts`). Returning nil here keeps `==`
|
|
45
|
+
# and the URN generator total for the abstract base and for a supplement
|
|
46
|
+
# whose own base is missing; EtsiStandard composes the real value and
|
|
47
|
+
# SupplementIdentifier delegates to its base.
|
|
48
|
+
def code
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# `parts` is a plain collection attribute on the leaf, so the base
|
|
53
|
+
# #exclude reaches it directly and nils it. It must come back as an EMPTY
|
|
54
|
+
# ARRAY instead: a part-less reference parses with `parts` defaulting to
|
|
55
|
+
# [], so a nil here would make `==` — and therefore #matches? — fail
|
|
56
|
+
# against exactly the reference this exclusion exists to match. Same
|
|
57
|
+
# "reset the whole cluster" rule recorded for CSA's year and IEEE's
|
|
58
|
+
# year/month/day in CLAUDE.md.
|
|
59
|
+
#
|
|
60
|
+
# This also covers supplements: the base #exclude recurses into the
|
|
61
|
+
# nested `base` identifier through exclude_from_nested, which re-enters
|
|
62
|
+
# this method on the inner EtsiStandard.
|
|
63
|
+
def exclude(*args)
|
|
64
|
+
result = super
|
|
46
65
|
part_keys = args & %i[part parts]
|
|
47
|
-
if
|
|
48
|
-
|
|
49
|
-
number: value.number,
|
|
50
|
-
minor: value.minor,
|
|
51
|
-
parts: [],
|
|
52
|
-
)
|
|
66
|
+
if !part_keys.empty? && result.respond_to?(:parts=)
|
|
67
|
+
result.parts = []
|
|
53
68
|
end
|
|
54
|
-
|
|
55
|
-
super
|
|
69
|
+
result
|
|
56
70
|
end
|
|
57
71
|
end
|
|
58
72
|
|