pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +33 -11
- data/conformance/pending.yaml +4 -0
- data/lib/pubid/adobe/identifier.rb +1 -3
- data/lib/pubid/adobe/parser.rb +10 -2
- data/lib/pubid/adobe.rb +1 -0
- data/lib/pubid/amca/builder.rb +2 -2
- data/lib/pubid/amca/identifiers/base.rb +49 -27
- data/lib/pubid/amca/identifiers/interpretation.rb +17 -9
- data/lib/pubid/amca/identifiers/publication.rb +13 -9
- data/lib/pubid/amca/identifiers/standard.rb +2 -0
- data/lib/pubid/amca/parser.rb +1 -1
- data/lib/pubid/amca/renderer.rb +4 -4
- data/lib/pubid/amca/urn_generator.rb +2 -2
- data/lib/pubid/amca.rb +2 -1
- data/lib/pubid/ansi/builder.rb +2 -2
- data/lib/pubid/ansi/identifier.rb +18 -0
- data/lib/pubid/ansi/parser.rb +1 -1
- data/lib/pubid/ansi/renderer.rb +2 -2
- data/lib/pubid/ansi.rb +5 -5
- data/lib/pubid/api/builder.rb +16 -2
- data/lib/pubid/api/identifier.rb +25 -4
- data/lib/pubid/api/identifiers/mpms.rb +10 -8
- data/lib/pubid/api/parser.rb +1 -1
- data/lib/pubid/api/renderer.rb +16 -7
- data/lib/pubid/api/single_identifier.rb +5 -12
- data/lib/pubid/api.rb +1 -0
- data/lib/pubid/ashrae/builder.rb +31 -10
- data/lib/pubid/ashrae/identifiers/addenda_package.rb +6 -0
- data/lib/pubid/ashrae/identifiers/addendum.rb +8 -0
- data/lib/pubid/ashrae/identifiers/base.rb +81 -5
- data/lib/pubid/ashrae/identifiers/combined_addenda.rb +7 -0
- data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
- data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
- data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
- data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
- data/lib/pubid/ashrae/parser.rb +23 -8
- data/lib/pubid/ashrae/renderer.rb +6 -6
- data/lib/pubid/ashrae/supplement_identifier.rb +17 -2
- data/lib/pubid/ashrae/urn_generator.rb +8 -2
- data/lib/pubid/ashrae.rb +7 -1
- data/lib/pubid/asme/builder.rb +11 -2
- data/lib/pubid/asme/identifier.rb +9 -0
- data/lib/pubid/asme/identifiers/standard.rb +86 -2
- data/lib/pubid/asme/parser.rb +1 -1
- data/lib/pubid/asme/renderer.rb +3 -3
- data/lib/pubid/asme/single_identifier.rb +8 -1
- data/lib/pubid/asme/urn_generator.rb +2 -2
- data/lib/pubid/asme.rb +1 -0
- data/lib/pubid/astm/builder.rb +10 -3
- data/lib/pubid/astm/identifier.rb +9 -0
- data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
- data/lib/pubid/astm/identifiers/code_number.rb +81 -0
- data/lib/pubid/astm/identifiers/data_series.rb +2 -0
- data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
- data/lib/pubid/astm/identifiers/manual.rb +10 -0
- data/lib/pubid/astm/identifiers/monograph.rb +2 -0
- data/lib/pubid/astm/identifiers/research_report.rb +10 -0
- data/lib/pubid/astm/identifiers/standard.rb +10 -0
- data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
- data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
- data/lib/pubid/astm/identifiers.rb +1 -0
- data/lib/pubid/astm/parser.rb +1 -1
- data/lib/pubid/astm/renderer.rb +1 -1
- data/lib/pubid/astm/single_identifier.rb +31 -1
- data/lib/pubid/astm/urn_generator.rb +7 -5
- data/lib/pubid/astm.rb +1 -0
- data/lib/pubid/bipm/builder.rb +66 -10
- data/lib/pubid/bipm/identifier.rb +134 -9
- data/lib/pubid/bipm/identifiers/committee_document.rb +12 -0
- data/lib/pubid/bipm/identifiers/guide.rb +11 -0
- data/lib/pubid/bipm/identifiers/meeting.rb +12 -0
- data/lib/pubid/bipm/identifiers/mep.rb +12 -0
- data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
- data/lib/pubid/bipm/identifiers/si_brochure.rb +13 -0
- data/lib/pubid/bipm/parser.rb +65 -12
- data/lib/pubid/bipm/renderer.rb +8 -0
- data/lib/pubid/bipm/urn_parser.rb +11 -3
- data/lib/pubid/bipm.rb +7 -1
- data/lib/pubid/bsi/builder.rb +48 -38
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -1
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
- data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
- data/lib/pubid/bsi/identifiers/handbook.rb +0 -2
- data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
- data/lib/pubid/bsi/identifiers/set.rb +11 -0
- data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
- data/lib/pubid/bsi/parser.rb +1 -1
- data/lib/pubid/bsi/renderer.rb +63 -51
- data/lib/pubid/bsi/single_identifier.rb +16 -7
- data/lib/pubid/bsi/urn_generator.rb +11 -2
- data/lib/pubid/bsi.rb +7 -1
- data/lib/pubid/builder/base.rb +18 -8
- data/lib/pubid/bundled_identifier.rb +16 -6
- data/lib/pubid/calconnect/identifier.rb +9 -5
- data/lib/pubid/calconnect/parser.rb +1 -1
- data/lib/pubid/calconnect.rb +7 -1
- data/lib/pubid/ccsds/identifier.rb +9 -2
- data/lib/pubid/ccsds/identifiers/base.rb +4 -2
- data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/ccsds/parser.rb +1 -1
- data/lib/pubid/ccsds/single_identifier.rb +2 -2
- data/lib/pubid/ccsds.rb +1 -0
- data/lib/pubid/cen_cenelec/builder.rb +101 -76
- data/lib/pubid/cen_cenelec/identifier.rb +115 -3
- data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
- data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
- data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
- data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
- data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
- data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
- data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
- data/lib/pubid/cen_cenelec/parser.rb +1 -1
- data/lib/pubid/cen_cenelec/renderer.rb +55 -60
- data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
- data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
- data/lib/pubid/cen_cenelec.rb +28 -10
- data/lib/pubid/cie/builder.rb +10 -0
- data/lib/pubid/cie/identifier.rb +6 -1
- data/lib/pubid/cie/identifiers/bundle.rb +4 -2
- data/lib/pubid/cie/identifiers/conference.rb +2 -2
- data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
- data/lib/pubid/cie/identifiers/identical.rb +2 -2
- data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
- data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
- data/lib/pubid/cie/identifiers/standard.rb +22 -13
- data/lib/pubid/cie/identifiers/supplement.rb +2 -2
- data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
- data/lib/pubid/cie/parser.rb +1 -1
- data/lib/pubid/cie.rb +7 -1
- data/lib/pubid/conformance/checks.rb +72 -0
- data/lib/pubid/conformance/corpus/case.rb +55 -0
- data/lib/pubid/conformance/corpus.rb +36 -0
- data/lib/pubid/conformance/generator.rb +212 -0
- data/lib/pubid/conformance/pending.rb +63 -0
- data/lib/pubid/conformance/runner.rb +153 -0
- data/lib/pubid/conformance.rb +55 -0
- data/lib/pubid/core.rb +2 -0
- data/lib/pubid/csa/builder.rb +47 -47
- data/lib/pubid/csa/composite_identifier.rb +14 -19
- data/lib/pubid/csa/identifier.rb +143 -81
- data/lib/pubid/csa/identifiers/bundled.rb +23 -13
- data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
- data/lib/pubid/csa/identifiers/cec.rb +44 -4
- data/lib/pubid/csa/identifiers/combined.rb +95 -73
- data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
- data/lib/pubid/csa/identifiers/package.rb +2 -2
- data/lib/pubid/csa/parser.rb +6 -2
- data/lib/pubid/csa/renderer.rb +13 -5
- data/lib/pubid/csa/single_identifier.rb +93 -4
- data/lib/pubid/csa/urn_generator.rb +9 -2
- data/lib/pubid/csa/wrapper_identifier.rb +39 -23
- data/lib/pubid/csa.rb +7 -1
- data/lib/pubid/doi/identifier.rb +6 -3
- data/lib/pubid/doi/parser.rb +1 -1
- data/lib/pubid/doi.rb +1 -0
- data/lib/pubid/easc/identifier.rb +0 -2
- data/lib/pubid/easc/parser.rb +10 -2
- data/lib/pubid/easc.rb +1 -0
- data/lib/pubid/ecma/builder.rb +23 -9
- data/lib/pubid/ecma/identifier.rb +81 -10
- data/lib/pubid/ecma/parser.rb +39 -4
- data/lib/pubid/ecma/renderer.rb +29 -8
- data/lib/pubid/ecma/urn_generator.rb +34 -13
- data/lib/pubid/ecma/urn_parser.rb +30 -14
- data/lib/pubid/ecma.rb +1 -0
- data/lib/pubid/errors.rb +80 -0
- data/lib/pubid/etsi/builder.rb +6 -1
- data/lib/pubid/etsi/identifiers/base.rb +34 -20
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
- data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
- data/lib/pubid/etsi/parser.rb +1 -1
- data/lib/pubid/etsi.rb +1 -0
- data/lib/pubid/evs/builder.rb +26 -0
- data/lib/pubid/evs/identifier.rb +37 -0
- data/lib/pubid/evs/identifiers/national_adoption.rb +17 -0
- data/lib/pubid/evs/identifiers.rb +9 -0
- data/lib/pubid/evs/parser.rb +27 -0
- data/lib/pubid/evs/renderer.rb +30 -0
- data/lib/pubid/evs/urn_generator.rb +30 -0
- data/lib/pubid/evs/urn_parser.rb +80 -0
- data/lib/pubid/evs.rb +90 -0
- data/lib/pubid/export.rb +1 -0
- data/lib/pubid/format_detector.rb +1 -0
- data/lib/pubid/gb/identifier.rb +6 -3
- data/lib/pubid/gb/parser.rb +1 -1
- data/lib/pubid/gb.rb +1 -0
- data/lib/pubid/gost/builder.rb +46 -9
- data/lib/pubid/gost/identifier.rb +0 -2
- data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
- data/lib/pubid/gost/parser.rb +10 -2
- data/lib/pubid/gost.rb +1 -0
- data/lib/pubid/iala/identifier.rb +9 -6
- data/lib/pubid/iala/parser.rb +10 -2
- data/lib/pubid/iala/urn_parser.rb +6 -2
- data/lib/pubid/iala.rb +1 -0
- data/lib/pubid/iana/builder.rb +3 -1
- data/lib/pubid/iana/identifier.rb +74 -6
- data/lib/pubid/iana/identifiers/registry.rb +36 -0
- data/lib/pubid/iana/parser.rb +1 -1
- data/lib/pubid/iana/renderer.rb +3 -0
- data/lib/pubid/iana/urn_generator.rb +5 -1
- data/lib/pubid/iana.rb +1 -0
- data/lib/pubid/identifier.rb +594 -10
- data/lib/pubid/identifier_metadata.rb +1 -0
- data/lib/pubid/idf/builder.rb +3 -3
- data/lib/pubid/idf/identifier.rb +18 -9
- data/lib/pubid/idf/parser.rb +1 -1
- data/lib/pubid/idf/renderer.rb +4 -4
- data/lib/pubid/idf/urn_generator.rb +1 -1
- data/lib/pubid/idf.rb +7 -1
- data/lib/pubid/iec/builder.rb +14 -7
- data/lib/pubid/iec/components.rb +0 -1
- data/lib/pubid/iec/identifier.rb +73 -83
- data/lib/pubid/iec/identifiers/amendment.rb +6 -2
- data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
- data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
- data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
- data/lib/pubid/iec/identifiers/guide.rb +0 -16
- data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
- data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
- data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
- data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
- data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
- data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
- data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
- data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
- data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
- data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
- data/lib/pubid/iec/identifiers/working_document.rb +24 -10
- data/lib/pubid/iec/parser.rb +2 -18
- data/lib/pubid/iec/renderer.rb +13 -10
- data/lib/pubid/iec/single_identifier.rb +33 -10
- data/lib/pubid/iec/urn_generator.rb +227 -61
- data/lib/pubid/iec/urn_parser.rb +42 -4
- data/lib/pubid/iec.rb +1 -0
- data/lib/pubid/ieee/aiee/identifier.rb +2 -2
- data/lib/pubid/ieee/aiee/parser.rb +1 -1
- data/lib/pubid/ieee/builder.rb +45 -1
- data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
- data/lib/pubid/ieee/identifiers/base.rb +42 -5
- data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
- data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
- data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
- data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
- data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
- data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
- data/lib/pubid/ieee/ire/identifier.rb +2 -2
- data/lib/pubid/ieee/ire/parser.rb +1 -1
- data/lib/pubid/ieee/nesc/parser.rb +1 -1
- data/lib/pubid/ieee/parser.rb +1 -1
- data/lib/pubid/ieee/renderer.rb +5 -1
- data/lib/pubid/ieee/urn_generator.rb +32 -3
- data/lib/pubid/ieee.rb +7 -1
- data/lib/pubid/ieee_debug.rb +1 -0
- data/lib/pubid/ietf/builder.rb +24 -8
- data/lib/pubid/ietf/identifiers/base.rb +25 -28
- data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
- data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
- data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
- data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
- data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
- data/lib/pubid/ietf/identifiers/std.rb +11 -0
- data/lib/pubid/ietf/identifiers.rb +1 -0
- data/lib/pubid/ietf/parser.rb +27 -9
- data/lib/pubid/ietf/renderer.rb +44 -6
- data/lib/pubid/ietf/urn_generator.rb +20 -6
- data/lib/pubid/ietf/urn_parser.rb +10 -2
- data/lib/pubid/ietf.rb +12 -2
- data/lib/pubid/iho/identifiers/base.rb +10 -3
- data/lib/pubid/iho/parser.rb +1 -1
- data/lib/pubid/iho.rb +1 -0
- data/lib/pubid/isbn/identifier.rb +25 -7
- data/lib/pubid/isbn/parser.rb +1 -1
- data/lib/pubid/isbn.rb +1 -0
- data/lib/pubid/iso/bundled_identifier.rb +5 -3
- data/lib/pubid/iso/combined_identifier.rb +5 -3
- data/lib/pubid/iso/identifier.rb +12 -7
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
- data/lib/pubid/iso/parser.rb +1 -1
- data/lib/pubid/iso.rb +7 -1
- data/lib/pubid/itu/identifiers/addendum.rb +2 -2
- data/lib/pubid/itu/identifiers/amendment.rb +2 -2
- data/lib/pubid/itu/identifiers/base.rb +19 -5
- data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
- data/lib/pubid/itu/identifiers/errata.rb +2 -2
- data/lib/pubid/itu/identifiers/supplement.rb +2 -2
- data/lib/pubid/itu/parser.rb +1 -1
- data/lib/pubid/itu.rb +1 -0
- data/lib/pubid/jcgm/builder.rb +1 -1
- data/lib/pubid/jcgm/identifier.rb +10 -0
- data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
- data/lib/pubid/jcgm/parser.rb +10 -3
- data/lib/pubid/jcgm/renderer.rb +10 -3
- data/lib/pubid/jcgm/single_identifier.rb +24 -15
- data/lib/pubid/jcgm/urn_generator.rb +1 -1
- data/lib/pubid/jcgm/urn_parser.rb +156 -14
- data/lib/pubid/jcgm.rb +10 -0
- data/lib/pubid/jis/identifier.rb +10 -3
- data/lib/pubid/jis/parser.rb +1 -1
- data/lib/pubid/jis.rb +1 -0
- data/lib/pubid/nist/components/stage.rb +2 -2
- data/lib/pubid/nist/configuration.rb +6 -8
- data/lib/pubid/nist/identifiers/base.rb +12 -2
- data/lib/pubid/nist/identifiers/circular.rb +9 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
- data/lib/pubid/nist/identifiers/crpl_report.rb +7 -1
- data/lib/pubid/nist/identifiers/handbook.rb +9 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +14 -6
- data/lib/pubid/nist/identifiers/monograph.rb +14 -7
- data/lib/pubid/nist/identifiers/report.rb +14 -6
- data/lib/pubid/nist/parser.rb +1 -1
- data/lib/pubid/nist/supplement_identifier.rb +16 -1
- data/lib/pubid/nist.rb +7 -1
- data/lib/pubid/oasis/builder.rb +12 -10
- data/lib/pubid/oasis/identifier.rb +89 -11
- data/lib/pubid/oasis/parser.rb +1 -1
- data/lib/pubid/oasis.rb +7 -1
- data/lib/pubid/ogc/identifier.rb +9 -5
- data/lib/pubid/ogc/parser.rb +1 -1
- data/lib/pubid/ogc.rb +1 -0
- data/lib/pubid/oiml/builder.rb +5 -1
- data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
- data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
- data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
- data/lib/pubid/oiml/identifiers/document.rb +2 -0
- data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
- data/lib/pubid/oiml/identifiers/guide.rb +2 -0
- data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
- data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
- data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
- data/lib/pubid/oiml/identifiers.rb +1 -0
- data/lib/pubid/oiml/parser.rb +1 -1
- data/lib/pubid/oiml/single_identifier.rb +26 -42
- data/lib/pubid/oiml/supplement_identifier.rb +27 -0
- data/lib/pubid/oiml.rb +7 -1
- data/lib/pubid/omg/builder.rb +1 -0
- data/lib/pubid/omg/identifier.rb +20 -3
- data/lib/pubid/omg/parser.rb +64 -11
- data/lib/pubid/omg/renderer.rb +13 -1
- data/lib/pubid/omg.rb +2 -1
- data/lib/pubid/parser/grammar.rb +74 -0
- data/lib/pubid/parser.rb +2 -0
- data/lib/pubid/parsers/mr_string.rb +19 -0
- data/lib/pubid/plateau/parser.rb +1 -1
- data/lib/pubid/plateau.rb +10 -0
- data/lib/pubid/prefixes_support.rb +1 -0
- data/lib/pubid/renderers/annotator.rb +233 -0
- data/lib/pubid/renderers/base.rb +13 -0
- data/lib/pubid/renderers/directives_renderer.rb +3 -3
- data/lib/pubid/renderers/human_readable.rb +3 -3
- data/lib/pubid/renderers/mr_string.rb +15 -9
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/rendering/numbering.rb +25 -7
- data/lib/pubid/rendering.rb +1 -0
- data/lib/pubid/sae/identifiers/base.rb +9 -2
- data/lib/pubid/sae/parser.rb +1 -1
- data/lib/pubid/sae.rb +1 -0
- data/lib/pubid/schema/declaration.rb +33 -0
- data/lib/pubid/schema/error.rb +14 -0
- data/lib/pubid/schema/identifier_type.rb +23 -0
- data/lib/pubid/schema/loader.rb +117 -0
- data/lib/pubid/schema/typed_stage.rb +24 -0
- data/lib/pubid/schema.rb +25 -0
- data/lib/pubid/tgpp/builder.rb +1 -1
- data/lib/pubid/tgpp/identifier.rb +21 -5
- data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
- data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
- data/lib/pubid/tgpp/parser.rb +22 -6
- data/lib/pubid/tgpp/renderer.rb +21 -5
- data/lib/pubid/tgpp/urn_generator.rb +27 -8
- data/lib/pubid/tgpp/urn_parser.rb +8 -6
- data/lib/pubid/tgpp.rb +7 -1
- data/lib/pubid/type_resolver.rb +16 -1
- data/lib/pubid/un/identifier.rb +6 -3
- data/lib/pubid/un/parser.rb +1 -1
- data/lib/pubid/un.rb +1 -0
- data/lib/pubid/urn_parser/errors.rb +8 -1
- data/lib/pubid/urn_parser.rb +1 -0
- data/lib/pubid/utils.rb +1 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/builder.rb +5 -5
- data/lib/pubid/w3c/identifier.rb +38 -9
- data/lib/pubid/w3c/parser.rb +1 -1
- data/lib/pubid/w3c/renderer.rb +1 -1
- data/lib/pubid/w3c/urn_generator.rb +2 -2
- data/lib/pubid/w3c.rb +1 -0
- data/lib/pubid/xsf/identifier.rb +9 -5
- data/lib/pubid/xsf/parser.rb +17 -4
- data/lib/pubid/xsf.rb +7 -1
- data/lib/pubid.rb +399 -21
- data/lib/tasks/conformance.rake +34 -0
- data/lib/tasks/docs.rake +3 -3
- data/lib/tasks/schema.rake +88 -0
- data/schema/core/joint_prefixes.yaml +24 -0
- data/schema/iec.yaml +1017 -0
- data/schema/iso.yaml +1586 -0
- data/schema/schema.schema.yaml +96 -0
- metadata +38 -17
- data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
- data/archived-gems/pubid-iec/stages.yaml +0 -129
- data/archived-gems/pubid-iec/update_codes.yaml +0 -67
- data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
- data/archived-gems/pubid-iso/stages.yaml +0 -106
- data/archived-gems/pubid-iso/update_codes.yaml +0 -4
- data/archived-gems/pubid-itu/i18n.yaml +0 -13
- data/archived-gems/pubid-itu/series.yaml +0 -42
- data/archived-gems/pubid-nist/publishers.yaml +0 -6
- data/archived-gems/pubid-nist/series.yaml +0 -121
- data/archived-gems/pubid-nist/update_codes.yaml +0 -93
- data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
- data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
- data/lib/pubid/iec/components/code.rb +0 -36
- /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
|
@@ -8,35 +8,30 @@ module Pubid
|
|
|
8
8
|
# collections of other identifiers or package materials.
|
|
9
9
|
#
|
|
10
10
|
# Examples:
|
|
11
|
-
# -
|
|
12
|
-
# - Future: BundleIdentifier refactor to use composite
|
|
11
|
+
# - Package: base + package materials
|
|
13
12
|
#
|
|
14
13
|
# This follows the Composite pattern where an identifier can contain
|
|
15
14
|
# other identifiers or additional metadata as a collection.
|
|
16
|
-
class CompositeIdentifier <
|
|
17
|
-
# The primary/base identifier
|
|
18
|
-
#
|
|
19
|
-
|
|
15
|
+
class CompositeIdentifier < Identifier
|
|
16
|
+
# The primary/base identifier. A real lutaml attribute under the uniform
|
|
17
|
+
# `base` name, so `#root` walks it and it survives serialization — see
|
|
18
|
+
# WrapperIdentifier#base for why the type is the cross-flavor
|
|
19
|
+
# ::Pubid::Identifier.
|
|
20
|
+
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
20
21
|
|
|
21
22
|
# Subclasses MUST implement to_s to define how they render
|
|
22
|
-
def to_s
|
|
23
|
+
def to_s(**_opts)
|
|
23
24
|
raise NotImplementedError, "Subclasses must implement to_s method"
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
def
|
|
29
|
-
|
|
27
|
+
# A package peels to the standard it packages — see
|
|
28
|
+
# WrapperIdentifier#base_document.
|
|
29
|
+
def base_document
|
|
30
|
+
base ? base.base_document : self
|
|
30
31
|
end
|
|
31
32
|
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# CSA composites are not Pubid::Identifier objects, so they do not inherit
|
|
37
|
-
# #root. They are their own origin for matching purposes.
|
|
38
|
-
def root
|
|
39
|
-
self
|
|
33
|
+
def drop_supplements
|
|
34
|
+
base || self
|
|
40
35
|
end
|
|
41
36
|
end
|
|
42
37
|
end
|
data/lib/pubid/csa/identifier.rb
CHANGED
|
@@ -2,22 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
module Pubid
|
|
4
4
|
module Csa
|
|
5
|
-
# Common base class for
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
5
|
+
# Common base class for EVERY CSA identifier — the single-document types
|
|
6
|
+
# through SingleIdentifier, and the container types (WrapperIdentifier,
|
|
7
|
+
# CompositeIdentifier, Bundled, Combined) directly. So every CSA identifier
|
|
8
|
+
# is `is_a?(Pubid::Csa::Identifier)` natively and gets the shared
|
|
9
|
+
# polymorphic `from_hash`, `#root`, `#exclude` and MR rendering. The
|
|
10
|
+
# containers used to be separate Lutaml::Model types, which is what made
|
|
11
|
+
# `root.number` raise rather than return the relaton index key.
|
|
10
12
|
class Identifier < ::Pubid::Identifier
|
|
11
13
|
def self.parse(input)
|
|
14
|
+
unless input.is_a?(String)
|
|
15
|
+
raise Pubid::Errors::InvalidInputError,
|
|
16
|
+
Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
17
|
+
end
|
|
18
|
+
|
|
12
19
|
if input.length > Pubid::MAX_INPUT_LENGTH
|
|
13
|
-
raise
|
|
20
|
+
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
14
21
|
end
|
|
15
22
|
|
|
16
23
|
# Filter out comments
|
|
17
|
-
|
|
24
|
+
if input.start_with?("#")
|
|
25
|
+
raise Pubid::Errors::ParseError.new(
|
|
26
|
+
"Not a CSA identifier (comment): #{input}",
|
|
27
|
+
input: input, flavor: "csa",
|
|
28
|
+
)
|
|
29
|
+
end
|
|
18
30
|
|
|
19
|
-
# Filter out non-standards
|
|
20
|
-
|
|
31
|
+
# Filter out non-standards (memberships, courses, newsletters)
|
|
32
|
+
if input.match?(/^CSA (Communities|Group|Learning|OnDemand|Update)/)
|
|
33
|
+
raise Pubid::Errors::ParseError.new(
|
|
34
|
+
"Not a CSA standard: #{input}", input: input, flavor: "csa"
|
|
35
|
+
)
|
|
36
|
+
end
|
|
21
37
|
|
|
22
38
|
# Preprocessing: normalize CEI to IEC (French name)
|
|
23
39
|
input = input.gsub("CEI/IEC", "IEC").gsub(/\bCEI\b/, "IEC")
|
|
@@ -46,16 +62,14 @@ module Pubid
|
|
|
46
62
|
|
|
47
63
|
# Parse normally (will create Bundled or Combined identifier)
|
|
48
64
|
tree = Parser.new.parse(normalized)
|
|
49
|
-
result =
|
|
65
|
+
result = build!(tree, input)
|
|
50
66
|
|
|
51
67
|
# Apply CAN/CSA- prefix to the appropriate parts
|
|
52
|
-
|
|
53
|
-
set_publisher_prefix(result, "CAN/CSA-")
|
|
68
|
+
set_publisher_prefix(result, "CAN/CSA-")
|
|
54
69
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
70
|
+
# Handle reaffirmation if present
|
|
71
|
+
if (wrapped_input =~ /\(R(\d{4})\)/) && result.class.attributes.key?(:reaffirmation)
|
|
72
|
+
result.reaffirmation = $1
|
|
59
73
|
end
|
|
60
74
|
|
|
61
75
|
return result
|
|
@@ -91,8 +105,7 @@ module Pubid
|
|
|
91
105
|
wrapped_input = wrapped_input.sub(/^CSA-/, "CSA ")
|
|
92
106
|
|
|
93
107
|
# Parse the wrapped identifier recursively
|
|
94
|
-
|
|
95
|
-
return nil unless wrapped_identifier
|
|
108
|
+
base = parse(wrapped_input)
|
|
96
109
|
|
|
97
110
|
# NOTE: Series identifiers should be wrapped in CanadianAdopted when
|
|
98
111
|
# they have CAN/CSA- prefix. The Series will handle rendering correctly.
|
|
@@ -101,32 +114,35 @@ module Pubid
|
|
|
101
114
|
# Set publisher prefix on wrapped identifier
|
|
102
115
|
# For Series identifiers with CAN/ wrapper, use full "CAN/CSA-" prefix
|
|
103
116
|
# For other identifiers, use the detected original_prefix ("CSA-" or "CSA")
|
|
104
|
-
if
|
|
105
|
-
if is_can_csa &&
|
|
117
|
+
if base.class.attributes.key?(:publisher_prefix)
|
|
118
|
+
if is_can_csa && base.is_a?(Identifiers::Series)
|
|
106
119
|
# Series gets full "CAN/CSA-" prefix for proper rendering
|
|
107
|
-
|
|
120
|
+
base.publisher_prefix = "CAN/CSA-"
|
|
108
121
|
elsif original_prefix
|
|
109
|
-
# For Combined identifiers, set on
|
|
110
|
-
if
|
|
111
|
-
|
|
122
|
+
# For Combined identifiers, set on the primary designation
|
|
123
|
+
if base.is_a?(Identifiers::Combined) && base.identifiers&.first
|
|
124
|
+
primary = base.identifiers.first
|
|
125
|
+
if primary.class.attributes.key?(:publisher_prefix)
|
|
126
|
+
primary.publisher_prefix = original_prefix
|
|
127
|
+
end
|
|
112
128
|
else
|
|
113
129
|
# For non-Combined identifiers, set directly
|
|
114
|
-
|
|
130
|
+
base.publisher_prefix = original_prefix
|
|
115
131
|
end
|
|
116
132
|
end
|
|
117
133
|
end
|
|
118
134
|
|
|
119
|
-
# Set reaffirmation on
|
|
120
|
-
if
|
|
121
|
-
|
|
122
|
-
if
|
|
123
|
-
|
|
135
|
+
# Set reaffirmation on base if it has the attribute
|
|
136
|
+
if base.class.attributes.key?(:reaffirmation) && reaffirm_year
|
|
137
|
+
base.reaffirmation = reaffirm_year
|
|
138
|
+
if base.class.attributes.key?(:original_reaffirmation_4digit)
|
|
139
|
+
base.original_reaffirmation_4digit = reaffirmation_was_4digit
|
|
124
140
|
end
|
|
125
141
|
end
|
|
126
142
|
|
|
127
143
|
# Create CanadianAdoptedIdentifier wrapper
|
|
128
144
|
result = Identifiers::CanadianAdopted.new
|
|
129
|
-
result.
|
|
145
|
+
result.base = base
|
|
130
146
|
result.reaffirmation = reaffirm_year if reaffirm_year
|
|
131
147
|
|
|
132
148
|
return result
|
|
@@ -157,44 +173,43 @@ module Pubid
|
|
|
157
173
|
end
|
|
158
174
|
|
|
159
175
|
# Parse the wrapped identifier recursively
|
|
160
|
-
|
|
161
|
-
return nil unless wrapped_identifier
|
|
176
|
+
base = parse(wrapped_input)
|
|
162
177
|
|
|
163
178
|
# Set year_format for dash format identifiers (preserve original 2-digit year)
|
|
164
|
-
if has_dash_year &&
|
|
165
|
-
|
|
179
|
+
if has_dash_year && base.class.attributes.key?(:year_format)
|
|
180
|
+
base.year_format = "dash"
|
|
166
181
|
# Mark original year as 2-digit so renderer converts back (1986 → 86)
|
|
167
|
-
if
|
|
168
|
-
|
|
182
|
+
if base.class.attributes.key?(:original_year_4digit)
|
|
183
|
+
base.original_year_4digit = false
|
|
169
184
|
end
|
|
170
185
|
end
|
|
171
186
|
|
|
172
187
|
# Check if this is a Series identifier - return it directly with CAN3- prefix
|
|
173
188
|
# Series identifiers are complete identifier types and handle the prefix themselves
|
|
174
189
|
# They don't need to be wrapped in CanadianAdopted
|
|
175
|
-
if
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return
|
|
190
|
+
if base.is_a?(Identifiers::Series)
|
|
191
|
+
base.publisher_prefix = "CAN3-"
|
|
192
|
+
base.reaffirmation = reaffirm_year if reaffirm_year
|
|
193
|
+
base.original_reaffirmation_4digit = reaffirmation_was_4digit
|
|
194
|
+
return base
|
|
180
195
|
end
|
|
181
196
|
|
|
182
197
|
# Set CAN3- as publisher prefix on wrapped identifier
|
|
183
|
-
if
|
|
184
|
-
|
|
198
|
+
if base.class.attributes.key?(:publisher_prefix)
|
|
199
|
+
base.publisher_prefix = "CAN3-"
|
|
185
200
|
end
|
|
186
201
|
|
|
187
|
-
# Set reaffirmation on
|
|
188
|
-
if
|
|
189
|
-
|
|
190
|
-
if
|
|
191
|
-
|
|
202
|
+
# Set reaffirmation on base if it has the attribute
|
|
203
|
+
if base.class.attributes.key?(:reaffirmation) && reaffirm_year
|
|
204
|
+
base.reaffirmation = reaffirm_year
|
|
205
|
+
if base.class.attributes.key?(:original_reaffirmation_4digit)
|
|
206
|
+
base.original_reaffirmation_4digit = reaffirmation_was_4digit
|
|
192
207
|
end
|
|
193
208
|
end
|
|
194
209
|
|
|
195
210
|
# Create CanadianAdoptedIdentifier wrapper
|
|
196
211
|
result = Identifiers::CanadianAdopted.new
|
|
197
|
-
result.
|
|
212
|
+
result.base = base
|
|
198
213
|
result.reaffirmation = reaffirm_year if reaffirm_year
|
|
199
214
|
|
|
200
215
|
return result
|
|
@@ -250,13 +265,20 @@ module Pubid
|
|
|
250
265
|
"/Amd #{amendment_num}#{separator}#{amend_full_year}"
|
|
251
266
|
end
|
|
252
267
|
|
|
253
|
-
# Parse with appropriate flavor parser
|
|
254
|
-
|
|
255
|
-
|
|
268
|
+
# Parse with appropriate flavor parser. The helper probes several
|
|
269
|
+
# flavors and reports failure with nil; the public contract is a
|
|
270
|
+
# raise, so translate here.
|
|
271
|
+
base = parse_external_standard(wrapped_input)
|
|
272
|
+
unless base
|
|
273
|
+
raise Pubid::Errors::ParseError.new(
|
|
274
|
+
"Unparseable adopted standard: #{input}",
|
|
275
|
+
input: input, flavor: "csa",
|
|
276
|
+
)
|
|
277
|
+
end
|
|
256
278
|
|
|
257
279
|
# Create CsaAdoptedIdentifier wrapper
|
|
258
280
|
result = Identifiers::CsaAdopted.new
|
|
259
|
-
result.
|
|
281
|
+
result.base = base
|
|
260
282
|
result.reaffirmation = reaffirm_year if reaffirm_year
|
|
261
283
|
|
|
262
284
|
return result
|
|
@@ -337,12 +359,9 @@ module Pubid
|
|
|
337
359
|
break if token.match?(/^PACKAGE$/i)
|
|
338
360
|
|
|
339
361
|
test_input = base_input.empty? ? token : "#{base_input} #{token}"
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
else
|
|
344
|
-
break
|
|
345
|
-
end
|
|
362
|
+
break unless try_parse(test_input)
|
|
363
|
+
|
|
364
|
+
base_input = test_input
|
|
346
365
|
end
|
|
347
366
|
|
|
348
367
|
# Extract materials as everything between base and PACKAGE
|
|
@@ -354,9 +373,16 @@ module Pubid
|
|
|
354
373
|
end
|
|
355
374
|
end
|
|
356
375
|
|
|
357
|
-
# Parse base identifier recursively
|
|
358
|
-
|
|
359
|
-
|
|
376
|
+
# Parse the base identifier recursively. An unparseable base is a
|
|
377
|
+
# failed package, not a nil.
|
|
378
|
+
if base_input.nil? || base_input.empty?
|
|
379
|
+
raise Pubid::Errors::ParseError.new(
|
|
380
|
+
"Unparseable package base: #{input}",
|
|
381
|
+
input: input, flavor: "csa",
|
|
382
|
+
)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
base = parse(base_input)
|
|
360
386
|
|
|
361
387
|
# Create PackageIdentifier
|
|
362
388
|
result = Identifiers::Package.new
|
|
@@ -393,39 +419,61 @@ module Pubid
|
|
|
393
419
|
normalized = normalized.gsub("CAN3-", "CSA ")
|
|
394
420
|
|
|
395
421
|
tree = Parser.new.parse(normalized)
|
|
396
|
-
result =
|
|
422
|
+
result = build!(tree, input)
|
|
397
423
|
|
|
398
424
|
# Set publisher prefix if detected
|
|
399
|
-
|
|
400
|
-
set_publisher_prefix(result, publisher_prefix)
|
|
401
|
-
end
|
|
425
|
+
set_publisher_prefix(result, publisher_prefix) if publisher_prefix
|
|
402
426
|
|
|
403
427
|
# Set year format if detected as dash and not already set
|
|
404
|
-
|
|
405
|
-
result.year_format = "dash"
|
|
406
|
-
end
|
|
428
|
+
result.year_format = "dash" if has_dash_year && result.year_format.nil?
|
|
407
429
|
|
|
408
430
|
result
|
|
409
431
|
rescue Parslet::ParseFailed => e
|
|
410
432
|
raise e
|
|
411
433
|
end
|
|
412
434
|
|
|
435
|
+
# Build a parse tree into an identifier, or fail loudly.
|
|
436
|
+
#
|
|
437
|
+
# Builder#build can return nil for a tree it recognises but cannot map
|
|
438
|
+
# to a class. `parse` must return an identifier or raise — every flavor
|
|
439
|
+
# but `api` already honours that — because a nil surfaces in the caller
|
|
440
|
+
# as a NoMethodError far from the input that caused it, rather than as a
|
|
441
|
+
# catchable parse failure.
|
|
442
|
+
def self.build!(tree, input)
|
|
443
|
+
built = Builder.new.build(tree)
|
|
444
|
+
return built if built
|
|
445
|
+
|
|
446
|
+
raise Pubid::Errors::ParseError.new(
|
|
447
|
+
"Unparseable CSA identifier: #{input}",
|
|
448
|
+
input: input, flavor: "csa",
|
|
449
|
+
)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# Probe whether a string parses. The package base scan walks
|
|
453
|
+
# progressively longer prefixes and keeps the longest that succeeds, so
|
|
454
|
+
# it is the one caller that genuinely wants a nil rather than a raise.
|
|
455
|
+
def self.try_parse(input)
|
|
456
|
+
parse(input)
|
|
457
|
+
rescue Parslet::ParseFailed, ArgumentError
|
|
458
|
+
nil
|
|
459
|
+
end
|
|
460
|
+
|
|
413
461
|
def self.set_publisher_prefix(obj, prefix)
|
|
414
462
|
# Set on main object if it has the attribute
|
|
415
463
|
if obj.class.attributes.key?(:publisher_prefix)
|
|
416
464
|
obj.publisher_prefix = prefix
|
|
417
465
|
end
|
|
418
466
|
|
|
419
|
-
# Set on combined identifier parts
|
|
467
|
+
# Set on combined identifier parts. The primary designation always
|
|
468
|
+
# takes the prefix; a trailing one only when it printed a publisher of
|
|
469
|
+
# its own (a bare continuation must stay bare).
|
|
420
470
|
if obj.is_a?(Identifiers::Combined)
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if obj.third && obj.third.class.attributes.key?(:has_publisher) && obj.third.has_publisher && obj.third.class.attributes.key?(:publisher_prefix)
|
|
428
|
-
obj.third.publisher_prefix = prefix
|
|
471
|
+
Array(obj.identifiers).each_with_index do |part, index|
|
|
472
|
+
next unless part.class.attributes.key?(:publisher_prefix)
|
|
473
|
+
next if index.positive? &&
|
|
474
|
+
!(part.class.attributes.key?(:has_publisher) && part.has_publisher)
|
|
475
|
+
|
|
476
|
+
part.publisher_prefix = prefix
|
|
429
477
|
end
|
|
430
478
|
end
|
|
431
479
|
|
|
@@ -489,15 +537,29 @@ module Pubid
|
|
|
489
537
|
end
|
|
490
538
|
|
|
491
539
|
# CSA encodes its identity across many shape-specific attributes
|
|
492
|
-
# (`publisher_prefix`, `
|
|
540
|
+
# (`publisher_prefix`, `number`, `no_number`, `series`, `series_prefix`,
|
|
493
541
|
# `package`, `reaffirmation`, `year` with prefix/format/French markers,
|
|
494
542
|
# etc.) that the generic MrString renderer doesn't know about. The
|
|
495
543
|
# CSA `to_s` already round-trips losslessly through the CSA parser, so
|
|
496
544
|
# MR mirrors it: ` ` → `.`, `:` → `.` (so the year never looks like
|
|
497
545
|
# another code segment), `/` → `-` (CAN/CSA- prefix), then lowercased
|
|
498
546
|
# to match the all-lowercase MR convention (issue #142).
|
|
547
|
+
#
|
|
548
|
+
# Those three are the SEMANTIC mappings — they carry CSA's segment
|
|
549
|
+
# structure. Everything else is then neutralised by CHARSET, not by an
|
|
550
|
+
# enumerated escape list, so a character that appears in a future
|
|
551
|
+
# reference cannot leak into what `to_slug` hands a filesystem. CSA
|
|
552
|
+
# references really do carry `(`, `)`, `,`, `&` and `+` today
|
|
553
|
+
# (`CSA C22.2 NO. 100:14 (R2024)`, `… Code, Handbook & Training
|
|
554
|
+
# Package`, `… + A1:15`), and the old `tr` chain let all of them
|
|
555
|
+
# through — 601 of 816 slugs were not filename-safe. The BIPM `mr_slug`
|
|
556
|
+
# precedent.
|
|
499
557
|
def to_mr_string
|
|
500
|
-
to_s
|
|
558
|
+
to_s
|
|
559
|
+
.downcase
|
|
560
|
+
.tr(" ", ".").tr(":", ".").tr("/", "-")
|
|
561
|
+
.gsub(/[^a-z0-9._-]+/, "-")
|
|
562
|
+
.gsub(/\A[-.]+|[-.]+\z/, "")
|
|
501
563
|
end
|
|
502
564
|
|
|
503
565
|
def to_slug
|
|
@@ -5,23 +5,33 @@ require "lutaml/model"
|
|
|
5
5
|
module Pubid
|
|
6
6
|
module Csa
|
|
7
7
|
module Identifiers
|
|
8
|
-
class Bundled <
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
class Bundled < Identifier
|
|
9
|
+
# The consolidated base document and the amendments bundled with it.
|
|
10
|
+
# Both are typed cross-flavor and polymorphic — see
|
|
11
|
+
# WrapperIdentifier#base — because a bundle's base is routinely a Cec,
|
|
12
|
+
# which is not a Standard subclass. #root is inherited: it walks
|
|
13
|
+
# `base` to the origin document.
|
|
14
|
+
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
15
|
+
attribute :bundled_with, ::Pubid::Identifier, polymorphic: true,
|
|
16
|
+
collection: true
|
|
11
17
|
attribute :reaffirmation, :string
|
|
12
18
|
attribute :original_reaffirmation_4digit, :boolean, default: -> {
|
|
13
19
|
false
|
|
14
20
|
}
|
|
15
21
|
attribute :year_format, :string # Add for compatibility with identifier.rb
|
|
16
22
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
def
|
|
20
|
-
self
|
|
23
|
+
# A bundle is a base document consolidated with its amendments, so
|
|
24
|
+
# both matching primitives peel to that base.
|
|
25
|
+
def base_document
|
|
26
|
+
base ? base.base_document : self
|
|
21
27
|
end
|
|
22
28
|
|
|
23
|
-
def
|
|
24
|
-
|
|
29
|
+
def drop_supplements
|
|
30
|
+
base || self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_s(**opts)
|
|
34
|
+
# For Cec identifiers, use normalized form (number instead of cec_part + NO.)
|
|
25
35
|
# This is used for "normalized form" rendering in bundled identifiers
|
|
26
36
|
if base.is_a?(Cec)
|
|
27
37
|
# Render base with normalized code format
|
|
@@ -37,7 +47,7 @@ module Pubid
|
|
|
37
47
|
end
|
|
38
48
|
end
|
|
39
49
|
base_str = (needs_space ? "#{prefix} " : prefix) +
|
|
40
|
-
base.
|
|
50
|
+
base.number.value.to_s + # Normalized code (e.g. "C22.2-1")
|
|
41
51
|
":#{year_display}"
|
|
42
52
|
parts = [base_str]
|
|
43
53
|
else
|
|
@@ -50,7 +60,7 @@ module Pubid
|
|
|
50
60
|
bundled_with.each do |bundled|
|
|
51
61
|
# For Cec identifiers, use normalized code format
|
|
52
62
|
if bundled.is_a?(Cec)
|
|
53
|
-
bundled_part = bundled.
|
|
63
|
+
bundled_part = bundled.number.value.to_s # e.g. "C22.2-2"
|
|
54
64
|
if bundled.year
|
|
55
65
|
# Use dash if year_format is dash, otherwise colon
|
|
56
66
|
separator = bundled.year_format == "dash" ? "-" : ":"
|
|
@@ -68,7 +78,7 @@ module Pubid
|
|
|
68
78
|
else
|
|
69
79
|
# Standard rendering for other identifier types
|
|
70
80
|
bundled_part = ""
|
|
71
|
-
bundled_part += bundled.
|
|
81
|
+
bundled_part += bundled.number.to_s if bundled.number
|
|
72
82
|
|
|
73
83
|
if bundled.year
|
|
74
84
|
# Use dash if year_format is dash, otherwise colon
|
|
@@ -123,7 +133,7 @@ module Pubid
|
|
|
123
133
|
end
|
|
124
134
|
end
|
|
125
135
|
|
|
126
|
-
result
|
|
136
|
+
annotate_plain_render(result, **opts)
|
|
127
137
|
end
|
|
128
138
|
end
|
|
129
139
|
end
|
|
@@ -12,40 +12,40 @@ module Pubid
|
|
|
12
12
|
#
|
|
13
13
|
# This is a wrapper pattern where:
|
|
14
14
|
# - CAN/ indicates Canadian adoption
|
|
15
|
-
# - The
|
|
15
|
+
# - The base is the actual CSA standard being adopted
|
|
16
16
|
#
|
|
17
17
|
# This is semantically different from a string prefix because:
|
|
18
18
|
# - CAN/ wraps an entire identifier (which may itself be complex)
|
|
19
19
|
# - The wrapped identifier is recursively parsed as a full CSA identifier
|
|
20
20
|
# - Proper object composition, not string manipulation
|
|
21
21
|
class CanadianAdopted < WrapperIdentifier
|
|
22
|
-
def to_s
|
|
22
|
+
def to_s(**opts)
|
|
23
23
|
# For CAN3- identifiers, don't add CAN/ prefix (CAN3- is already complete)
|
|
24
24
|
# For Series with CAN/CSA- prefix, don't add CAN/ (it's already complete)
|
|
25
25
|
# For CAN/CSA- identifiers, CAN/ wraps CSA- part
|
|
26
|
-
if
|
|
27
|
-
prefix =
|
|
26
|
+
if base.class.attributes.key?(:publisher_prefix) && base.publisher_prefix
|
|
27
|
+
prefix = base.publisher_prefix
|
|
28
28
|
# CAN3- is standalone, just render wrapped identifier
|
|
29
29
|
# CAN/CSA- is already complete for Series identifiers
|
|
30
|
-
if prefix == "CAN3-" || (prefix == "CAN/CSA-" &&
|
|
31
|
-
result =
|
|
30
|
+
if prefix == "CAN3-" || (prefix == "CAN/CSA-" && base.is_a?(Identifiers::Series))
|
|
31
|
+
result = base.to_s
|
|
32
32
|
else
|
|
33
33
|
# For other cases, prepend CAN/ prefix
|
|
34
|
-
result = "CAN/#{
|
|
34
|
+
result = "CAN/#{base}"
|
|
35
35
|
end
|
|
36
36
|
else
|
|
37
37
|
# No publisher_prefix, prepend CAN/
|
|
38
|
-
result = "CAN/#{
|
|
38
|
+
result = "CAN/#{base}"
|
|
39
39
|
end
|
|
40
|
-
# Only add reaffirmation from wrapper if
|
|
40
|
+
# Only add reaffirmation from wrapper if base doesn't have one
|
|
41
41
|
# (to avoid duplicates - Identifier.parse sets it on both)
|
|
42
|
-
if reaffirmation && !(
|
|
42
|
+
if reaffirmation && !(base.class.attributes.key?(:reaffirmation) && base.reaffirmation)
|
|
43
43
|
# Determine if space is needed before reaffirmation
|
|
44
44
|
# Space needed if year is 2-digit and reaffirmation is 4-digit (original format)
|
|
45
45
|
# No space if both year and reaffirmation are 2-digit
|
|
46
46
|
# Check original_year_4digit flag - if false, year was originally 2-digit
|
|
47
|
-
year_was_2digit =
|
|
48
|
-
!
|
|
47
|
+
year_was_2digit = base.class.attributes.key?(:original_year_4digit) &&
|
|
48
|
+
!base.original_year_4digit
|
|
49
49
|
# Check original_reaffirmation_4digit flag
|
|
50
50
|
reaffirmation_was_4digit = original_reaffirmation_4digit
|
|
51
51
|
|
|
@@ -74,7 +74,7 @@ module Pubid
|
|
|
74
74
|
result += "(R#{reaffirmation_str})"
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
|
-
result
|
|
77
|
+
annotate_plain_render(result, **opts)
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
end
|
|
@@ -13,12 +13,52 @@ module Pubid
|
|
|
13
13
|
attribute :cec_part, Components::Code # C22.2, C22.3, C22.4, C22.6
|
|
14
14
|
attribute :no_number, Components::Code # Number after NO.
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
16
|
+
# `CSA C22.2 NO. 286:23` stores the joined "C22.2-286" in `number`, which
|
|
17
|
+
# appears nowhere in the printed form; the two halves it does print live
|
|
18
|
+
# in `cec_part` and `no_number`. Naming them gives the identifier its
|
|
19
|
+
# docnumber spans back.
|
|
20
|
+
def annotation_tokens
|
|
21
|
+
super + [
|
|
22
|
+
[:publisher_prefix, "publisher"],
|
|
23
|
+
[:cec_part, "docnumber"],
|
|
24
|
+
[:no_number, "docnumber"],
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Merged with SingleIdentifier's block (lutaml combines an inherited
|
|
29
|
+
# key_value block with a subclass one), so this adds only the half of
|
|
30
|
+
# the code that Cec keeps separately.
|
|
31
|
+
key_value do
|
|
32
|
+
map "cec_part",
|
|
33
|
+
with: { to: :cec_part_to_kv, from: :cec_part_from_kv }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def cec_part_to_kv(model, doc)
|
|
37
|
+
emit_kv(doc, "cec_part", model.cec_part)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def cec_part_from_kv(model, value)
|
|
41
|
+
model.cec_part = Components::Code.new(value: value.to_s)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The document code, synthesised from its two halves:
|
|
45
|
+
# cec_part + "-" + no_number (e.g. "C22.2-1"). This is the index key.
|
|
46
|
+
#
|
|
47
|
+
# It shadows the reader lutaml generates for the inherited `number`
|
|
48
|
+
# attribute, which is safe because Cec declares no `number` of its own
|
|
49
|
+
# — the ITU precedent (itu/identifiers/base.rb). `cec_part` and
|
|
50
|
+
# `no_number` are themselves serialized, so from_hash reproduces the
|
|
51
|
+
# synthesised value.
|
|
52
|
+
#
|
|
53
|
+
# Deliberately NOT memoised: `@number` is the very ivar lutaml uses to
|
|
54
|
+
# store the inherited attribute, so caching there would both discard a
|
|
55
|
+
# value assigned through the generated writer and go stale if
|
|
56
|
+
# `cec_part`/`no_number` were reassigned — and `number` is the relaton
|
|
57
|
+
# index key. The concatenation is trivial, so there is nothing to save.
|
|
58
|
+
def number
|
|
19
59
|
return nil unless cec_part && no_number
|
|
20
60
|
|
|
21
|
-
|
|
61
|
+
Components::Code.new(value: "#{cec_part.value}-#{no_number.value}")
|
|
22
62
|
end
|
|
23
63
|
end
|
|
24
64
|
end
|