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
|
@@ -37,7 +37,9 @@ module Pubid
|
|
|
37
37
|
abbr = annotate(abbr, typed_stage_css(@id.typed_stage),
|
|
38
38
|
annotated: ann)
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
if @id.subgroup
|
|
41
|
+
subgroup_str = render_component(@id.subgroup, context)
|
|
42
|
+
end
|
|
41
43
|
|
|
42
44
|
[
|
|
43
45
|
pub_str,
|
|
@@ -50,15 +52,15 @@ module Pubid
|
|
|
50
52
|
ann = context.annotated
|
|
51
53
|
parts = []
|
|
52
54
|
if @id.number
|
|
53
|
-
parts << annotate(@id.number
|
|
55
|
+
parts << annotate(render_component(@id.number, context), "docnumber",
|
|
54
56
|
annotated: ann)
|
|
55
57
|
end
|
|
56
58
|
if @id.part
|
|
57
|
-
parts << " #{annotate(@id.part
|
|
59
|
+
parts << " #{annotate(render_component(@id.part, context), 'part',
|
|
58
60
|
annotated: ann)}"
|
|
59
61
|
end
|
|
60
62
|
if @id.subpart
|
|
61
|
-
parts << "-#{annotate(@id.subpart
|
|
63
|
+
parts << "-#{annotate(render_component(@id.subpart, context), 'part',
|
|
62
64
|
annotated: ann)}"
|
|
63
65
|
end
|
|
64
66
|
if @id.stage_iteration
|
|
@@ -41,15 +41,15 @@ module Pubid
|
|
|
41
41
|
ann = context.annotated
|
|
42
42
|
parts = []
|
|
43
43
|
if @id.number
|
|
44
|
-
parts << annotate(@id.number
|
|
44
|
+
parts << annotate(render_component(@id.number, context), "docnumber",
|
|
45
45
|
annotated: ann)
|
|
46
46
|
end
|
|
47
47
|
if @id.part
|
|
48
|
-
parts << "-#{annotate(@id.part
|
|
48
|
+
parts << "-#{annotate(render_component(@id.part, context), 'part',
|
|
49
49
|
annotated: ann)}"
|
|
50
50
|
end
|
|
51
51
|
if @id.subpart
|
|
52
|
-
parts << "-#{annotate(@id.subpart
|
|
52
|
+
parts << "-#{annotate(render_component(@id.subpart, context), 'part',
|
|
53
53
|
annotated: ann)}"
|
|
54
54
|
end
|
|
55
55
|
if @id.stage_iteration
|
|
@@ -28,6 +28,20 @@ module Pubid
|
|
|
28
28
|
class MrString < Base
|
|
29
29
|
SEPARATOR_SUPPLEMENT = "_"
|
|
30
30
|
|
|
31
|
+
# The flat MR segments, in order, as the hook each one reads. A hook
|
|
32
|
+
# returning nil contributes no segment, so a flavor fills only the slots
|
|
33
|
+
# its identity actually uses — `mr_volume` (ECMA) is nil everywhere else.
|
|
34
|
+
SEGMENTS = %i[
|
|
35
|
+
mr_publisher
|
|
36
|
+
mr_type
|
|
37
|
+
mr_number_with_part
|
|
38
|
+
mr_year
|
|
39
|
+
mr_edition
|
|
40
|
+
mr_volume
|
|
41
|
+
mr_languages
|
|
42
|
+
mr_all_parts
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
31
45
|
def render(context: nil, **)
|
|
32
46
|
suffix = @id.mr_supplement_suffix
|
|
33
47
|
|
|
@@ -43,15 +57,7 @@ module Pubid
|
|
|
43
57
|
private
|
|
44
58
|
|
|
45
59
|
def render_flat(id)
|
|
46
|
-
|
|
47
|
-
parts << id.mr_publisher
|
|
48
|
-
parts << id.mr_type
|
|
49
|
-
parts << id.mr_number_with_part
|
|
50
|
-
parts << id.mr_year
|
|
51
|
-
parts << id.mr_edition
|
|
52
|
-
parts << id.mr_languages
|
|
53
|
-
parts << id.mr_all_parts
|
|
54
|
-
parts.compact.join(".")
|
|
60
|
+
SEGMENTS.filter_map { |hook| id.public_send(hook) }.join(".")
|
|
55
61
|
end
|
|
56
62
|
end
|
|
57
63
|
end
|
data/lib/pubid/renderers.rb
CHANGED
|
@@ -4,21 +4,39 @@ module Pubid
|
|
|
4
4
|
module Rendering
|
|
5
5
|
module Numbering
|
|
6
6
|
# Render number with optional parts and subparts
|
|
7
|
-
# @param number [Components::Code] primary number
|
|
8
|
-
# @param part [Components::Code, nil] optional part
|
|
9
|
-
# @param subpart [Components::Code, nil] optional subpart
|
|
7
|
+
# @param number [Components::Code, String, nil] primary number
|
|
8
|
+
# @param part [Components::Code, String, nil] optional part
|
|
9
|
+
# @param subpart [Components::Code, String, nil] optional subpart
|
|
10
10
|
# @param options [Hash] rendering options
|
|
11
11
|
# @return [String] formatted numbering string
|
|
12
12
|
def render_numbering(number, part = nil, subpart = nil, **options)
|
|
13
|
-
|
|
13
|
+
number_str = numbering_value(number)
|
|
14
|
+
return "" unless number_str
|
|
14
15
|
|
|
15
|
-
result = " #{
|
|
16
|
+
result = " #{number_str}"
|
|
16
17
|
separator = options[:part_separator] || "-"
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
[part, subpart].each do |component|
|
|
19
|
+
value = numbering_value(component)
|
|
20
|
+
result += "#{separator}#{value}" if value
|
|
21
|
+
end
|
|
19
22
|
|
|
20
23
|
result
|
|
21
24
|
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# `number`/`part`/`subpart` are a Components::Code on ::Pubid::Identifier
|
|
29
|
+
# but a plain :string in a growing number of flavors, so read the value
|
|
30
|
+
# through whichever shape the caller holds. Returns nil for an absent or
|
|
31
|
+
# empty component, which is what suppresses the segment.
|
|
32
|
+
def numbering_value(component)
|
|
33
|
+
return nil if component.nil?
|
|
34
|
+
|
|
35
|
+
value = component.respond_to?(:value) ? component.value : component
|
|
36
|
+
return nil if value.nil? || value.to_s.empty?
|
|
37
|
+
|
|
38
|
+
value.to_s
|
|
39
|
+
end
|
|
22
40
|
end
|
|
23
41
|
end
|
|
24
42
|
end
|
data/lib/pubid/rendering.rb
CHANGED
data/lib/pubid/sae/builder.rb
CHANGED
|
@@ -7,15 +7,25 @@ module Pubid
|
|
|
7
7
|
# Handles all SAE document types (AMS, AIR, ARP, AS, MA).
|
|
8
8
|
class Identifier < ::Pubid::Identifier
|
|
9
9
|
def self.parse(input)
|
|
10
|
+
unless input.is_a?(String)
|
|
11
|
+
raise Pubid::Errors::InvalidInputError,
|
|
12
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
if input.length > Pubid::MAX_INPUT_LENGTH
|
|
16
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
17
|
+
end
|
|
18
|
+
|
|
10
19
|
parsed = Parser.parse(input)
|
|
11
20
|
Builder.build(parsed)
|
|
12
|
-
rescue Parslet::ParseFailed => e
|
|
13
|
-
raise "Failed to parse SAE identifier: #{input}\n#{e.message}"
|
|
14
21
|
end
|
|
15
22
|
|
|
16
23
|
attribute :publisher, :string, default: -> { "SAE" }
|
|
17
24
|
attribute :type, Sae::Components::Type
|
|
18
|
-
|
|
25
|
+
# A plain :string, like every converted flavor. Sae::Components::Code was
|
|
26
|
+
# a bare alias of the shared component and never carried more than
|
|
27
|
+
# `value`, so this is a representation change only.
|
|
28
|
+
attribute :number, :string
|
|
19
29
|
attribute :date, Sae::Components::Date
|
|
20
30
|
|
|
21
31
|
def self.type
|
data/lib/pubid/sae/parser.rb
CHANGED
data/lib/pubid/sae.rb
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Schema
|
|
5
|
+
# A loaded flavor declaration (schema/{flavor}.yaml).
|
|
6
|
+
class Declaration
|
|
7
|
+
attr_reader :flavor, :schema_version, :prefixes, :identifier_types
|
|
8
|
+
|
|
9
|
+
def initialize(flavor:, schema_version:, prefixes:, identifier_types:)
|
|
10
|
+
@flavor = flavor
|
|
11
|
+
@schema_version = schema_version
|
|
12
|
+
@prefixes = prefixes.freeze
|
|
13
|
+
@identifier_types = identifier_types.map(&:freeze).freeze
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Own tokens plus joint/co-publication tokens from
|
|
18
|
+
# schema/core/joint_prefixes.yaml - mirrors the runtime
|
|
19
|
+
# Pubid::{Flavor}.prefixes contract (see PrefixesSupport).
|
|
20
|
+
def merged_prefixes
|
|
21
|
+
(prefixes + Loader.joint_prefixes_for(flavor)).freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def type_for(key)
|
|
25
|
+
identifier_types.find { |type| type.key == key }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def types_count
|
|
29
|
+
identifier_types.size
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Schema
|
|
5
|
+
# Base error for schema loading and lookup failures.
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
# Raised when a flavor declaration file cannot be found.
|
|
9
|
+
class NotFoundError < Error; end
|
|
10
|
+
|
|
11
|
+
# Raised when a declaration file violates the format contract.
|
|
12
|
+
class InvalidError < Error; end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Schema
|
|
5
|
+
# One identifier type declaration (e.g. iso "amendment", iec "vap").
|
|
6
|
+
class IdentifierType
|
|
7
|
+
attr_reader :key, :title, :short, :abbr, :typed_stages
|
|
8
|
+
|
|
9
|
+
def initialize(key:, title:, short: nil, abbr: [], typed_stages: [])
|
|
10
|
+
@key = key
|
|
11
|
+
@title = title
|
|
12
|
+
@short = short
|
|
13
|
+
@abbr = abbr.freeze
|
|
14
|
+
@typed_stages = typed_stages.map(&:freeze).freeze
|
|
15
|
+
freeze
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def typed_stage_for_abbr(candidate)
|
|
19
|
+
typed_stages.find { |stage| stage.matches_abbr?(candidate) }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Schema
|
|
5
|
+
# Loads and validates flavor declarations from schema/. Declarations
|
|
6
|
+
# are memoized and deeply frozen; loading is lazy per flavor so the
|
|
7
|
+
# parse hot path pays no boot cost.
|
|
8
|
+
class Loader
|
|
9
|
+
SCHEMA_ROOT = File.expand_path("../../../schema", __dir__).freeze
|
|
10
|
+
CORE_DIR = File.join(SCHEMA_ROOT, "core").freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def for(flavor)
|
|
14
|
+
flavor = flavor.to_s
|
|
15
|
+
declarations[flavor] ||= build_declaration(flavor)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def joint_prefixes_for(flavor)
|
|
19
|
+
joint_prefixes[flavor.to_s] || [].freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Full joint-prefix map (flavor key => tokens) from
|
|
23
|
+
# schema/core/joint_prefixes.yaml.
|
|
24
|
+
def joint_prefixes_map
|
|
25
|
+
joint_prefixes
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def loaded_flavors
|
|
29
|
+
declarations.keys.sort
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def declarations
|
|
35
|
+
@declarations ||= {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def joint_prefixes
|
|
39
|
+
@joint_prefixes ||= load_joint_prefixes
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def load_joint_prefixes
|
|
43
|
+
path = File.join(CORE_DIR, "joint_prefixes.yaml")
|
|
44
|
+
data = YAML.safe_load_file(path)
|
|
45
|
+
data.fetch("joint_prefixes")
|
|
46
|
+
.transform_values(&:freeze)
|
|
47
|
+
.freeze
|
|
48
|
+
rescue Errno::ENOENT, KeyError => e
|
|
49
|
+
raise InvalidError, "cannot load #{path}: #{e.message}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def build_declaration(flavor)
|
|
53
|
+
path = declaration_path(flavor)
|
|
54
|
+
data = YAML.safe_load_file(path)
|
|
55
|
+
validate!(flavor, path, data)
|
|
56
|
+
Declaration.new(
|
|
57
|
+
flavor: data.fetch("flavor"),
|
|
58
|
+
schema_version: data.fetch("schema_version"),
|
|
59
|
+
prefixes: data.fetch("prefixes"),
|
|
60
|
+
identifier_types: parse_identifier_types(data),
|
|
61
|
+
).freeze
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def declaration_path(flavor)
|
|
65
|
+
path = File.join(SCHEMA_ROOT, "#{flavor}.yaml")
|
|
66
|
+
unless File.exist?(path)
|
|
67
|
+
raise NotFoundError, "no declaration for #{flavor} at #{path}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
path
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def parse_identifier_types(data)
|
|
74
|
+
data.fetch("identifier_types")
|
|
75
|
+
.map { |entry| parse_identifier_type(entry) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def parse_identifier_type(entry)
|
|
79
|
+
IdentifierType.new(
|
|
80
|
+
key: entry.fetch("key"),
|
|
81
|
+
title: entry.fetch("title"),
|
|
82
|
+
short: entry["short"],
|
|
83
|
+
abbr: entry["abbr"] || [],
|
|
84
|
+
typed_stages: parse_typed_stages(entry),
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_typed_stages(entry)
|
|
89
|
+
(entry["typed_stages"] || []).map { |stage| parse_typed_stage(stage) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def parse_typed_stage(stage)
|
|
93
|
+
TypedStage.new(
|
|
94
|
+
stage_code: stage.fetch("stage_code"),
|
|
95
|
+
type_code: stage["type_code"],
|
|
96
|
+
abbr: stage.fetch("abbr"),
|
|
97
|
+
name: stage["name"],
|
|
98
|
+
harmonized_stages: stage["harmonized_stages"] || [],
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def validate!(flavor, path, data)
|
|
103
|
+
raise InvalidError, "#{path}: not a mapping" unless data.is_a?(Hash)
|
|
104
|
+
|
|
105
|
+
%w[flavor schema_version prefixes identifier_types].each do |key|
|
|
106
|
+
next if data.key?(key)
|
|
107
|
+
|
|
108
|
+
raise InvalidError, "#{path}: missing required key #{key}"
|
|
109
|
+
end
|
|
110
|
+
return unless data["flavor"] != flavor
|
|
111
|
+
|
|
112
|
+
raise InvalidError, "#{path}: flavor/file mismatch"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Schema
|
|
5
|
+
# One typed stage entry of an identifier type declaration.
|
|
6
|
+
class TypedStage
|
|
7
|
+
attr_reader :stage_code, :type_code, :abbr, :name, :harmonized_stages
|
|
8
|
+
|
|
9
|
+
def initialize(stage_code:, type_code: nil, abbr: [], name: nil,
|
|
10
|
+
harmonized_stages: [])
|
|
11
|
+
@stage_code = stage_code
|
|
12
|
+
@type_code = type_code
|
|
13
|
+
@abbr = abbr.freeze
|
|
14
|
+
@name = name
|
|
15
|
+
@harmonized_stages = harmonized_stages.freeze
|
|
16
|
+
freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def matches_abbr?(candidate)
|
|
20
|
+
abbr.include?(candidate)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/pubid/schema.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module Pubid
|
|
6
|
+
# Single source of truth declarations (schema/ directory). TODO 03 of the
|
|
7
|
+
# SSOT restructure: loader and value objects. TODO 04-07 make the runtime
|
|
8
|
+
# a consumer of these declarations (registry bridge, prefixes, metadata).
|
|
9
|
+
module Schema
|
|
10
|
+
autoload :Error, "pubid/schema/error"
|
|
11
|
+
autoload :NotFoundError, "pubid/schema/error"
|
|
12
|
+
autoload :InvalidError, "pubid/schema/error"
|
|
13
|
+
autoload :TypedStage, "pubid/schema/typed_stage"
|
|
14
|
+
autoload :IdentifierType, "pubid/schema/identifier_type"
|
|
15
|
+
autoload :Declaration, "pubid/schema/declaration"
|
|
16
|
+
autoload :Loader, "pubid/schema/loader"
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Pubid::Schema.for("iso") => frozen Pubid::Schema::Declaration
|
|
20
|
+
def for(flavor)
|
|
21
|
+
Loader.for(flavor)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/pubid/tgpp/builder.rb
CHANGED
|
@@ -14,7 +14,13 @@ module Pubid
|
|
|
14
14
|
attribute :suffix, :string
|
|
15
15
|
# 1–2 hyphen parts (e.g. "26.171-1", "29.198-04-1"); strings preserve any
|
|
16
16
|
# zero-padding.
|
|
17
|
-
|
|
17
|
+
# `initialize_empty` makes a part-less identifier hold `[]` on BOTH
|
|
18
|
+
# construction paths: Builder always passes an array, but the serialized
|
|
19
|
+
# hash carries no `parts` key, so from_hash used to leave it nil and the
|
|
20
|
+
# two compared unequal — which silently broke `#matches?` (and so every
|
|
21
|
+
# part-less relaton index lookup). It does not change the serialized
|
|
22
|
+
# shape: lutaml omits an empty collection either way. See CLAUDE.md.
|
|
23
|
+
attribute :parts, :string, collection: true, initialize_empty: true
|
|
18
24
|
# Raw release token, stored verbatim: "REL-4", "Ph1", "UMTS",
|
|
19
25
|
# "Release 2000".
|
|
20
26
|
attribute :release, :string
|
|
@@ -73,18 +79,28 @@ module Pubid
|
|
|
73
79
|
@with_publisher = false
|
|
74
80
|
end
|
|
75
81
|
|
|
76
|
-
# Parse a 3GPP identifier string into an identifier object
|
|
82
|
+
# Parse a 3GPP identifier string into an identifier object.
|
|
83
|
+
#
|
|
84
|
+
# Let Parslet::ParseFailed propagate on a bad reference (matching ISO and
|
|
85
|
+
# ETSI), so relaton-cli's `rescue Parslet::ParseFailed` fetch handler
|
|
86
|
+
# catches it instead of a bare RuntimeError. The length guard keeps its
|
|
87
|
+
# ArgumentError — that is a different failure (input too long, not
|
|
88
|
+
# unparseable) and it is the ReDoS barrier.
|
|
89
|
+
#
|
|
77
90
|
# @param identifier [String] The 3GPP identifier string to parse
|
|
78
91
|
# @return [Identifier] The appropriate identifier object
|
|
79
92
|
def self.parse(identifier)
|
|
93
|
+
unless identifier.is_a?(String)
|
|
94
|
+
raise Pubid::Errors::InvalidInputError,
|
|
95
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
96
|
+
end
|
|
97
|
+
|
|
80
98
|
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
81
|
-
raise
|
|
99
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
82
100
|
end
|
|
83
101
|
|
|
84
102
|
parsed = Parser.parse(identifier)
|
|
85
103
|
Builder.build(parsed)
|
|
86
|
-
rescue Parslet::ParseFailed => e
|
|
87
|
-
raise "Failed to parse 3GPP identifier '#{identifier}': #{e.message}"
|
|
88
104
|
end
|
|
89
105
|
end
|
|
90
106
|
end
|
|
@@ -4,8 +4,8 @@ module Pubid
|
|
|
4
4
|
module Tgpp
|
|
5
5
|
module Identifiers
|
|
6
6
|
# Technical Report identifier type.
|
|
7
|
-
# Format: [3GPP ]TR NN.NNN[suffix][-part…]:<release
|
|
8
|
-
# Example: TR 00.01U:UMTS/3.0.0
|
|
7
|
+
# Format: [3GPP ]TR NN.NNN[suffix][-part…][:<release>][/<version>]
|
|
8
|
+
# Example: TR 00.01U:UMTS/3.0.0, or the partial "TR 00.01U".
|
|
9
9
|
class TechnicalReport < Pubid::Tgpp::Identifier
|
|
10
10
|
TYPED_STAGES = [
|
|
11
11
|
Pubid::Components::TypedStage.new(
|
|
@@ -4,8 +4,8 @@ module Pubid
|
|
|
4
4
|
module Tgpp
|
|
5
5
|
module Identifiers
|
|
6
6
|
# Technical Specification identifier type.
|
|
7
|
-
# Format: [3GPP ]TS NN.NNN[suffix][-part…]:<release
|
|
8
|
-
# Example: TS 23.207:REL-4/2.0.0
|
|
7
|
+
# Format: [3GPP ]TS NN.NNN[suffix][-part…][:<release>][/<version>]
|
|
8
|
+
# Example: TS 23.207:REL-4/2.0.0, or the partial "TS 23.207".
|
|
9
9
|
class TechnicalSpecification < Pubid::Tgpp::Identifier
|
|
10
10
|
TYPED_STAGES = [
|
|
11
11
|
Pubid::Components::TypedStage.new(
|
data/lib/pubid/tgpp/parser.rb
CHANGED
|
@@ -6,12 +6,18 @@ module Pubid
|
|
|
6
6
|
module Tgpp
|
|
7
7
|
# Parslet grammar for 3GPP identifiers.
|
|
8
8
|
#
|
|
9
|
-
# Form: `[3GPP ]<TR|TS> <NN.NNN>[suffix][-part…]:<release
|
|
9
|
+
# Form: `[3GPP ]<TR|TS> <NN.NNN>[suffix][-part…][:<release>][/<version>]`
|
|
10
10
|
# TS 23.207:REL-4/2.0.0
|
|
11
11
|
# 3GPP TR 00.01U:UMTS/3.0.0
|
|
12
12
|
# TS 29.198-04-1:REL-5/5.0.0
|
|
13
13
|
# TS 02.68:Release 2000/9.0.0
|
|
14
|
-
|
|
14
|
+
# 3GPP TS 23.207 (bare reference)
|
|
15
|
+
#
|
|
16
|
+
# The release and the version are both optional: a user reference names the
|
|
17
|
+
# document alone ("3GPP TS 23.207"), and relaton parses that bare form to
|
|
18
|
+
# search the index. Only the type and the dotted number core are required,
|
|
19
|
+
# so "TS" and "TS foo" are still rejected.
|
|
20
|
+
class Parser < ::Pubid::Parser::Grammar
|
|
15
21
|
rule(:digit) { match["0-9"] }
|
|
16
22
|
rule(:digits) { digit.repeat(1) }
|
|
17
23
|
rule(:space) { str(" ") }
|
|
@@ -37,19 +43,29 @@ module Pubid
|
|
|
37
43
|
# Excludes ":" (as well as "/") so the ":"-delimited URN scheme can always
|
|
38
44
|
# encode it — every real release ("REL-4", "Ph1", "UMTS", "Release 2000")
|
|
39
45
|
# is colon-free.
|
|
40
|
-
|
|
46
|
+
#
|
|
47
|
+
# A trailing segment shaped exactly like a version is a mistyped "/"
|
|
48
|
+
# separator ("TS 23.207:2.0.0"), not a release: no release in the 88,464
|
|
49
|
+
# published index rows contains a dot at all. Reject it rather than
|
|
50
|
+
# silently misfiling the version as the release — which only became
|
|
51
|
+
# reachable once the version segment was made optional.
|
|
52
|
+
rule(:release) do
|
|
53
|
+
(version_core >> any.absent?).absent? >>
|
|
54
|
+
match["^/:"].repeat(1).as(:release)
|
|
55
|
+
end
|
|
41
56
|
|
|
42
57
|
# Three-part version, kept as a string.
|
|
43
|
-
rule(:
|
|
44
|
-
|
|
58
|
+
rule(:version_core) do
|
|
59
|
+
digits >> str(".") >> digits >> str(".") >> digits
|
|
45
60
|
end
|
|
61
|
+
rule(:version) { version_core.as(:version) }
|
|
46
62
|
|
|
47
63
|
rule(:identifier) do
|
|
48
64
|
publisher_prefix.maybe >>
|
|
49
65
|
type >> space >>
|
|
50
66
|
number_core >> suffix.maybe >> parts >>
|
|
51
67
|
(str(":") >> release).maybe >>
|
|
52
|
-
str("/") >> version
|
|
68
|
+
(str("/") >> version).maybe
|
|
53
69
|
end
|
|
54
70
|
|
|
55
71
|
rule(:root) { identifier }
|
data/lib/pubid/tgpp/renderer.rb
CHANGED
|
@@ -9,6 +9,7 @@ module Pubid
|
|
|
9
9
|
# "3GPP TS 23.207:REL-4/2.0.0" (with_publisher: true)
|
|
10
10
|
# "TS 29.198-04-1:REL-5/5.0.0" (parts)
|
|
11
11
|
# "TR 00.01U:UMTS/3.0.0" (suffix)
|
|
12
|
+
# "TS 23.207" (partial reference)
|
|
12
13
|
class Renderer < ::Pubid::Renderers::Base
|
|
13
14
|
PUBLISHER = "3GPP"
|
|
14
15
|
|
|
@@ -17,15 +18,30 @@ module Pubid
|
|
|
17
18
|
head = []
|
|
18
19
|
head << PUBLISHER if with_publisher?(id)
|
|
19
20
|
head << id.type_prefix
|
|
20
|
-
|
|
21
|
-
# A handful of legacy records omit the release segment entirely
|
|
22
|
-
# (e.g. "TS 29.215/2.0.0").
|
|
23
|
-
result += ":#{id.release}" if id.release
|
|
24
|
-
"#{result}/#{id.version}"
|
|
21
|
+
"#{head.join(' ')} #{id.code}#{qualifiers(id)}"
|
|
25
22
|
end
|
|
26
23
|
|
|
27
24
|
private
|
|
28
25
|
|
|
26
|
+
# The trailing ":<release>" and "/<version>" qualifiers. Both are
|
|
27
|
+
# optional: a handful of legacy records omit the release entirely
|
|
28
|
+
# (e.g. "TS 29.215/2.0.0"), and a partial user reference omits both
|
|
29
|
+
# (e.g. "TS 23.207"). Render no separator for an absent one.
|
|
30
|
+
#
|
|
31
|
+
# Blank, not just nil: the grammar cannot produce "", but a hand-built
|
|
32
|
+
# hash can, and a dangling "TS 23.207:" would not re-parse. This mirrors
|
|
33
|
+
# the same guard in UrnGenerator#tail_segments.
|
|
34
|
+
def qualifiers(id)
|
|
35
|
+
result = +""
|
|
36
|
+
result << ":#{id.release}" unless blank?(id.release)
|
|
37
|
+
result << "/#{id.version}" unless blank?(id.version)
|
|
38
|
+
result
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def blank?(value)
|
|
42
|
+
value.nil? || value.empty?
|
|
43
|
+
end
|
|
44
|
+
|
|
29
45
|
# Default is no publisher token (the relaton index id form); the caller
|
|
30
46
|
# opts in via `to_s(with_publisher: true)`.
|
|
31
47
|
def with_publisher?(id)
|