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
data/lib/pubid/ieee_debug.rb
CHANGED
data/lib/pubid/ietf/builder.rb
CHANGED
|
@@ -28,28 +28,44 @@ module Pubid
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
30
|
def build_rfc(data)
|
|
31
|
-
Identifiers::Rfc.new(number: data[:number]
|
|
31
|
+
Identifiers::Rfc.new(number: unpad(data[:number]))
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
# The series token only selects the class: it is derived back from the
|
|
35
|
+
# class (Identifiers::Std::SERIES) rather than stored, since `_type`
|
|
36
|
+
# already carries it.
|
|
34
37
|
def build_subseries(data)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
klass = Identifiers.const_get(
|
|
39
|
+
SUBSERIES_CLASSES.fetch(data[:series].to_s),
|
|
40
|
+
)
|
|
41
|
+
klass.new(number: unpad(data[:number]))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Strip the zero-padding the RFC editor's rfc-index.xml writes ("STD0066",
|
|
45
|
+
# "RFC0001") so the canonical printed form is the unpadded one. The
|
|
46
|
+
# look-ahead keeps the last digit, so an all-zero number stays "0" rather
|
|
47
|
+
# than becoming empty.
|
|
48
|
+
def unpad(number)
|
|
49
|
+
number.to_s.sub(/\A0+(?=\d)/, "")
|
|
38
50
|
end
|
|
39
51
|
|
|
40
52
|
def build_draft(data)
|
|
41
53
|
full = "draft-#{data[:draft_rest]}"
|
|
42
|
-
|
|
43
|
-
Identifiers::InternetDraft.new(
|
|
54
|
+
slug, version = split_draft_version(full)
|
|
55
|
+
Identifiers::InternetDraft.new(number: slug, version: version)
|
|
44
56
|
end
|
|
45
57
|
|
|
46
58
|
# An Internet-Draft version is a trailing "-NN" of *exactly* two digits at
|
|
47
59
|
# the very end of the slug. A three-digit topic tail (e.g. "...-256") is
|
|
48
60
|
# NOT a version: there the char before the last two digits is itself a
|
|
49
|
-
# digit, not "-", so the guard below leaves it in the
|
|
61
|
+
# digit, not "-", so the guard below leaves it in the slug. This also
|
|
50
62
|
# means a (non-existent in practice) revision >= 100 would be read as part
|
|
51
|
-
# of the
|
|
63
|
+
# of the slug — IETF drafts are always two-digit-versioned, so that case
|
|
52
64
|
# never arises. Either way the printed string round-trips exactly.
|
|
65
|
+
#
|
|
66
|
+
# Dotted slugs need no special handling here: only the final three
|
|
67
|
+
# characters are inspected, so "draft-ietf-pilc-2.5g3g-12" splits into
|
|
68
|
+
# ("draft-ietf-pilc-2.5g3g", "12").
|
|
53
69
|
def split_draft_version(full)
|
|
54
70
|
if full.length > 3 && full[-3] == "-" && full[-2..].match?(/\A\d\d\z/)
|
|
55
71
|
[full[0...-3], full[-2..]]
|
|
@@ -7,22 +7,13 @@ module Pubid
|
|
|
7
7
|
# Pubid::Ietf::Identifiers descend from this class, so a parsed IETF id is
|
|
8
8
|
# an instance of Pubid::Ietf::Identifier.
|
|
9
9
|
#
|
|
10
|
-
# All families are flat, supplement-free, and use plain string attributes
|
|
10
|
+
# All families are flat, supplement-free, and use plain string attributes.
|
|
11
|
+
# Those attributes are declared on the LEAVES by Identifiers::Serialization
|
|
12
|
+
# (see the determinism note there — never re-add `attribute :number` here):
|
|
11
13
|
# * Rfc -> number ("2119")
|
|
12
|
-
# * Bcp/Std/Fyi ->
|
|
13
|
-
# * InternetDraft ->
|
|
14
|
+
# * Bcp/Std/Fyi -> number ("3") + a derived `series` reader
|
|
15
|
+
# * InternetDraft -> number ("draft-giuliano-treedn") + optional version
|
|
14
16
|
class Identifier < ::Pubid::Identifier
|
|
15
|
-
# Numeric part of an RFC or sub-series id, kept as a string (no zero-pad
|
|
16
|
-
# in the printed form, so "2119" not "02119").
|
|
17
|
-
attribute :number, :string
|
|
18
|
-
# Sub-series token for BCP/STD/FYI ("BCP"/"STD"/"FYI"); nil otherwise.
|
|
19
|
-
attribute :series, :string
|
|
20
|
-
# Full Internet-Draft slug including the leading "draft-"; nil otherwise.
|
|
21
|
-
attribute :name, :string
|
|
22
|
-
# Internet-Draft version, a two-digit string preserving zero-pad ("02");
|
|
23
|
-
# nil for the unversioned "latest" sibling.
|
|
24
|
-
attribute :version, :string
|
|
25
|
-
|
|
26
17
|
# Polymorphic type map for lutaml::Model key_value (de)serialization: maps
|
|
27
18
|
# each subclass's polymorphic_name to its class name so a stored hash
|
|
28
19
|
# rebuilds the correct identifier type via the shared from_hash dispatch.
|
|
@@ -35,16 +26,10 @@ module Pubid
|
|
|
35
26
|
"Pubid::Ietf::Identifiers::InternetDraft",
|
|
36
27
|
}.freeze
|
|
37
28
|
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
map "_type", to: :_type, polymorphic_map: IETF_TYPE_MAP
|
|
43
|
-
map "number", to: :number
|
|
44
|
-
map "series", to: :series
|
|
45
|
-
map "name", to: :name
|
|
46
|
-
map "version", to: :version
|
|
47
|
-
end
|
|
29
|
+
# NOTE: no `key_value` block here on purpose. The mapping lives on the
|
|
30
|
+
# leaves (Identifiers::Serialization); a block on this shared parent would
|
|
31
|
+
# be inherited-and-merged by every leaf and re-emit keys the leaf did not
|
|
32
|
+
# declare.
|
|
48
33
|
|
|
49
34
|
# Publisher is always "IETF". A plain constant (not a `publisher` method)
|
|
50
35
|
# so it doesn't shadow the inherited lutaml `publisher` attribute, which
|
|
@@ -62,14 +47,26 @@ module Pubid
|
|
|
62
47
|
# Parse an IETF identifier string into the appropriate identifier object.
|
|
63
48
|
# @param identifier [String] the IETF identifier string to parse
|
|
64
49
|
# @return [Identifier] the concrete identifier object
|
|
65
|
-
# @raise [
|
|
50
|
+
# @raise [Pubid::Errors::InvalidInputError] if the input exceeds
|
|
51
|
+
# Pubid::MAX_INPUT_LENGTH
|
|
52
|
+
# @raise [Pubid::Errors::ParseError] if parsing fails
|
|
66
53
|
def self.parse(identifier)
|
|
54
|
+
# Inline length guard (CodeQL rb/polynomial-redos barrier) — must be
|
|
55
|
+
# the first statement. This class-level funnel is what relaton reaches
|
|
56
|
+
# directly through `pubid_class: ::Pubid::Ietf::Identifier`, so it
|
|
57
|
+
# cannot rely on the guard in Pubid::Ietf.parse.
|
|
58
|
+
unless identifier.is_a?(String)
|
|
59
|
+
raise Pubid::Errors::InvalidInputError,
|
|
60
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
64
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
65
|
+
end
|
|
66
|
+
|
|
67
67
|
parsed = Parser.parse(identifier)
|
|
68
68
|
Builder.build(parsed)
|
|
69
|
-
rescue Parslet::ParseFailed => e
|
|
70
|
-
raise "Failed to parse IETF identifier '#{identifier}': #{e.message}"
|
|
71
69
|
end
|
|
72
70
|
end
|
|
73
|
-
|
|
74
71
|
end
|
|
75
72
|
end
|
|
@@ -5,6 +5,17 @@ module Pubid
|
|
|
5
5
|
module Identifiers
|
|
6
6
|
# A BCP (Best Current Practice) sub-series id, e.g. "BCP 3".
|
|
7
7
|
class Bcp < Identifier
|
|
8
|
+
include Serialization
|
|
9
|
+
|
|
10
|
+
# The series token is derived from the class, not stored:
|
|
11
|
+
# `_type` already encodes it, so serializing `series` would
|
|
12
|
+
# duplicate the type in every index row.
|
|
13
|
+
SERIES = "BCP"
|
|
14
|
+
|
|
15
|
+
def series
|
|
16
|
+
SERIES
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
TYPED_STAGES = [
|
|
9
20
|
Pubid::Components::TypedStage.new(
|
|
10
21
|
code: :bcp,
|
|
@@ -5,6 +5,17 @@ module Pubid
|
|
|
5
5
|
module Identifiers
|
|
6
6
|
# An FYI (For Your Information) sub-series id, e.g. "FYI 1".
|
|
7
7
|
class Fyi < Identifier
|
|
8
|
+
include Serialization
|
|
9
|
+
|
|
10
|
+
# The series token is derived from the class, not stored:
|
|
11
|
+
# `_type` already encodes it, so serializing `series` would
|
|
12
|
+
# duplicate the type in every index row.
|
|
13
|
+
SERIES = "FYI"
|
|
14
|
+
|
|
15
|
+
def series
|
|
16
|
+
SERIES
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
TYPED_STAGES = [
|
|
9
20
|
Pubid::Components::TypedStage.new(
|
|
10
21
|
code: :fyi,
|
|
@@ -5,9 +5,25 @@ module Pubid
|
|
|
5
5
|
module Identifiers
|
|
6
6
|
# An Internet-Draft, e.g. "draft-giuliano-treedn-02" (versioned) or
|
|
7
7
|
# "draft-giuliano-treedn" (the unversioned "latest" sibling). The full
|
|
8
|
-
# slug (including the leading "draft-") is stored in `
|
|
9
|
-
#
|
|
8
|
+
# slug (including the leading "draft-") is stored in `number` — it is the
|
|
9
|
+
# relaton-index narrowing key, shared by a draft's unversioned aggregator
|
|
10
|
+
# row and all of its versions; the optional trailing two-digit version is
|
|
11
|
+
# in `version`.
|
|
10
12
|
class InternetDraft < Identifier
|
|
13
|
+
include Serialization
|
|
14
|
+
|
|
15
|
+
# Two-digit version string, zero-pad preserved ("02"); nil for the
|
|
16
|
+
# unversioned "latest" sibling, in which case the canonical to_hash
|
|
17
|
+
# drops the key entirely.
|
|
18
|
+
attribute :version, :string
|
|
19
|
+
|
|
20
|
+
# Merged with the block Serialization installs (lutaml combines a
|
|
21
|
+
# mixin-installed key_value with a second in-class one), so the
|
|
22
|
+
# serialized shape is {_type, number} plus `version` when set.
|
|
23
|
+
key_value do
|
|
24
|
+
map "version", to: :version
|
|
25
|
+
end
|
|
26
|
+
|
|
11
27
|
TYPED_STAGES = [
|
|
12
28
|
Pubid::Components::TypedStage.new(
|
|
13
29
|
code: :internet_draft,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ietf
|
|
5
|
+
module Identifiers
|
|
6
|
+
# Installs the flat, index-friendly attribute set and the shared
|
|
7
|
+
# `key_value` block on the five concrete IETF leaves (Rfc, Bcp, Std, Fyi,
|
|
8
|
+
# InternetDraft).
|
|
9
|
+
#
|
|
10
|
+
# Why the leaves and not the shared Pubid::Ietf::Identifier base:
|
|
11
|
+
# `number` redefines the parent ::Pubid::Identifier's
|
|
12
|
+
# `attribute :number, Components::Code` as a plain :string. Declaring that
|
|
13
|
+
# on a class the concrete types INHERIT from resolves against the parent
|
|
14
|
+
# definition nondeterministically under multi-flavor load — it passes an
|
|
15
|
+
# IETF-only run and can flip `root.number` to "" under the full suite (the
|
|
16
|
+
# IEEE lesson; see lib/pubid/ieee/identifiers/code_number.rb and
|
|
17
|
+
# CLAUDE.md). Declaring `number` directly on each leaf removes the
|
|
18
|
+
# ambiguity at the point of use.
|
|
19
|
+
#
|
|
20
|
+
# This matters because relaton-index bsearches on `id.root.number.to_s`,
|
|
21
|
+
# and every IETF identifier is its own root (the flavor has no wrapper or
|
|
22
|
+
# supplement types), so an empty key silently defeats the search for every
|
|
23
|
+
# row. spec/pubid/ietf/root_number_spec.rb guards it and must run under
|
|
24
|
+
# the FULL suite to be meaningful.
|
|
25
|
+
#
|
|
26
|
+
# `series` is deliberately NOT an attribute here: `_type` already encodes
|
|
27
|
+
# it, so storing it would duplicate the type in every sub-series row. The
|
|
28
|
+
# three sub-series leaves expose it as a derived reader instead.
|
|
29
|
+
module Serialization
|
|
30
|
+
def self.included(base)
|
|
31
|
+
# Document number of an RFC or sub-series id ("2119", "66"), kept as
|
|
32
|
+
# a string so the printed form carries no zero-pad; for an
|
|
33
|
+
# Internet-Draft, the version-less slug INCLUDING the leading
|
|
34
|
+
# "draft-" ("draft-ietf-quic-transport"). The slug is the right index
|
|
35
|
+
# key for the same reason the number is for an RFC: a draft's
|
|
36
|
+
# unversioned aggregator row and every one of its versions share it,
|
|
37
|
+
# so a document and its variants cluster into one bucket.
|
|
38
|
+
base.attribute :number, :string
|
|
39
|
+
|
|
40
|
+
# Only these keys serialize; the inherited Pubid::Identifier
|
|
41
|
+
# attributes are intentionally dropped. InternetDraft merges its own
|
|
42
|
+
# `version` mapping on top of this block.
|
|
43
|
+
base.key_value do
|
|
44
|
+
map "_type", to: :_type, polymorphic_map: Identifier::IETF_TYPE_MAP
|
|
45
|
+
map "number", to: :number
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -5,6 +5,17 @@ module Pubid
|
|
|
5
5
|
module Identifiers
|
|
6
6
|
# An STD (Internet Standard) sub-series id, e.g. "STD 66".
|
|
7
7
|
class Std < Identifier
|
|
8
|
+
include Serialization
|
|
9
|
+
|
|
10
|
+
# The series token is derived from the class, not stored:
|
|
11
|
+
# `_type` already encodes it, so serializing `series` would
|
|
12
|
+
# duplicate the type in every index row.
|
|
13
|
+
SERIES = "STD"
|
|
14
|
+
|
|
15
|
+
def series
|
|
16
|
+
SERIES
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
TYPED_STAGES = [
|
|
9
20
|
Pubid::Components::TypedStage.new(
|
|
10
21
|
code: :std,
|
data/lib/pubid/ietf/parser.rb
CHANGED
|
@@ -12,24 +12,42 @@ module Pubid
|
|
|
12
12
|
# * draft -> { draft_rest: } (everything after "draft-"; the version
|
|
13
13
|
# split is done in the Builder to keep the digit-tail
|
|
14
14
|
# heuristic in one place)
|
|
15
|
-
class Parser <
|
|
15
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
16
16
|
rule(:space) { str(" ") }
|
|
17
17
|
rule(:digit) { match["0-9"] }
|
|
18
18
|
rule(:digits) { digit.repeat(1) }
|
|
19
19
|
|
|
20
|
-
# "RFC 2119"
|
|
21
|
-
|
|
20
|
+
# "RFC 2119", and the zero-padded, space-less spelling the RFC editor's
|
|
21
|
+
# rfc-index.xml emits ("RFC0001"). See #subseries for why.
|
|
22
|
+
rule(:rfc) { str("RFC") >> space.maybe >> digits.as(:number) }
|
|
22
23
|
|
|
23
|
-
# "BCP 3" / "STD 66" / "FYI 1"
|
|
24
|
+
# "BCP 3" / "STD 66" / "FYI 1".
|
|
25
|
+
#
|
|
26
|
+
# The space is optional and leading zeros are allowed because
|
|
27
|
+
# rfc-index.xml writes the sub-series membership of an RFC in the padded,
|
|
28
|
+
# space-less form -- <is-also><doc-id>STD0066</doc-id></is-also> -- and
|
|
29
|
+
# relaton builds the STD/BCP/FYI <-> RFC cross-references from exactly
|
|
30
|
+
# those elements without normalizing them itself. The Builder strips the
|
|
31
|
+
# pad, so the printed form stays the canonical "STD 66".
|
|
24
32
|
rule(:subseries) do
|
|
25
33
|
(str("BCP") | str("STD") | str("FYI")).as(:series) >>
|
|
26
|
-
space >> digits.as(:number)
|
|
34
|
+
space.maybe >> digits.as(:number)
|
|
27
35
|
end
|
|
28
36
|
|
|
29
|
-
# Internet-Draft slug characters
|
|
30
|
-
# separators
|
|
31
|
-
#
|
|
32
|
-
|
|
37
|
+
# Internet-Draft slug characters: lowercase, digits and the "-", "+", "_"
|
|
38
|
+
# separators, plus two historical shapes the published corpus carries --
|
|
39
|
+
# a dot inside a topic token ("draft-ietf-pilc-2.5g3g-12") and uppercase
|
|
40
|
+
# letters in protocol/organisation names ("draft-chapin-clnp-ISO8473-00").
|
|
41
|
+
# 50 of the 166,740 relaton-data-ids identifiers need those two
|
|
42
|
+
# characters; nothing else outside [a-z0-9-] occurs in the corpus.
|
|
43
|
+
#
|
|
44
|
+
# Widening the tail is unambiguous: the top-level alternation is keyed on
|
|
45
|
+
# the leading token (RFC / BCP|STD|FYI / draft-), so a wider draft tail
|
|
46
|
+
# cannot make another branch match.
|
|
47
|
+
#
|
|
48
|
+
# The whole remainder after "draft-" is captured; the Builder anchors the
|
|
49
|
+
# optional trailing "-NN" version.
|
|
50
|
+
rule(:draft_rest) { match['a-zA-Z0-9+_.\-'].repeat(1).as(:draft_rest) }
|
|
33
51
|
rule(:draft) { str("draft-") >> draft_rest }
|
|
34
52
|
|
|
35
53
|
rule(:identifier) { rfc | subseries | draft }
|
data/lib/pubid/ietf/renderer.rb
CHANGED
|
@@ -10,17 +10,55 @@ module Pubid
|
|
|
10
10
|
# "draft-giuliano-treedn-02" / "draft-giuliano-treedn"
|
|
11
11
|
class Renderer < ::Pubid::Renderers::Base
|
|
12
12
|
def render(context: nil, **_opts)
|
|
13
|
-
|
|
13
|
+
require_number!(@id)
|
|
14
|
+
render_identifier(@id)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
14
18
|
|
|
19
|
+
# For an Internet-Draft, `number` holds the version-less slug including
|
|
20
|
+
# the leading "draft-"; for the sub-series, `series` is derived from the
|
|
21
|
+
# class rather than stored. The sub-series arm names its three classes
|
|
22
|
+
# explicitly instead of being a catch-all `else`, because a bare
|
|
23
|
+
# Pubid::Ietf::Identifier has no `series` reader at all.
|
|
24
|
+
def render_identifier(id)
|
|
15
25
|
case id
|
|
16
|
-
when Identifiers::Rfc
|
|
17
|
-
|
|
18
|
-
when Identifiers::
|
|
19
|
-
id.version ? "#{id.name}-#{id.version}" : id.name
|
|
20
|
-
else # Bcp/Std/Fyi sub-series
|
|
26
|
+
when Identifiers::Rfc then "RFC #{id.number}"
|
|
27
|
+
when Identifiers::InternetDraft then render_draft(id)
|
|
28
|
+
when Identifiers::Bcp, Identifiers::Std, Identifiers::Fyi
|
|
21
29
|
"#{id.series} #{id.number}"
|
|
30
|
+
else unsupported!(id)
|
|
22
31
|
end
|
|
23
32
|
end
|
|
33
|
+
|
|
34
|
+
def render_draft(id)
|
|
35
|
+
id.version ? "#{id.number}-#{id.version}" : id.number
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Fail loudly rather than render a nil/partial string. `number` carries
|
|
39
|
+
# the whole document identity for every IETF type, so a nil one means the
|
|
40
|
+
# object was built from something that is not a current IETF hash — most
|
|
41
|
+
# likely a pre-`number` index row, which stored an Internet-Draft slug
|
|
42
|
+
# under `name` (a key nothing reads any more; lutaml ignores it
|
|
43
|
+
# silently). Such a row would otherwise deserialize into an identifier
|
|
44
|
+
# that renders "" or "-02" and keys the index under "", with no error
|
|
45
|
+
# anywhere — exactly the silent-wrong-lookup failure this flavor's
|
|
46
|
+
# round-trip specs exist to prevent. Regenerate the
|
|
47
|
+
# relaton-data-{rfcs,rfcsubseries,ids} indexes instead.
|
|
48
|
+
def require_number!(id)
|
|
49
|
+
return unless id.respond_to?(:number)
|
|
50
|
+
return unless id.number.nil? || id.number.empty?
|
|
51
|
+
|
|
52
|
+
raise ArgumentError,
|
|
53
|
+
"Cannot render #{id.class} with an empty number " \
|
|
54
|
+
"(a pre-`number` index row stored the draft slug under `name`; " \
|
|
55
|
+
"regenerate the index)"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def unsupported!(id)
|
|
59
|
+
raise ArgumentError,
|
|
60
|
+
"Cannot render #{id.class}: not a concrete IETF identifier"
|
|
61
|
+
end
|
|
24
62
|
end
|
|
25
63
|
end
|
|
26
64
|
end
|
|
@@ -7,17 +7,31 @@ module Pubid
|
|
|
7
7
|
# BCP/STD/FYI -> urn:ietf:bcp:3 / urn:ietf:std:66 / urn:ietf:fyi:1
|
|
8
8
|
# Internet-Draft -> urn:ietf:id:draft-giuliano-treedn[:02]
|
|
9
9
|
class UrnGenerator < Pubid::UrnGenerator::Base
|
|
10
|
+
# The sub-series arm names its three classes explicitly rather than being
|
|
11
|
+
# a catch-all `else`, because a bare Pubid::Ietf::Identifier has no
|
|
12
|
+
# `series` reader at all — `series` is derived from the concrete class.
|
|
10
13
|
def generate
|
|
11
14
|
case identifier
|
|
12
|
-
when Identifiers::Rfc
|
|
13
|
-
|
|
14
|
-
when Identifiers::
|
|
15
|
-
base = "urn:ietf:id:#{identifier.name}"
|
|
16
|
-
identifier.version ? "#{base}:#{identifier.version}" : base
|
|
17
|
-
else # Bcp/Std/Fyi sub-series
|
|
15
|
+
when Identifiers::Rfc then "urn:ietf:rfc:#{identifier.number}"
|
|
16
|
+
when Identifiers::InternetDraft then draft_urn
|
|
17
|
+
when Identifiers::Bcp, Identifiers::Std, Identifiers::Fyi
|
|
18
18
|
"urn:ietf:#{identifier.series.downcase}:#{identifier.number}"
|
|
19
|
+
else unsupported!
|
|
19
20
|
end
|
|
20
21
|
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def draft_urn
|
|
26
|
+
base = "urn:ietf:id:#{identifier.number}"
|
|
27
|
+
identifier.version ? "#{base}:#{identifier.version}" : base
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def unsupported!
|
|
31
|
+
raise ArgumentError,
|
|
32
|
+
"Cannot build a URN for #{identifier.class}: " \
|
|
33
|
+
"not a concrete IETF identifier"
|
|
34
|
+
end
|
|
21
35
|
end
|
|
22
36
|
end
|
|
23
37
|
end
|
|
@@ -21,11 +21,19 @@ module Pubid
|
|
|
21
21
|
when "rfc" then "RFC #{parts[0]}"
|
|
22
22
|
when "bcp", "std", "fyi" then "#{type.upcase} #{parts[0]}"
|
|
23
23
|
when "id" then draft_text(parts)
|
|
24
|
-
else
|
|
25
|
-
raise Errors::ParseError, "Invalid IETF URN type: #{type.inspect}"
|
|
24
|
+
else invalid_type!(type)
|
|
26
25
|
end
|
|
27
26
|
end
|
|
28
27
|
|
|
28
|
+
# `Errors` is defined under Pubid::UrnParser (the module), which is
|
|
29
|
+
# neither in this class's lexical scope nor an ancestor of Base, so the
|
|
30
|
+
# constant must be fully qualified — a bare `Errors::ParseError` raises
|
|
31
|
+
# NameError instead of the intended error.
|
|
32
|
+
def invalid_type!(type)
|
|
33
|
+
raise Pubid::UrnParser::Errors::ParseError,
|
|
34
|
+
"Invalid IETF URN type: #{type.inspect}"
|
|
35
|
+
end
|
|
36
|
+
|
|
29
37
|
def draft_text(parts)
|
|
30
38
|
name, version = parts
|
|
31
39
|
version ? "#{name}-#{version}" : name
|
data/lib/pubid/ietf.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "pubid"
|
|
3
4
|
module Pubid
|
|
4
5
|
# IETF flavor: one module covering the three IETF document families that share
|
|
5
6
|
# the IETF publisher and the `urn:ietf:` namespace —
|
|
@@ -24,8 +25,17 @@ module Pubid
|
|
|
24
25
|
# Parse an IETF identifier string
|
|
25
26
|
def self.parse(identifier)
|
|
26
27
|
# Inline length guard (CodeQL rb/polynomial-redos barrier) before the
|
|
27
|
-
# normalization/parse path
|
|
28
|
-
|
|
28
|
+
# normalization/parse path. The type check goes above it because it is
|
|
29
|
+
# what makes `.length` safe to call; the length check itself must still
|
|
30
|
+
# be the first thing the input string meets.
|
|
31
|
+
unless identifier.is_a?(String)
|
|
32
|
+
raise Pubid::Errors::InvalidInputError,
|
|
33
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
34
|
+
end
|
|
35
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
36
|
+
raise Pubid::Errors::InvalidInputError,
|
|
37
|
+
Pubid::INPUT_TOO_LONG_MESSAGE
|
|
38
|
+
end
|
|
29
39
|
|
|
30
40
|
Identifier.parse(identifier)
|
|
31
41
|
end
|
|
@@ -14,12 +14,19 @@ module Pubid
|
|
|
14
14
|
# Parse an IHO identifier string into an identifier object
|
|
15
15
|
# @param identifier [String] The IHO identifier string to parse
|
|
16
16
|
# @return [Pubid::Iho::Identifier] The appropriate identifier object
|
|
17
|
-
# @raise [
|
|
17
|
+
# @raise [Pubid::Errors::ParseError] If parsing fails
|
|
18
18
|
def self.parse(identifier)
|
|
19
|
+
unless identifier.is_a?(String)
|
|
20
|
+
raise Pubid::Errors::InvalidInputError,
|
|
21
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
25
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
26
|
+
end
|
|
27
|
+
|
|
19
28
|
parsed = Parser.parse(identifier)
|
|
20
29
|
Builder.build(parsed)
|
|
21
|
-
rescue Parslet::ParseFailed => e
|
|
22
|
-
raise "Failed to parse IHO identifier '#{identifier}': #{e.message}"
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
# `number` overrides the generic Components::Code attribute with a plain
|
data/lib/pubid/iho/parser.rb
CHANGED
data/lib/pubid/iho.rb
CHANGED
|
@@ -44,20 +44,38 @@ module Pubid
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def self.parse(identifier)
|
|
47
|
+
unless identifier.is_a?(String)
|
|
48
|
+
raise Pubid::Errors::InvalidInputError,
|
|
49
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
50
|
+
end
|
|
51
|
+
|
|
47
52
|
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
48
|
-
raise
|
|
53
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
49
54
|
end
|
|
50
55
|
|
|
56
|
+
# The two guards above must stay OUTSIDE build_identifier: this method
|
|
57
|
+
# rescues ArgumentError to convert the Builder's check-digit and
|
|
58
|
+
# length validation into a parse failure, and that rescue used to
|
|
59
|
+
# swallow the guards' own ArgumentError and re-raise it as a
|
|
60
|
+
# RuntimeError - so ISBN was the one guarded flavor where an over-long
|
|
61
|
+
# input did not surface as ArgumentError.
|
|
62
|
+
build_identifier(identifier)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @raise [Pubid::Errors::ParseError] if the string is not a valid ISBN
|
|
66
|
+
def self.build_identifier(identifier)
|
|
51
67
|
parsed = Parser.parse(identifier)
|
|
52
68
|
Builder.build(parsed)
|
|
53
|
-
rescue Parslet::ParseFailed => e
|
|
54
|
-
raise "Failed to parse ISBN '#{identifier}': #{e.message}"
|
|
55
69
|
rescue ArgumentError => e
|
|
56
|
-
# Builder validates length
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
raise
|
|
70
|
+
# The Builder validates length and check digit. Surface that as a parse
|
|
71
|
+
# failure, so every ISBN rejection reaches the caller as the same class
|
|
72
|
+
# a grammar rejection does.
|
|
73
|
+
raise Pubid::Errors::ParseError.new(
|
|
74
|
+
"invalid ISBN '#{identifier}': #{e.message}",
|
|
75
|
+
input: identifier, flavor: "isbn",
|
|
76
|
+
)
|
|
60
77
|
end
|
|
78
|
+
private_class_method :build_identifier
|
|
61
79
|
end
|
|
62
80
|
end
|
|
63
81
|
end
|
data/lib/pubid/isbn/parser.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Pubid
|
|
|
12
12
|
# ISBN-10 final digit may be "X" (check digit value 10). Hyphens are
|
|
13
13
|
# optional and may appear in any group position; they are preserved
|
|
14
14
|
# for round-trip rendering.
|
|
15
|
-
class Parser <
|
|
15
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
16
16
|
rule(:space) { str(" ") }
|
|
17
17
|
rule(:colon) { str(":") }
|
|
18
18
|
rule(:hyphen) { str("-") }
|