pubid 2.0.0.pre.alpha.7 → 2.0.0.pre.alpha.9
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 +9 -50
- data/data/bipm/update_codes.yaml +9 -0
- data/data/iec/update_codes.yaml +3 -0
- data/data/ieee/update_codes.yaml +107 -1
- data/data/nist/series.yaml +155 -0
- data/data/nist/update_codes.yaml +8 -0
- data/lib/pubid/adobe/builder.rb +52 -0
- data/lib/pubid/adobe/identifier.rb +49 -0
- data/lib/pubid/adobe/identifiers/publication.rb +31 -0
- data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
- data/lib/pubid/adobe/identifiers.rb +10 -0
- data/lib/pubid/adobe/parser.rb +128 -0
- data/lib/pubid/adobe/renderer.rb +39 -0
- data/lib/pubid/adobe/urn_generator.rb +42 -0
- data/lib/pubid/adobe/urn_parser.rb +69 -0
- data/lib/pubid/adobe.rb +60 -0
- data/lib/pubid/amca/builder.rb +2 -2
- data/lib/pubid/amca/identifier.rb +1 -3
- data/lib/pubid/amca/identifiers/base.rb +1 -6
- data/lib/pubid/amca/identifiers/interpretation.rb +1 -1
- data/lib/pubid/amca/identifiers/publication.rb +1 -1
- data/lib/pubid/amca/identifiers/standard.rb +1 -1
- data/lib/pubid/amca/identifiers.rb +0 -1
- data/lib/pubid/amca/single_identifier.rb +1 -1
- data/lib/pubid/amca.rb +3 -3
- data/lib/pubid/ashrae/builder.rb +22 -22
- data/lib/pubid/ashrae/identifier.rb +3 -4
- data/lib/pubid/ashrae/identifiers/addenda_package.rb +1 -1
- data/lib/pubid/ashrae/identifiers/addendum.rb +1 -1
- data/lib/pubid/ashrae/identifiers/base.rb +14 -8
- data/lib/pubid/ashrae/identifiers/combined_addenda.rb +1 -1
- data/lib/pubid/ashrae/identifiers.rb +0 -1
- data/lib/pubid/ashrae/parser.rb +14 -9
- data/lib/pubid/ashrae/renderer.rb +19 -19
- data/lib/pubid/ashrae/single_identifier.rb +1 -1
- data/lib/pubid/ashrae/supplement_identifier.rb +6 -6
- data/lib/pubid/ashrae.rb +3 -3
- data/lib/pubid/bipm/builder.rb +107 -0
- data/lib/pubid/bipm/identifier.rb +160 -0
- data/lib/pubid/bipm/identifiers/committee_document.rb +24 -0
- data/lib/pubid/bipm/identifiers/guide.rb +24 -0
- data/lib/pubid/bipm/identifiers/meeting.rb +41 -0
- data/lib/pubid/bipm/identifiers/mep.rb +21 -0
- data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
- data/lib/pubid/bipm/identifiers/si_brochure.rb +20 -0
- data/lib/pubid/bipm/identifiers.rb +15 -0
- data/lib/pubid/bipm/parser.rb +184 -0
- data/lib/pubid/bipm/renderer.rb +110 -0
- data/lib/pubid/bipm/urn_generator.rb +58 -0
- data/lib/pubid/bipm/urn_parser.rb +52 -0
- data/lib/pubid/bipm.rb +86 -0
- data/lib/pubid/bsi/builder.rb +14 -14
- data/lib/pubid/bsi/identifier.rb +0 -1
- data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
- data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
- data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
- data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
- data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
- data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
- data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
- data/lib/pubid/bsi/renderer.rb +8 -8
- data/lib/pubid/bsi/single_identifier.rb +48 -0
- data/lib/pubid/builder/base.rb +5 -3
- data/lib/pubid/bundled_identifier.rb +3 -3
- data/lib/pubid/calconnect/builder.rb +38 -0
- data/lib/pubid/calconnect/identifier.rb +117 -0
- data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
- data/lib/pubid/calconnect/identifiers.rb +9 -0
- data/lib/pubid/calconnect/parser.rb +54 -0
- data/lib/pubid/calconnect/renderer.rb +36 -0
- data/lib/pubid/calconnect/urn_generator.rb +33 -0
- data/lib/pubid/calconnect/urn_parser.rb +34 -0
- data/lib/pubid/calconnect.rb +77 -0
- data/lib/pubid/ccsds/builder.rb +1 -1
- data/lib/pubid/ccsds/identifier.rb +1 -1
- data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
- data/lib/pubid/ccsds/urn_generator.rb +3 -3
- data/lib/pubid/cen_cenelec/builder.rb +46 -12
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -2
- data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +6 -0
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
- data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
- data/lib/pubid/cen_cenelec/renderer.rb +5 -5
- data/lib/pubid/cen_cenelec/supplement_identifier.rb +5 -5
- data/lib/pubid/cen_cenelec/urn_generator.rb +1 -1
- data/lib/pubid/cen_cenelec.rb +76 -72
- data/lib/pubid/cie/builder.rb +139 -24
- data/lib/pubid/cie/identifier.rb +7 -3
- data/lib/pubid/cie/identifiers/bundle.rb +32 -4
- data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
- data/lib/pubid/cie/identifiers/conference.rb +9 -4
- data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
- data/lib/pubid/cie/identifiers/dual_published.rb +4 -4
- data/lib/pubid/cie/identifiers/identical.rb +7 -7
- data/lib/pubid/cie/identifiers/joint_published.rb +8 -8
- data/lib/pubid/cie/identifiers/proceedings.rb +39 -0
- data/lib/pubid/cie/identifiers/standard.rb +33 -7
- data/lib/pubid/cie/identifiers/supplement.rb +24 -22
- data/lib/pubid/cie/identifiers/tutorial_bundle.rb +6 -2
- data/lib/pubid/cie/identifiers.rb +2 -0
- data/lib/pubid/cie/parser.rb +54 -5
- data/lib/pubid/cie/single_identifier.rb +40 -1
- data/lib/pubid/cie/supplement_identifier.rb +29 -16
- data/lib/pubid/cie/urn_generator.rb +11 -8
- data/lib/pubid/cie.rb +0 -1
- data/lib/pubid/components/date.rb +21 -5
- data/lib/pubid/csa/builder.rb +1 -1
- data/lib/pubid/csa/composite_identifier.rb +17 -1
- data/lib/pubid/csa/identifier.rb +48 -3
- data/lib/pubid/csa/identifiers/bundled.rb +6 -0
- data/lib/pubid/csa/identifiers/combined.rb +6 -0
- data/lib/pubid/csa/identifiers/package.rb +2 -2
- data/lib/pubid/csa/parser.rb +6 -6
- data/lib/pubid/csa/wrapper_identifier.rb +17 -0
- data/lib/pubid/doi/builder.rb +18 -0
- data/lib/pubid/doi/identifier.rb +46 -0
- data/lib/pubid/doi/identifiers/resource.rb +30 -0
- data/lib/pubid/doi/identifiers.rb +9 -0
- data/lib/pubid/doi/parser.rb +52 -0
- data/lib/pubid/doi/renderer.rb +13 -0
- data/lib/pubid/doi.rb +55 -0
- data/lib/pubid/easc/builder.rb +55 -0
- data/lib/pubid/easc/identifier.rb +61 -0
- data/lib/pubid/easc/identifiers/pmg.rb +20 -0
- data/lib/pubid/easc/identifiers/rmg.rb +19 -0
- data/lib/pubid/easc/identifiers.rb +10 -0
- data/lib/pubid/easc/parser.rb +80 -0
- data/lib/pubid/easc/renderer.rb +48 -0
- data/lib/pubid/easc/urn_generator.rb +46 -0
- data/lib/pubid/easc/urn_parser.rb +57 -0
- data/lib/pubid/easc.rb +52 -0
- data/lib/pubid/ecma/builder.rb +31 -0
- data/lib/pubid/ecma/identifier.rb +76 -0
- data/lib/pubid/ecma/identifiers/memento.rb +30 -0
- data/lib/pubid/ecma/identifiers/standard.rb +31 -0
- data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
- data/lib/pubid/ecma/identifiers.rb +11 -0
- data/lib/pubid/ecma/parser.rb +41 -0
- data/lib/pubid/ecma/renderer.rb +46 -0
- data/lib/pubid/ecma/urn_generator.rb +25 -0
- data/lib/pubid/ecma/urn_parser.rb +35 -0
- data/lib/pubid/ecma.rb +67 -0
- data/lib/pubid/etsi/builder.rb +7 -3
- data/lib/pubid/etsi/identifier.rb +1 -3
- data/lib/pubid/etsi/identifiers/base.rb +28 -10
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +128 -4
- data/lib/pubid/etsi/identifiers/supplement_identifier.rb +35 -3
- data/lib/pubid/etsi/identifiers.rb +0 -1
- data/lib/pubid/etsi/parser.rb +8 -2
- data/lib/pubid/etsi/renderer.rb +8 -2
- data/lib/pubid/etsi.rb +5 -5
- data/lib/pubid/export/exporter.rb +2 -1
- data/lib/pubid/export/flavor_exporter.rb +18 -3
- data/lib/pubid/gb/builder.rb +45 -0
- data/lib/pubid/gb/identifier.rb +64 -0
- data/lib/pubid/gb/identifiers/standard.rb +34 -0
- data/lib/pubid/gb/identifiers.rb +9 -0
- data/lib/pubid/gb/parser.rb +63 -0
- data/lib/pubid/gb/renderer.rb +35 -0
- data/lib/pubid/gb.rb +87 -0
- data/lib/pubid/gost/builder.rb +148 -0
- data/lib/pubid/gost/identifier.rb +49 -0
- data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
- data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
- data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
- data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
- data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
- data/lib/pubid/gost/identifiers.rb +13 -0
- data/lib/pubid/gost/parser.rb +97 -0
- data/lib/pubid/gost/renderer.rb +48 -0
- data/lib/pubid/gost/urn_generator.rb +46 -0
- data/lib/pubid/gost/urn_parser.rb +52 -0
- data/lib/pubid/gost.rb +49 -0
- data/lib/pubid/iala/builder.rb +22 -27
- data/lib/pubid/iala/identifier.rb +27 -2
- data/lib/pubid/iala/identifiers/advice.rb +1 -1
- data/lib/pubid/iala/identifiers/annex.rb +14 -12
- data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
- data/lib/pubid/iala/identifiers/guideline.rb +3 -1
- data/lib/pubid/iala/identifiers/letter.rb +1 -1
- data/lib/pubid/iala/identifiers/manual.rb +3 -1
- data/lib/pubid/iala/identifiers/model_course.rb +3 -1
- data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
- data/lib/pubid/iala/identifiers/report.rb +1 -1
- data/lib/pubid/iala/identifiers/resolution.rb +1 -1
- data/lib/pubid/iala/identifiers/standard.rb +3 -1
- data/lib/pubid/iala/identifiers.rb +0 -1
- data/lib/pubid/iala/renderer.rb +1 -1
- data/lib/pubid/iala/urn_generator.rb +1 -1
- data/lib/pubid/iala/urn_parser.rb +19 -2
- data/lib/pubid/iala.rb +4 -4
- data/lib/pubid/iana/builder.rb +20 -0
- data/lib/pubid/iana/identifier.rb +72 -0
- data/lib/pubid/iana/identifiers/registry.rb +33 -0
- data/lib/pubid/iana/identifiers.rb +9 -0
- data/lib/pubid/iana/parser.rb +38 -0
- data/lib/pubid/iana/renderer.rb +29 -0
- data/lib/pubid/iana/urn_generator.rb +15 -0
- data/lib/pubid/iana/urn_parser.rb +24 -0
- data/lib/pubid/iana.rb +69 -0
- data/lib/pubid/identifier.rb +210 -23
- data/lib/pubid/idf/builder.rb +1 -1
- data/lib/pubid/idf/parser.rb +2 -2
- data/lib/pubid/idf/renderer.rb +1 -1
- data/lib/pubid/idf/supplement_identifier.rb +3 -3
- data/lib/pubid/iec/builder.rb +35 -25
- data/lib/pubid/iec/identifier.rb +47 -2
- data/lib/pubid/iec/identifiers/base.rb +2 -2
- data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +11 -11
- data/lib/pubid/iec/identifiers/international_standard.rb +8 -5
- data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
- data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
- data/lib/pubid/iec/identifiers/technical_report.rb +1 -1
- data/lib/pubid/iec/identifiers/technical_specification.rb +1 -1
- data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
- data/lib/pubid/iec/identifiers.rb +1 -0
- data/lib/pubid/iec/parser.rb +51 -10
- data/lib/pubid/iec/renderer.rb +18 -8
- data/lib/pubid/iec/single_identifier.rb +1 -1
- data/lib/pubid/iec/supplement_identifier.rb +32 -19
- data/lib/pubid/iec.rb +1 -6
- data/lib/pubid/ieee/aiee/builder.rb +17 -3
- data/lib/pubid/ieee/aiee/identifier.rb +45 -61
- data/lib/pubid/ieee/builder.rb +341 -68
- data/lib/pubid/ieee/compaction.rb +121 -0
- data/lib/pubid/ieee/components/draft.rb +47 -7
- data/lib/pubid/ieee/identifier.rb +1 -3
- data/lib/pubid/ieee/identifiers/adopted_standard.rb +30 -5
- data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
- data/lib/pubid/ieee/identifiers/base.rb +106 -13
- data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
- data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
- data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
- data/lib/pubid/ieee/identifiers/csa_dual_published.rb +3 -3
- data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
- data/lib/pubid/ieee/identifiers/dual_published.rb +3 -3
- data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
- data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +2 -1
- data/lib/pubid/ieee/identifiers/joint_development.rb +56 -11
- data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -1
- data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
- data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
- data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
- data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
- data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
- data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
- data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
- data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
- data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
- data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
- data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
- data/lib/pubid/ieee/identifiers/standard.rb +4 -1
- data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
- data/lib/pubid/ieee/identifiers.rb +2 -1
- data/lib/pubid/ieee/ire/builder.rb +7 -6
- data/lib/pubid/ieee/ire/identifier.rb +48 -33
- data/lib/pubid/ieee/nesc/builder.rb +33 -20
- data/lib/pubid/ieee/nesc/parser.rb +15 -14
- data/lib/pubid/ieee/parser.rb +461 -43
- data/lib/pubid/ieee/pre_parser.rb +1 -1
- data/lib/pubid/ieee/renderer.rb +154 -57
- data/lib/pubid/ieee/typed_stages.rb +12 -1
- data/lib/pubid/ieee/urn_generator.rb +3 -5
- data/lib/pubid/ieee.rb +56 -3
- data/lib/pubid/ietf/builder.rb +62 -0
- data/lib/pubid/ietf/identifier.rb +5 -0
- data/lib/pubid/ietf/identifiers/base.rb +75 -0
- data/lib/pubid/ietf/identifiers/bcp.rb +25 -0
- data/lib/pubid/ietf/identifiers/fyi.rb +25 -0
- data/lib/pubid/ietf/identifiers/internet_draft.rb +29 -0
- data/lib/pubid/ietf/identifiers/rfc.rb +25 -0
- data/lib/pubid/ietf/identifiers/std.rb +25 -0
- data/lib/pubid/ietf/identifiers.rb +13 -0
- data/lib/pubid/ietf/parser.rb +43 -0
- data/lib/pubid/ietf/renderer.rb +26 -0
- data/lib/pubid/ietf/urn_generator.rb +23 -0
- data/lib/pubid/ietf/urn_parser.rb +35 -0
- data/lib/pubid/ietf.rb +76 -0
- data/lib/pubid/iho/identifier.rb +1 -3
- data/lib/pubid/iho/identifiers/base.rb +1 -7
- data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
- data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
- data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
- data/lib/pubid/iho/identifiers/publication.rb +1 -1
- data/lib/pubid/iho/identifiers/standard.rb +1 -1
- data/lib/pubid/iho/identifiers.rb +0 -1
- data/lib/pubid/iho.rb +7 -7
- data/lib/pubid/isbn/builder.rb +44 -0
- data/lib/pubid/isbn/check_digit.rb +53 -0
- data/lib/pubid/isbn/identifier.rb +63 -0
- data/lib/pubid/isbn/identifiers/book.rb +30 -0
- data/lib/pubid/isbn/identifiers.rb +9 -0
- data/lib/pubid/isbn/parser.rb +45 -0
- data/lib/pubid/isbn/renderer.rb +16 -0
- data/lib/pubid/isbn.rb +52 -0
- data/lib/pubid/iso/builder.rb +9 -4
- data/lib/pubid/iso/combined_identifier.rb +2 -2
- data/lib/pubid/iso/identifier.rb +17 -1
- data/lib/pubid/iso/identifiers/directives_supplement.rb +8 -8
- data/lib/pubid/iso/normalizer.rb +2 -2
- data/lib/pubid/iso/parser.rb +16 -12
- data/lib/pubid/iso/supplement_identifier.rb +19 -6
- data/lib/pubid/iso/urn_generator.rb +4 -1
- data/lib/pubid/iso/urn_parser.rb +1 -1
- data/lib/pubid/itu/builder.rb +230 -29
- data/lib/pubid/itu/components/code.rb +48 -5
- data/lib/pubid/itu/components/designation.rb +35 -0
- data/lib/pubid/itu/components.rb +1 -0
- data/lib/pubid/itu/identifier.rb +1 -3
- data/lib/pubid/itu/identifiers/addendum.rb +15 -0
- data/lib/pubid/itu/identifiers/amendment.rb +6 -28
- data/lib/pubid/itu/identifiers/annex.rb +13 -2
- data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
- data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
- data/lib/pubid/itu/identifiers/base.rb +341 -23
- data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
- data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
- data/lib/pubid/itu/identifiers/errata.rb +15 -0
- data/lib/pubid/itu/identifiers/handbook.rb +38 -0
- data/lib/pubid/itu/identifiers/question.rb +63 -0
- data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
- data/lib/pubid/itu/identifiers/report.rb +39 -0
- data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
- data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
- data/lib/pubid/itu/identifiers/supplement.rb +119 -14
- data/lib/pubid/itu/identifiers.rb +10 -1
- data/lib/pubid/itu/model.rb +1 -1
- data/lib/pubid/itu/parser.rb +480 -26
- data/lib/pubid/itu/urn_generator.rb +36 -6
- data/lib/pubid/itu/urn_parser.rb +8 -0
- data/lib/pubid/itu.rb +11 -3
- data/lib/pubid/jcgm/builder.rb +23 -13
- data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
- data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
- data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
- data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
- data/lib/pubid/jcgm/identifiers.rb +2 -0
- data/lib/pubid/jcgm/parser.rb +66 -6
- data/lib/pubid/jcgm/renderer.rb +26 -12
- data/lib/pubid/jcgm/single_identifier.rb +74 -5
- data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
- data/lib/pubid/jcgm/urn_generator.rb +21 -13
- data/lib/pubid/jcgm/urn_parser.rb +15 -3
- data/lib/pubid/jis/identifier.rb +52 -0
- data/lib/pubid/nist/builder.rb +29 -9
- data/lib/pubid/nist/caster.rb +7 -45
- data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
- data/lib/pubid/nist/components/supplement.rb +5 -2
- data/lib/pubid/nist/configuration.rb +7 -1
- data/lib/pubid/nist/identifier.rb +1 -3
- data/lib/pubid/nist/identifiers/base.rb +121 -37
- data/lib/pubid/nist/identifiers/circular.rb +1 -1
- data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
- data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +1 -1
- data/lib/pubid/nist/identifiers/crpl_report.rb +1 -1
- data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
- data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
- data/lib/pubid/nist/identifiers/handbook.rb +1 -1
- data/lib/pubid/nist/identifiers/internal_report.rb +1 -1
- data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +1 -1
- data/lib/pubid/nist/identifiers/monograph.rb +1 -1
- data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
- data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
- data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
- data/lib/pubid/nist/identifiers/report.rb +1 -1
- data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
- data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
- data/lib/pubid/nist/identifiers.rb +0 -1
- data/lib/pubid/nist/parser.rb +29 -4
- data/lib/pubid/nist/preprocessor.rb +15 -0
- data/lib/pubid/nist/router.rb +3 -2
- data/lib/pubid/nist/series/ir.rb +0 -3
- data/lib/pubid/nist/supplement_identifier.rb +9 -9
- data/lib/pubid/nist.rb +13 -12
- data/lib/pubid/oasis/builder.rb +77 -0
- data/lib/pubid/oasis/identifier.rb +82 -0
- data/lib/pubid/oasis/identifiers/standard.rb +29 -0
- data/lib/pubid/oasis/identifiers.rb +9 -0
- data/lib/pubid/oasis/parser.rb +34 -0
- data/lib/pubid/oasis/renderer.rb +29 -0
- data/lib/pubid/oasis/urn_generator.rb +25 -0
- data/lib/pubid/oasis/urn_parser.rb +22 -0
- data/lib/pubid/oasis.rb +74 -0
- data/lib/pubid/ogc/builder.rb +33 -0
- data/lib/pubid/ogc/identifier.rb +77 -0
- data/lib/pubid/ogc/identifiers/document.rb +26 -0
- data/lib/pubid/ogc/identifiers.rb +10 -0
- data/lib/pubid/ogc/parser.rb +40 -0
- data/lib/pubid/ogc/renderer.rb +33 -0
- data/lib/pubid/ogc/urn_generator.rb +14 -0
- data/lib/pubid/ogc/urn_parser.rb +22 -0
- data/lib/pubid/ogc.rb +71 -0
- data/lib/pubid/oiml/builder.rb +31 -7
- data/lib/pubid/oiml/identifier.rb +9 -1
- data/lib/pubid/oiml/parser.rb +11 -12
- data/lib/pubid/oiml/renderer.rb +13 -13
- data/lib/pubid/oiml/single_identifier.rb +20 -0
- data/lib/pubid/oiml/supplement_identifier.rb +9 -9
- data/lib/pubid/oiml/urn_parser.rb +23 -6
- data/lib/pubid/oiml.rb +4 -0
- data/lib/pubid/omg/builder.rb +19 -0
- data/lib/pubid/omg/identifier.rb +44 -0
- data/lib/pubid/omg/identifiers/specification.rb +32 -0
- data/lib/pubid/omg/identifiers.rb +9 -0
- data/lib/pubid/omg/parser.rb +40 -0
- data/lib/pubid/omg/renderer.rb +19 -0
- data/lib/pubid/omg.rb +51 -0
- data/lib/pubid/parsers/mr_string.rb +101 -7
- data/lib/pubid/plateau/builder.rb +8 -4
- data/lib/pubid/plateau/identifier.rb +1 -3
- data/lib/pubid/plateau/identifiers/base.rb +1 -6
- data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
- data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
- data/lib/pubid/plateau/identifiers.rb +0 -1
- data/lib/pubid/plateau/parser.rb +15 -5
- data/lib/pubid/plateau/renderer.rb +1 -1
- data/lib/pubid/plateau/supplement_identifier.rb +11 -11
- data/lib/pubid/plateau.rb +4 -4
- data/lib/pubid/renderers/human_readable.rb +3 -1
- data/lib/pubid/renderers/mr_string.rb +46 -4
- data/lib/pubid/renderers/supplement_renderer.rb +1 -1
- data/lib/pubid/rendering/supplement.rb +4 -4
- data/lib/pubid/sae/builder.rb +1 -1
- data/lib/pubid/sae/identifier.rb +1 -3
- data/lib/pubid/sae/identifiers/base.rb +10 -7
- data/lib/pubid/sae/identifiers.rb +0 -1
- data/lib/pubid/sae.rb +3 -3
- data/lib/pubid/tgpp/builder.rb +41 -0
- data/lib/pubid/tgpp/identifier.rb +91 -0
- data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
- data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
- data/lib/pubid/tgpp/identifiers.rb +11 -0
- data/lib/pubid/tgpp/parser.rb +62 -0
- data/lib/pubid/tgpp/renderer.rb +36 -0
- data/lib/pubid/tgpp/urn_generator.rb +20 -0
- data/lib/pubid/tgpp/urn_parser.rb +28 -0
- data/lib/pubid/tgpp.rb +78 -0
- data/lib/pubid/type_resolver.rb +59 -0
- data/lib/pubid/un/builder.rb +42 -0
- data/lib/pubid/un/identifier.rb +37 -0
- data/lib/pubid/un/identifiers/document.rb +24 -0
- data/lib/pubid/un/identifiers.rb +9 -0
- data/lib/pubid/un/parser.rb +25 -0
- data/lib/pubid/un/renderer.rb +11 -0
- data/lib/pubid/un.rb +46 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/builder.rb +55 -0
- data/lib/pubid/w3c/identifier.rb +101 -0
- data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
- data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
- data/lib/pubid/w3c/identifiers/note.rb +30 -0
- data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/standard.rb +12 -0
- data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
- data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
- data/lib/pubid/w3c/identifiers.rb +25 -0
- data/lib/pubid/w3c/parser.rb +43 -0
- data/lib/pubid/w3c/renderer.rb +35 -0
- data/lib/pubid/w3c/urn_generator.rb +18 -0
- data/lib/pubid/w3c/urn_parser.rb +36 -0
- data/lib/pubid/w3c.rb +67 -0
- data/lib/pubid/xsf/builder.rb +17 -0
- data/lib/pubid/xsf/identifier.rb +62 -0
- data/lib/pubid/xsf/identifiers/xep.rb +31 -0
- data/lib/pubid/xsf/identifiers.rb +9 -0
- data/lib/pubid/xsf/parser.rb +25 -0
- data/lib/pubid/xsf/renderer.rb +23 -0
- data/lib/pubid/xsf/urn_generator.rb +13 -0
- data/lib/pubid/xsf/urn_parser.rb +18 -0
- data/lib/pubid/xsf.rb +76 -0
- data/lib/pubid.rb +25 -1
- metadata +205 -4
- data/lib/pubid/cie/components/code.rb +0 -80
- data/lib/pubid/iala/identifiers/base.rb +0 -14
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parslet"
|
|
4
|
+
|
|
5
|
+
module Pubid
|
|
6
|
+
module Ogc
|
|
7
|
+
# Parslet grammar for OGC identifiers.
|
|
8
|
+
#
|
|
9
|
+
# Recognizes `<yy>-<nnn>` optionally followed by a revision suffix that
|
|
10
|
+
# begins with a letter (r/c/a/R…) and may carry a trailing letter
|
|
11
|
+
# (e.g. "r3a"). An optional leading "OGC" publisher token is accepted for
|
|
12
|
+
# leniency, though the canonical printed form omits it.
|
|
13
|
+
#
|
|
14
|
+
# Examples: "25-023", "24-032r1", "01-009a", "04-095c1", "OGC 24-032r1".
|
|
15
|
+
class Parser < Parslet::Parser
|
|
16
|
+
rule(:space) { match["\\s"].repeat(1) }
|
|
17
|
+
rule(:digits) { match["0-9"].repeat(1) }
|
|
18
|
+
|
|
19
|
+
# Optional leading publisher token, e.g. "OGC " — consumed, not captured.
|
|
20
|
+
rule(:publisher) { (str("OGC") >> space).maybe }
|
|
21
|
+
|
|
22
|
+
# Revision suffix: a run of letters/digits that starts after the numeric
|
|
23
|
+
# part (which greedily consumes all digits, so the suffix begins with a
|
|
24
|
+
# separator letter). Kept as a single token for the builder to normalize.
|
|
25
|
+
rule(:revision) { match["A-Za-z0-9"].repeat(1).as(:revision) }
|
|
26
|
+
|
|
27
|
+
rule(:identifier) do
|
|
28
|
+
publisher >>
|
|
29
|
+
digits.as(:year) >> str("-") >> digits.as(:number) >>
|
|
30
|
+
revision.maybe >> space.maybe
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
root(:identifier)
|
|
34
|
+
|
|
35
|
+
def self.parse(input)
|
|
36
|
+
new.parse(input)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ogc
|
|
5
|
+
# Human-readable renderer for OGC identifiers.
|
|
6
|
+
#
|
|
7
|
+
# Produces the canonical printed form, e.g.:
|
|
8
|
+
# "24-032r1"
|
|
9
|
+
# "01-009a"
|
|
10
|
+
# "OGC 24-032r1" (only when with_publisher: true)
|
|
11
|
+
#
|
|
12
|
+
# Registered as the `:human` format in the OGC format registry and invoked
|
|
13
|
+
# via `render(format: :human)`.
|
|
14
|
+
class Renderer < ::Pubid::Renderers::Base
|
|
15
|
+
PUBLISHER = "OGC"
|
|
16
|
+
|
|
17
|
+
def render(**_opts)
|
|
18
|
+
id = @id
|
|
19
|
+
result = +""
|
|
20
|
+
result << "#{PUBLISHER} " if with_publisher?(id)
|
|
21
|
+
result << "#{id.year}-#{id.number}"
|
|
22
|
+
result << id.revision.to_s if id.revision
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def with_publisher?(id)
|
|
29
|
+
id.respond_to?(:with_publisher) && id.with_publisher == true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ogc
|
|
5
|
+
# Emits `urn:ogc:<year>:<number>[:<revision>]`, e.g. `urn:ogc:24:032:r1`.
|
|
6
|
+
class UrnGenerator < Pubid::UrnGenerator::Base
|
|
7
|
+
def generate
|
|
8
|
+
parts = ["urn", "ogc", identifier.year.to_s, identifier.number.to_s]
|
|
9
|
+
parts << identifier.revision.to_s if identifier.revision
|
|
10
|
+
parts.join(":")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ogc
|
|
5
|
+
# Parses OGC URNs back into identifiers.
|
|
6
|
+
#
|
|
7
|
+
# UrnGenerator emits: `urn:ogc:<year>:<number>[:<revision>]`.
|
|
8
|
+
#
|
|
9
|
+
# Examples:
|
|
10
|
+
# - urn:ogc:25:023 → 25-023
|
|
11
|
+
# - urn:ogc:24:032:r1 → 24-032r1
|
|
12
|
+
class UrnParser < Pubid::UrnParser::Base
|
|
13
|
+
def parse_urn(urn)
|
|
14
|
+
body = strip_namespace(urn)
|
|
15
|
+
year, number, revision = split_parts(body)
|
|
16
|
+
text = "#{year}-#{number}"
|
|
17
|
+
text += revision.to_s if revision
|
|
18
|
+
flavor_parse(text)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/pubid/ogc.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ogc
|
|
5
|
+
extend Pubid::PrefixesSupport
|
|
6
|
+
|
|
7
|
+
# OGC identifiers are digit-leading (`25-023`) and carry no publisher token
|
|
8
|
+
# in the printed form. Per the PREFIXES inclusion policy, bare numeric
|
|
9
|
+
# patterns are NOT listed (they would make cross-flavor routing ambiguous).
|
|
10
|
+
# Instead the sole entry is the publisher token "OGC", which relaton uses to
|
|
11
|
+
# route a reference to this flavor even though it is not literally present
|
|
12
|
+
# in the id string.
|
|
13
|
+
PREFIXES = ["OGC"].freeze
|
|
14
|
+
|
|
15
|
+
autoload :Builder, "#{__dir__}/ogc/builder"
|
|
16
|
+
autoload :Identifier, "#{__dir__}/ogc/identifier"
|
|
17
|
+
autoload :Identifiers, "#{__dir__}/ogc/identifiers"
|
|
18
|
+
autoload :Parser, "#{__dir__}/ogc/parser"
|
|
19
|
+
autoload :Renderer, "#{__dir__}/ogc/renderer"
|
|
20
|
+
autoload :UrnGenerator, "#{__dir__}/ogc/urn_generator"
|
|
21
|
+
autoload :UrnParser, "#{__dir__}/ogc/urn_parser"
|
|
22
|
+
|
|
23
|
+
# Parse an OGC identifier string
|
|
24
|
+
def self.parse(identifier)
|
|
25
|
+
Identifier.parse(identifier)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Per-flavor format registry: inherits global formats, overrides :human
|
|
29
|
+
Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
|
|
30
|
+
Identifier.format_registry.register(:human, renderer: Ogc::Renderer)
|
|
31
|
+
|
|
32
|
+
# Auto-discover all identifier types from the Identifiers namespace
|
|
33
|
+
# @return [Array<Class>] identifier classes that define a self.type Hash
|
|
34
|
+
def self.identifier_types
|
|
35
|
+
@identifier_types ||= Identifiers.constants
|
|
36
|
+
.filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
|
|
37
|
+
.select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
|
|
38
|
+
.select { |c| c.type.is_a?(Hash) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Build typed stage index from identifier types
|
|
42
|
+
# @return [Array<Pubid::Components::TypedStage>] all typed stages
|
|
43
|
+
def self.all_typed_stages
|
|
44
|
+
@all_typed_stages ||= identifier_types.flat_map do |klass|
|
|
45
|
+
if klass.const_defined?(:TYPED_STAGES)
|
|
46
|
+
klass.const_get(:TYPED_STAGES)
|
|
47
|
+
else
|
|
48
|
+
[]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Lookup: type code -> identifier class
|
|
54
|
+
# @param code [String, Symbol] the type key to find
|
|
55
|
+
# @return [Class, nil] the matching identifier class
|
|
56
|
+
def self.locate_type(code)
|
|
57
|
+
identifier_types.find { |t| t.type[:key].to_s == code.to_s }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Lookup: abbreviation -> typed stage
|
|
61
|
+
# @param abbr [String, Symbol] the abbreviation to find
|
|
62
|
+
# @return [Pubid::Components::TypedStage, nil] the matching typed stage
|
|
63
|
+
def self.locate_stage(abbr)
|
|
64
|
+
abbr_str = abbr.to_s.upcase
|
|
65
|
+
all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Register OGC flavor with the registry
|
|
71
|
+
Pubid::Registry.register(:ogc, Pubid::Ogc)
|
data/lib/pubid/oiml/builder.rb
CHANGED
|
@@ -21,8 +21,8 @@ module Pubid
|
|
|
21
21
|
return build_short_amendment(parsed_hash)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
# Check for supplements first (have
|
|
25
|
-
if parsed_hash[:
|
|
24
|
+
# Check for supplements first (have base)
|
|
25
|
+
if parsed_hash[:base]
|
|
26
26
|
return build_supplement(parsed_hash)
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -53,11 +53,11 @@ module Pubid
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
# Build the base document
|
|
56
|
-
|
|
56
|
+
base = build_base_document(base_hash)
|
|
57
57
|
|
|
58
58
|
# Create amendment
|
|
59
59
|
amendment = Identifiers::Amendment.new
|
|
60
|
-
amendment.
|
|
60
|
+
amendment.base = base
|
|
61
61
|
|
|
62
62
|
# Extract year from edition_format if present, otherwise from year directly
|
|
63
63
|
year_value = if parsed_hash[:edition_format].is_a?(Hash)
|
|
@@ -97,8 +97,8 @@ module Pubid
|
|
|
97
97
|
supplement.joined = true if plus_marker
|
|
98
98
|
|
|
99
99
|
# Recursively parse base identifier
|
|
100
|
-
if parsed_hash[:
|
|
101
|
-
supplement.
|
|
100
|
+
if parsed_hash[:base]
|
|
101
|
+
supplement.base = build(parsed_hash[:base])
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
# Extract year from edition_format if present, otherwise from year directly
|
|
@@ -116,7 +116,7 @@ module Pubid
|
|
|
116
116
|
# Annex with no year of its own but a dated base ("R 60:2017 Annexes"):
|
|
117
117
|
# the year belongs to the base and must render glued to it.
|
|
118
118
|
if supplement.is_a?(Identifiers::Annex) && !year_value &&
|
|
119
|
-
supplement.
|
|
119
|
+
supplement.base&.date
|
|
120
120
|
supplement.year_on_base = true
|
|
121
121
|
end
|
|
122
122
|
|
|
@@ -214,6 +214,11 @@ module Pubid
|
|
|
214
214
|
# Structured: :issue and :sequence captured directly as zero-padded
|
|
215
215
|
# strings. Citation: :volume_roman, :issue_arabic, :article_id —
|
|
216
216
|
# decode the 8-digit article_id to recover year+issue+sequence.
|
|
217
|
+
#
|
|
218
|
+
# For the citation form, the parsed roman volume is cross-checked
|
|
219
|
+
# against the year decoded from the article_id; a mismatch warns but
|
|
220
|
+
# does not raise (the article_id is the source of truth — the roman
|
|
221
|
+
# volume is redundant display).
|
|
217
222
|
def apply_bulletin_locator(identifier, parsed_hash)
|
|
218
223
|
if parsed_hash[:article_id]
|
|
219
224
|
article_id = parsed_hash[:article_id].to_s
|
|
@@ -221,6 +226,7 @@ module Pubid
|
|
|
221
226
|
identifier.date.year = article_id[0, 4]
|
|
222
227
|
identifier.issue = article_id[4, 2]
|
|
223
228
|
identifier.sequence = article_id[6, 2]
|
|
229
|
+
warn_on_volume_mismatch(identifier, parsed_hash[:volume_roman])
|
|
224
230
|
return
|
|
225
231
|
end
|
|
226
232
|
|
|
@@ -228,6 +234,24 @@ module Pubid
|
|
|
228
234
|
identifier.sequence = parsed_hash[:sequence].to_s if parsed_hash[:sequence]
|
|
229
235
|
end
|
|
230
236
|
|
|
237
|
+
# Citation form carries the volume in two places: spelled out as a
|
|
238
|
+
# roman numeral ("LXVII") and encoded in the 8-digit article_id
|
|
239
|
+
# (year+issue+sequence, where year - 1959 = volume). They should
|
|
240
|
+
# agree; if they don't, the input was malformed. Warn loudly so the
|
|
241
|
+
# user sees the discrepancy, but continue using the article_id
|
|
242
|
+
# (deterministic) rather than the roman (possibly mistyped).
|
|
243
|
+
def warn_on_volume_mismatch(identifier, parsed_volume_roman)
|
|
244
|
+
return unless parsed_volume_roman && identifier.date&.year
|
|
245
|
+
|
|
246
|
+
declared = parsed_volume_roman.to_s
|
|
247
|
+
computed = Identifiers::Bulletin.to_roman(identifier.date.year.to_i -
|
|
248
|
+
Identifiers::Bulletin::BASE_YEAR_OFFSET)
|
|
249
|
+
return if declared == computed
|
|
250
|
+
|
|
251
|
+
warn "OIML Bulletin citation volume mismatch: parsed '#{declared}' " \
|
|
252
|
+
"but article_id year #{identifier.date.year} implies '#{computed}'"
|
|
253
|
+
end
|
|
254
|
+
|
|
231
255
|
def extract_language(lang_data)
|
|
232
256
|
# Handle both direct string and nested hash from parser
|
|
233
257
|
case lang_data
|
|
@@ -37,7 +37,7 @@ module Pubid
|
|
|
37
37
|
# lutaml's polymorphic_map only validates `_type` on deserialization; it
|
|
38
38
|
# does not re-instantiate the concrete subclass. Route by `_type` so
|
|
39
39
|
# `Pubid::Oiml::Identifier.from_hash(h)` returns the right class (and its
|
|
40
|
-
# nested
|
|
40
|
+
# nested base), mirroring Pubid::Iso::Identifier.from_hash.
|
|
41
41
|
def self.from_hash(data, options = {})
|
|
42
42
|
type = data["_type"] || data[:_type]
|
|
43
43
|
klass_name = OIML_TYPE_MAP[type]
|
|
@@ -48,6 +48,14 @@ module Pubid
|
|
|
48
48
|
super
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
# Uniform class-level parse entry, mirroring every other flavor's
|
|
52
|
+
# `Pubid::<Flavor>::Identifier.parse`. OIML's real logic lives in the
|
|
53
|
+
# module method, so delegate to it (same pattern as jcgm/nist/plateau).
|
|
54
|
+
# The `Pubid::MAX_INPUT_LENGTH` ReDoS guard lives in `Pubid::Oiml.parse`.
|
|
55
|
+
def self.parse(identifier)
|
|
56
|
+
Pubid::Oiml.parse(identifier)
|
|
57
|
+
end
|
|
58
|
+
|
|
51
59
|
def to_urn
|
|
52
60
|
UrnGenerator.new(self).generate
|
|
53
61
|
end
|
data/lib/pubid/oiml/parser.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Pubid
|
|
|
20
20
|
rule(:identifier) do
|
|
21
21
|
amendment_identifier | amendment_short | annex_letter_identifier |
|
|
22
22
|
annex_identifier | plus_supplement_identifier |
|
|
23
|
-
trailing_supplement_identifier | bulletin_identifier |
|
|
23
|
+
trailing_supplement_identifier | bulletin_identifier | base
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Publisher - always "OIML"
|
|
@@ -44,10 +44,9 @@ module Pubid
|
|
|
44
44
|
rule(:two_digits) { match('\d').repeat(2, 2) }
|
|
45
45
|
|
|
46
46
|
# Roman numeral token composed of I,V,X,L,C,D,M (uppercase, matching
|
|
47
|
-
# OIML's print convention).
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
rule(:roman_numeral) { match("[IVXLCDM]").repeat(1) }
|
|
47
|
+
# OIML's print convention). Captured so the builder can cross-check
|
|
48
|
+
# the declared volume against the year implied by the article_id.
|
|
49
|
+
rule(:roman_numeral) { match("[IVXLCDM]").repeat(1).as(:volume_roman) }
|
|
51
50
|
|
|
52
51
|
# Bulletin locator — citation form. The format OIML prints on the
|
|
53
52
|
# article page is: "LXVII(2) 20260211" where LXVII is the volume in
|
|
@@ -62,7 +61,7 @@ module Pubid
|
|
|
62
61
|
# Bulletin identifier — no code; the locator (when present) is the
|
|
63
62
|
# (year, issue, sequence) tuple drawn from either the structured
|
|
64
63
|
# YYYY-II-SS form or the citation VOLUME(ISSUE) ARTID form. Both
|
|
65
|
-
# decode to the same record. Tried before
|
|
64
|
+
# decode to the same record. Tried before base because
|
|
66
65
|
# "Bulletin" is a word that the single-letter doc_type rule cannot
|
|
67
66
|
# match.
|
|
68
67
|
rule(:bulletin_identifier) do
|
|
@@ -188,7 +187,7 @@ module Pubid
|
|
|
188
187
|
rule(:amendment_identifier) do
|
|
189
188
|
str("Amendment") >> space >> lparen >> year_digits.as(:year) >> rparen >>
|
|
190
189
|
space >> str("to") >> space >>
|
|
191
|
-
base_without_language.as(:
|
|
190
|
+
base_without_language.as(:base) >>
|
|
192
191
|
language_portion.maybe.as(:language)
|
|
193
192
|
end
|
|
194
193
|
|
|
@@ -210,7 +209,7 @@ module Pubid
|
|
|
210
209
|
# amendment_short is tried first; it only matches when a year follows the
|
|
211
210
|
# word, so the no-year trailing form falls through to here.
|
|
212
211
|
rule(:trailing_supplement_identifier) do
|
|
213
|
-
base_without_language.as(:
|
|
212
|
+
base_without_language.as(:base) >>
|
|
214
213
|
space >> (str("Amendment") | str("Errata")).as(:trailing_marker) >>
|
|
215
214
|
language_portion.maybe.as(:language)
|
|
216
215
|
end
|
|
@@ -220,7 +219,7 @@ module Pubid
|
|
|
220
219
|
# and errata to dated bases (e.g. "OIML B 10:2011+Amendment:2012").
|
|
221
220
|
# Annexes already encode the year-on-base intent via their own model.
|
|
222
221
|
rule(:plus_supplement_identifier) do
|
|
223
|
-
base_without_language.as(:
|
|
222
|
+
base_without_language.as(:base) >>
|
|
224
223
|
str("+") >>
|
|
225
224
|
(str("Amendment") | str("Errata")).as(:plus_marker) >>
|
|
226
225
|
(colon >> year_digits.as(:year)).maybe >>
|
|
@@ -230,7 +229,7 @@ module Pubid
|
|
|
230
229
|
# Annex identifier - "BASE Annexes Edition YYYY" / "BASE Annexes:YYYY" /
|
|
231
230
|
# "BASE:YYYY Annexes" (year on the base, no annex year).
|
|
232
231
|
rule(:annex_identifier) do
|
|
233
|
-
base_without_language.as(:
|
|
232
|
+
base_without_language.as(:base) >>
|
|
234
233
|
space >> str("Annexes").as(:annex_marker) >>
|
|
235
234
|
(
|
|
236
235
|
(space >> edition_text >> space >> year_digits.as(:year)).as(:edition_format) |
|
|
@@ -246,7 +245,7 @@ module Pubid
|
|
|
246
245
|
|
|
247
246
|
# Annex with letter - "BASE Annex A Edition YYYY" / "BASE:YYYY Annex B-C"
|
|
248
247
|
rule(:annex_letter_identifier) do
|
|
249
|
-
base_without_language.as(:
|
|
248
|
+
base_without_language.as(:base) >>
|
|
250
249
|
space >> str("Annex") >> space >> annex_letter_value >>
|
|
251
250
|
((space >> edition_text >> space >> year_digits.as(:year)) | (colon >> year_digits.as(:year))).maybe >>
|
|
252
251
|
language_portion.maybe.as(:language)
|
|
@@ -262,7 +261,7 @@ module Pubid
|
|
|
262
261
|
end
|
|
263
262
|
|
|
264
263
|
# Base identifier for recursion and standalone parsing
|
|
265
|
-
rule(:
|
|
264
|
+
rule(:base) do
|
|
266
265
|
publisher >>
|
|
267
266
|
doc_type >>
|
|
268
267
|
full_number >>
|
data/lib/pubid/oiml/renderer.rb
CHANGED
|
@@ -138,7 +138,7 @@ module Pubid
|
|
|
138
138
|
# Plus-joined: "BASE+Amendment:YEAR" / "BASE+Errata:YEAR" with both
|
|
139
139
|
# the base and the supplement carrying their own year.
|
|
140
140
|
if id.joined
|
|
141
|
-
base_str = strip_language(id.
|
|
141
|
+
base_str = strip_language(id.base.to_s)
|
|
142
142
|
result = "#{base_str}+#{id.supplement_type}"
|
|
143
143
|
result += ":#{id.year}" if id.year
|
|
144
144
|
result += " (#{id.language})" if id.language
|
|
@@ -149,7 +149,7 @@ module Pubid
|
|
|
149
149
|
# publication year kept on the base identifier. The word comes from the
|
|
150
150
|
# concrete supplement class.
|
|
151
151
|
if id.trailing
|
|
152
|
-
base_str = strip_language(id.
|
|
152
|
+
base_str = strip_language(id.base.to_s)
|
|
153
153
|
result = "#{base_str} #{id.supplement_type}"
|
|
154
154
|
result += " (#{id.language})" if id.language
|
|
155
155
|
return result
|
|
@@ -157,16 +157,16 @@ module Pubid
|
|
|
157
157
|
|
|
158
158
|
base_format = if format && format != :short
|
|
159
159
|
format
|
|
160
|
-
elsif id.
|
|
160
|
+
elsif id.base.class.attributes.key?(:parsed_format) && id.base.parsed_format == "long"
|
|
161
161
|
:long
|
|
162
162
|
else
|
|
163
163
|
:short
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
-
base_str = if id.
|
|
167
|
-
id.
|
|
166
|
+
base_str = if id.base.is_a?(SingleIdentifier)
|
|
167
|
+
id.base.to_s(format: base_format)
|
|
168
168
|
else
|
|
169
|
-
id.
|
|
169
|
+
id.base.to_s
|
|
170
170
|
end
|
|
171
171
|
base_str = strip_language(base_str)
|
|
172
172
|
|
|
@@ -182,14 +182,14 @@ module Pubid
|
|
|
182
182
|
# "BASE:YYYY Annex(es)" — the year is glued to the base, the marker
|
|
183
183
|
# carries none. Keep the base date instead of stripping it.
|
|
184
184
|
if id.year_on_base
|
|
185
|
-
base_str = strip_language(id.
|
|
185
|
+
base_str = strip_language(id.base.to_s)
|
|
186
186
|
marker = id.letter ? "Annex #{id.letter}" : "Annexes"
|
|
187
187
|
result = "#{base_str} #{marker}"
|
|
188
188
|
result += " (#{id.language})" if id.language
|
|
189
189
|
return result
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
-
base_format = if id.
|
|
192
|
+
base_format = if id.base.class.attributes.key?(:parsed_format) && id.base.parsed_format == "long"
|
|
193
193
|
:long
|
|
194
194
|
else
|
|
195
195
|
:short
|
|
@@ -203,10 +203,10 @@ module Pubid
|
|
|
203
203
|
:short
|
|
204
204
|
end
|
|
205
205
|
|
|
206
|
-
base_str = if id.
|
|
207
|
-
id.
|
|
206
|
+
base_str = if id.base.is_a?(SingleIdentifier)
|
|
207
|
+
id.base.to_s(format: base_format)
|
|
208
208
|
else
|
|
209
|
-
id.
|
|
209
|
+
id.base.to_s
|
|
210
210
|
end
|
|
211
211
|
result = base_str.sub(/:.*/, "").sub(/\s+Edition\s+\d{4}/, "").sub(
|
|
212
212
|
/\(.*\)/, ""
|
|
@@ -219,8 +219,8 @@ module Pubid
|
|
|
219
219
|
result += " Annexes"
|
|
220
220
|
if id.year
|
|
221
221
|
result += annex_format == :long ? " Edition #{id.year}" : ":#{id.year}"
|
|
222
|
-
elsif id.
|
|
223
|
-
result += annex_format == :long ? " Edition #{id.
|
|
222
|
+
elsif id.base.date
|
|
223
|
+
result += annex_format == :long ? " Edition #{id.base.date.render(context: @context)}" : ":#{id.base.date.render(context: @context)}"
|
|
224
224
|
end
|
|
225
225
|
end
|
|
226
226
|
|
|
@@ -103,6 +103,26 @@ module Pubid
|
|
|
103
103
|
raise NotImplementedError, "Subclasses must implement type_string"
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
+
# OIML keeps identity in `code` (Components::Code) and `type_string`
|
|
107
|
+
# (e.g. "R", "V", "D"), not in the inherited `number`/`typed_stage` —
|
|
108
|
+
# the generic MrString renderer would otherwise drop both and produce
|
|
109
|
+
# `OIML.<year>`. Losslessness for issue #142 requires the type letter
|
|
110
|
+
# and document number to appear in MR.
|
|
111
|
+
def mr_number_with_part
|
|
112
|
+
segments = []
|
|
113
|
+
segments << code&.number&.to_s if code&.number
|
|
114
|
+
segments << code&.part&.to_s if code&.part
|
|
115
|
+
segments << code&.subpart&.to_s if code&.subpart
|
|
116
|
+
segments << code&.suffix&.to_s if code&.suffix
|
|
117
|
+
return nil if segments.empty?
|
|
118
|
+
|
|
119
|
+
segments.join("-")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def mr_type
|
|
123
|
+
type_string&.downcase
|
|
124
|
+
end
|
|
125
|
+
|
|
106
126
|
# Subclasses override this
|
|
107
127
|
end
|
|
108
128
|
end
|
|
@@ -5,7 +5,7 @@ module Pubid
|
|
|
5
5
|
class SupplementIdentifier < Identifier
|
|
6
6
|
# Base class for OIML supplements (amendments, annexes)
|
|
7
7
|
# These wrap a base identifier like ISO amendments
|
|
8
|
-
attribute :
|
|
8
|
+
attribute :base, Oiml::Identifier, polymorphic: true
|
|
9
9
|
attribute :year, :string
|
|
10
10
|
attribute :language, :string
|
|
11
11
|
# True for the trailing-word shorthand ("OIML R 138:2009 Amendment"),
|
|
@@ -21,28 +21,28 @@ module Pubid
|
|
|
21
21
|
} # Track supplement's parsed format
|
|
22
22
|
|
|
23
23
|
# Serialization delta on top of Oiml::Identifier's shared block. The
|
|
24
|
-
# nested
|
|
24
|
+
# nested base is (de)serialized recursively through the
|
|
25
25
|
# polymorphic router so its own `_type` selects the right subclass.
|
|
26
26
|
key_value do
|
|
27
|
-
map "
|
|
28
|
-
with: { to: :
|
|
27
|
+
map "base",
|
|
28
|
+
with: { to: :base_to_kv, from: :base_from_kv }
|
|
29
29
|
map "year", to: :year
|
|
30
30
|
map "trailing", to: :trailing
|
|
31
31
|
map "joined", to: :joined
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def
|
|
35
|
-
base = model.
|
|
34
|
+
def base_to_kv(model, doc)
|
|
35
|
+
base = model.base
|
|
36
36
|
return unless base
|
|
37
37
|
|
|
38
38
|
doc.add_child(
|
|
39
|
-
Lutaml::KeyValue::DataModel::Element.new("
|
|
39
|
+
Lutaml::KeyValue::DataModel::Element.new("base",
|
|
40
40
|
base.to_hash),
|
|
41
41
|
)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
model.
|
|
44
|
+
def base_from_kv(model, value)
|
|
45
|
+
model.base = ::Pubid::Oiml::Identifier.from_hash(value) if value
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
attr_reader :requested_format
|
|
@@ -4,18 +4,35 @@ module Pubid
|
|
|
4
4
|
module Oiml
|
|
5
5
|
# Parses OIML URNs back into identifiers.
|
|
6
6
|
#
|
|
7
|
-
# UrnGenerator emits: `urn:oiml:{type}:{
|
|
8
|
-
#
|
|
7
|
+
# UrnGenerator emits: `urn:oiml:{type}:{locator}` where type is the
|
|
8
|
+
# lowercase document class — single letter for typed documents
|
|
9
|
+
# (r, d, b, g, …) or the word "bulletin" for Bulletin issues. The
|
|
10
|
+
# locator is the number-part-subpart for typed documents and the
|
|
11
|
+
# YYYY-II-SS tuple for Bulletins.
|
|
9
12
|
#
|
|
10
13
|
# Examples:
|
|
11
|
-
# - urn:oiml:r:111-1
|
|
12
|
-
# - urn:oiml:d:1
|
|
14
|
+
# - urn:oiml:r:111-1 → OIML R 111-1
|
|
15
|
+
# - urn:oiml:d:1 → OIML D 1
|
|
16
|
+
# - urn:oiml:bulletin:2026-02-11 → OIML Bulletin 2026-02-11
|
|
13
17
|
class UrnParser < Pubid::UrnParser::Base
|
|
14
18
|
def parse_urn(urn)
|
|
15
19
|
body = strip_namespace(urn)
|
|
16
20
|
parts = split_parts(body)
|
|
17
|
-
type_token
|
|
18
|
-
|
|
21
|
+
type_token = parts.fetch(0)
|
|
22
|
+
number = parts[1]
|
|
23
|
+
|
|
24
|
+
text = "OIML #{display_type(type_token)}"
|
|
25
|
+
text += " #{number}" if number
|
|
26
|
+
flavor_parse(text)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# URN type tokens are lowercase. Typed documents use a single letter
|
|
32
|
+
# that maps cleanly via upcase; Bulletin is the multi-letter word
|
|
33
|
+
# that the human parser expects capitalized.
|
|
34
|
+
def display_type(token)
|
|
35
|
+
token.downcase == "bulletin" ? "Bulletin" : token.upcase
|
|
19
36
|
end
|
|
20
37
|
end
|
|
21
38
|
end
|
data/lib/pubid/oiml.rb
CHANGED
|
@@ -19,6 +19,10 @@ module Pubid
|
|
|
19
19
|
autoload :UrnParser, "#{__dir__}/oiml/urn_parser"
|
|
20
20
|
|
|
21
21
|
def self.parse(identifier)
|
|
22
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
23
|
+
raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
24
|
+
end
|
|
25
|
+
|
|
22
26
|
parser = Parser.new
|
|
23
27
|
builder = Builder.new
|
|
24
28
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Omg
|
|
5
|
+
# Builds a Pubid::Omg::Identifier from a parse tree.
|
|
6
|
+
class Builder
|
|
7
|
+
def self.build(parsed_data)
|
|
8
|
+
new.build(parsed_data)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def build(data)
|
|
12
|
+
Identifiers::Specification.new(
|
|
13
|
+
acronym: data[:acronym].to_s,
|
|
14
|
+
version: data[:version]&.to_s,
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Omg
|
|
5
|
+
# Base class for every OMG identifier AND the flavor's parse/create
|
|
6
|
+
# entry point.
|
|
7
|
+
class Identifier < ::Pubid::Identifier
|
|
8
|
+
# The spec family acronym, e.g. "AMI4CCM", "UML", "CORBA".
|
|
9
|
+
attribute :acronym, :string
|
|
10
|
+
|
|
11
|
+
# Free-form version string. Stored verbatim because OMG versioning is
|
|
12
|
+
# loose ("1.0", "2.5.1", "5 beta 3", "1.1"). Use Version#to_s for
|
|
13
|
+
# rendering.
|
|
14
|
+
attribute :version, :string
|
|
15
|
+
|
|
16
|
+
OMG_TYPE_MAP = {
|
|
17
|
+
"pubid:omg:specification" => "Pubid::Omg::Identifiers::Specification",
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
key_value do
|
|
21
|
+
map "_type", to: :_type, polymorphic_map: OMG_TYPE_MAP
|
|
22
|
+
map "acronym", to: :acronym
|
|
23
|
+
map "version", to: :version
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
PUBLISHER = "OMG"
|
|
27
|
+
|
|
28
|
+
def to_s(**opts)
|
|
29
|
+
render(format: :human, **opts)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.parse(identifier)
|
|
33
|
+
if identifier.length > Pubid::MAX_INPUT_LENGTH
|
|
34
|
+
raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
parsed = Parser.parse(identifier)
|
|
38
|
+
Builder.build(parsed)
|
|
39
|
+
rescue Parslet::ParseFailed => e
|
|
40
|
+
raise "Failed to parse OMG identifier '#{identifier}': #{e.message}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|