pubid 1.15.21 → 2.0.0.alpha.10
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/LICENSE.txt +1 -1
- data/README.adoc +2044 -53
- data/archived-gems/pubid-ccsds/update_codes.yaml +1 -0
- data/archived-gems/pubid-iec/stages.yaml +129 -0
- data/archived-gems/pubid-iec/update_codes.yaml +67 -0
- data/archived-gems/pubid-ieee/update_codes.yaml +104 -0
- data/archived-gems/pubid-iso/stages.yaml +106 -0
- data/archived-gems/pubid-iso/update_codes.yaml +4 -0
- data/archived-gems/pubid-itu/i18n.yaml +13 -0
- data/archived-gems/pubid-itu/series.yaml +42 -0
- data/archived-gems/pubid-nist/publishers.yaml +6 -0
- data/archived-gems/pubid-nist/series.yaml +121 -0
- data/archived-gems/pubid-nist/stages.yaml +16 -0
- data/archived-gems/pubid-nist/update_codes.yaml +93 -0
- data/archived-gems/pubid-plateau/update_codes.yaml +6 -0
- data/data/bipm/update_codes.yaml +9 -0
- data/data/ccsds/update_codes.yaml +1 -0
- data/data/iec/update_codes.yaml +70 -0
- data/data/ieee/update_codes.yaml +210 -0
- data/data/iso/update_codes.yaml +21 -0
- data/data/nist/series.yaml +155 -0
- data/data/nist/update_codes.yaml +122 -0
- data/data/plateau/update_codes.yaml +6 -0
- data/lib/pubid/adobe/builder.rb +52 -0
- data/lib/pubid/adobe/identifier.rb +47 -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 +136 -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 +176 -0
- data/lib/pubid/amca/identifier.rb +4 -0
- data/lib/pubid/amca/identifiers/base.rb +92 -0
- data/lib/pubid/amca/identifiers/interpretation.rb +38 -0
- data/lib/pubid/amca/identifiers/publication.rb +34 -0
- data/lib/pubid/amca/identifiers/standard.rb +20 -0
- data/lib/pubid/amca/identifiers.rb +11 -0
- data/lib/pubid/amca/parser.rb +153 -0
- data/lib/pubid/amca/renderer.rb +82 -0
- data/lib/pubid/amca/single_identifier.rb +10 -0
- data/lib/pubid/amca/urn_generator.rb +51 -0
- data/lib/pubid/amca/urn_parser.rb +28 -0
- data/lib/pubid/amca.rb +73 -0
- data/lib/pubid/ansi/builder.rb +54 -0
- data/lib/pubid/ansi/identifier.rb +31 -0
- data/lib/pubid/ansi/identifiers/american_national_standard.rb +13 -0
- data/lib/pubid/ansi/identifiers/standard.rb +15 -0
- data/lib/pubid/ansi/identifiers.rb +11 -0
- data/lib/pubid/ansi/parser.rb +91 -0
- data/lib/pubid/ansi/renderer.rb +53 -0
- data/lib/pubid/ansi/single_identifier.rb +16 -0
- data/lib/pubid/ansi/urn_generator.rb +41 -0
- data/lib/pubid/ansi/urn_parser.rb +23 -0
- data/lib/pubid/ansi.rb +68 -0
- data/lib/pubid/api/builder.rb +58 -0
- data/lib/pubid/api/components/code.rb +9 -0
- data/lib/pubid/api/identifier.rb +42 -0
- data/lib/pubid/api/identifiers/base.rb +12 -0
- data/lib/pubid/api/identifiers/bulletin.rb +13 -0
- data/lib/pubid/api/identifiers/continuous_operations_standard.rb +13 -0
- data/lib/pubid/api/identifiers/mpms.rb +26 -0
- data/lib/pubid/api/identifiers/publication.rb +13 -0
- data/lib/pubid/api/identifiers/recommended_practice.rb +13 -0
- data/lib/pubid/api/identifiers/specification.rb +13 -0
- data/lib/pubid/api/identifiers/standard.rb +13 -0
- data/lib/pubid/api/identifiers/technical_report.rb +13 -0
- data/lib/pubid/api/identifiers/typeless_standard.rb +11 -0
- data/lib/pubid/api/identifiers.rb +18 -0
- data/lib/pubid/api/parser.rb +140 -0
- data/lib/pubid/api/renderer.rb +98 -0
- data/lib/pubid/api/single_identifier.rb +24 -0
- data/lib/pubid/api/urn_generator.rb +23 -0
- data/lib/pubid/api/urn_parser.rb +35 -0
- data/lib/pubid/api.rb +68 -0
- data/lib/pubid/ashrae/builder.rb +519 -0
- data/lib/pubid/ashrae/identifier.rb +8 -0
- data/lib/pubid/ashrae/identifiers/addenda_package.rb +42 -0
- data/lib/pubid/ashrae/identifiers/addendum.rb +44 -0
- data/lib/pubid/ashrae/identifiers/base.rb +119 -0
- data/lib/pubid/ashrae/identifiers/combined_addenda.rb +43 -0
- data/lib/pubid/ashrae/identifiers/errata.rb +39 -0
- data/lib/pubid/ashrae/identifiers/guideline.rb +41 -0
- data/lib/pubid/ashrae/identifiers/interpretation.rb +45 -0
- data/lib/pubid/ashrae/identifiers/standard.rb +41 -0
- data/lib/pubid/ashrae/identifiers.rb +15 -0
- data/lib/pubid/ashrae/parser.rb +748 -0
- data/lib/pubid/ashrae/renderer.rb +117 -0
- data/lib/pubid/ashrae/single_identifier.rb +10 -0
- data/lib/pubid/ashrae/supplement_identifier.rb +38 -0
- data/lib/pubid/ashrae/urn_generator.rb +57 -0
- data/lib/pubid/ashrae/urn_parser.rb +27 -0
- data/lib/pubid/ashrae.rb +77 -0
- data/lib/pubid/asme/builder.rb +162 -0
- data/lib/pubid/asme/components/code.rb +26 -0
- data/lib/pubid/asme/identifier.rb +24 -0
- data/lib/pubid/asme/identifiers/base.rb +10 -0
- data/lib/pubid/asme/identifiers/standard.rb +96 -0
- data/lib/pubid/asme/identifiers.rb +10 -0
- data/lib/pubid/asme/parser.rb +308 -0
- data/lib/pubid/asme/renderer.rb +66 -0
- data/lib/pubid/asme/single_identifier.rb +38 -0
- data/lib/pubid/asme/urn_generator.rb +133 -0
- data/lib/pubid/asme/urn_parser.rb +31 -0
- data/lib/pubid/asme.rb +67 -0
- data/lib/pubid/astm/builder.rb +166 -0
- data/lib/pubid/astm/components/code.rb +42 -0
- data/lib/pubid/astm/components.rb +9 -0
- data/lib/pubid/astm/identifier.rb +24 -0
- data/lib/pubid/astm/identifiers/adjunct.rb +28 -0
- data/lib/pubid/astm/identifiers/base.rb +13 -0
- data/lib/pubid/astm/identifiers/code_number.rb +81 -0
- data/lib/pubid/astm/identifiers/data_series.rb +13 -0
- data/lib/pubid/astm/identifiers/iso_dual_published.rb +65 -0
- data/lib/pubid/astm/identifiers/manual.rb +23 -0
- data/lib/pubid/astm/identifiers/monograph.rb +13 -0
- data/lib/pubid/astm/identifiers/research_report.rb +21 -0
- data/lib/pubid/astm/identifiers/standard.rb +23 -0
- data/lib/pubid/astm/identifiers/technical_report.rb +12 -0
- data/lib/pubid/astm/identifiers/work_in_progress.rb +12 -0
- data/lib/pubid/astm/identifiers.rb +19 -0
- data/lib/pubid/astm/parser.rb +244 -0
- data/lib/pubid/astm/renderer.rb +172 -0
- data/lib/pubid/astm/single_identifier.rb +47 -0
- data/lib/pubid/astm/urn_generator.rb +101 -0
- data/lib/pubid/astm/urn_parser.rb +30 -0
- data/lib/pubid/astm.rb +55 -0
- data/lib/pubid/bipm/builder.rb +163 -0
- data/lib/pubid/bipm/identifier.rb +285 -0
- data/lib/pubid/bipm/identifiers/committee_document.rb +36 -0
- data/lib/pubid/bipm/identifiers/guide.rb +35 -0
- data/lib/pubid/bipm/identifiers/meeting.rb +53 -0
- data/lib/pubid/bipm/identifiers/mep.rb +33 -0
- data/lib/pubid/bipm/identifiers/metrologia_article.rb +48 -0
- data/lib/pubid/bipm/identifiers/si_brochure.rb +33 -0
- data/lib/pubid/bipm/identifiers.rb +15 -0
- data/lib/pubid/bipm/parser.rb +237 -0
- data/lib/pubid/bipm/renderer.rb +118 -0
- data/lib/pubid/bipm/urn_generator.rb +58 -0
- data/lib/pubid/bipm/urn_parser.rb +60 -0
- data/lib/pubid/bipm.rb +91 -0
- data/lib/pubid/bsi/builder.rb +1495 -0
- data/lib/pubid/bsi/components/code.rb +11 -0
- data/lib/pubid/bsi/components/date.rb +11 -0
- data/lib/pubid/bsi/components/publisher.rb +11 -0
- data/lib/pubid/bsi/components/type.rb +11 -0
- data/lib/pubid/bsi/identifier.rb +6 -0
- data/lib/pubid/bsi/identifiers/addendum_document.rb +30 -0
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +67 -0
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +51 -0
- data/lib/pubid/bsi/identifiers/aerospace_standard.rb +65 -0
- data/lib/pubid/bsi/identifiers/amendment.rb +48 -0
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +21 -0
- data/lib/pubid/bsi/identifiers/british_standard.rb +34 -0
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +40 -0
- data/lib/pubid/bsi/identifiers/committee_document.rb +44 -0
- data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +84 -0
- data/lib/pubid/bsi/identifiers/corrigendum.rb +44 -0
- data/lib/pubid/bsi/identifiers/detailed_specification.rb +33 -0
- data/lib/pubid/bsi/identifiers/disc.rb +27 -0
- data/lib/pubid/bsi/identifiers/draft_document.rb +27 -0
- data/lib/pubid/bsi/identifiers/electronic_book.rb +16 -0
- data/lib/pubid/bsi/identifiers/expert_commentary.rb +36 -0
- data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +35 -0
- data/lib/pubid/bsi/identifiers/flex.rb +30 -0
- data/lib/pubid/bsi/identifiers/handbook.rb +23 -0
- data/lib/pubid/bsi/identifiers/index.rb +30 -0
- data/lib/pubid/bsi/identifiers/method.rb +35 -0
- data/lib/pubid/bsi/identifiers/national_annex.rb +48 -0
- data/lib/pubid/bsi/identifiers/practice_guide.rb +21 -0
- data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +27 -0
- data/lib/pubid/bsi/identifiers/published_document.rb +27 -0
- data/lib/pubid/bsi/identifiers/section.rb +32 -0
- data/lib/pubid/bsi/identifiers/set.rb +40 -0
- data/lib/pubid/bsi/identifiers/standalone_amendment.rb +40 -0
- data/lib/pubid/bsi/identifiers/supplement_document.rb +29 -0
- data/lib/pubid/bsi/identifiers/supplementary_index.rb +35 -0
- data/lib/pubid/bsi/identifiers/technical_specification.rb +34 -0
- data/lib/pubid/bsi/identifiers/test_method.rb +35 -0
- data/lib/pubid/bsi/identifiers/value_added_publication.rb +37 -0
- data/lib/pubid/bsi/identifiers.rb +51 -0
- data/lib/pubid/bsi/model.rb +196 -0
- data/lib/pubid/bsi/parser.rb +673 -0
- data/lib/pubid/bsi/renderer.rb +1064 -0
- data/lib/pubid/bsi/single_identifier.rb +141 -0
- data/lib/pubid/bsi/urn_generator.rb +92 -0
- data/lib/pubid/bsi/urn_parser.rb +52 -0
- data/lib/pubid/bsi.rb +282 -0
- data/lib/pubid/builder/base.rb +187 -0
- data/lib/pubid/bundled_identifier.rb +134 -0
- data/lib/pubid/calconnect/builder.rb +38 -0
- data/lib/pubid/calconnect/identifier.rb +121 -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 +82 -0
- data/lib/pubid/ccsds/builder.rb +57 -0
- data/lib/pubid/ccsds/identifier.rb +76 -0
- data/lib/pubid/ccsds/identifiers/base.rb +41 -0
- data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +70 -0
- data/lib/pubid/ccsds/identifiers/corrigendum.rb +40 -0
- data/lib/pubid/ccsds/identifiers.rb +10 -0
- data/lib/pubid/ccsds/parser.rb +73 -0
- data/lib/pubid/ccsds/single_identifier.rb +77 -0
- data/lib/pubid/ccsds/supplement_identifier.rb +37 -0
- data/lib/pubid/ccsds/urn_generator.rb +115 -0
- data/lib/pubid/ccsds/urn_parser.rb +20 -0
- data/lib/pubid/ccsds.rb +64 -0
- data/lib/pubid/cen_cenelec/builder.rb +362 -0
- data/lib/pubid/cen_cenelec/identifier.rb +38 -0
- data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +45 -0
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +19 -0
- data/lib/pubid/cen_cenelec/identifiers/base.rb +34 -0
- data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +29 -0
- data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +40 -0
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +20 -0
- data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +99 -0
- data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +50 -0
- data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +29 -0
- data/lib/pubid/cen_cenelec/identifiers/fragment.rb +18 -0
- data/lib/pubid/cen_cenelec/identifiers/guide.rb +27 -0
- data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +36 -0
- data/lib/pubid/cen_cenelec/identifiers.rb +32 -0
- data/lib/pubid/cen_cenelec/parser.rb +144 -0
- data/lib/pubid/cen_cenelec/renderer.rb +261 -0
- data/lib/pubid/cen_cenelec/single_identifier.rb +49 -0
- data/lib/pubid/cen_cenelec/supplement_identifier.rb +47 -0
- data/lib/pubid/cen_cenelec/urn_generator.rb +129 -0
- data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
- data/lib/pubid/cen_cenelec.rb +208 -0
- data/lib/pubid/cie/builder.rb +524 -0
- data/lib/pubid/cie/components/language.rb +58 -0
- data/lib/pubid/cie/identifier.rb +33 -0
- data/lib/pubid/cie/identifiers/bundle.rb +50 -0
- data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
- data/lib/pubid/cie/identifiers/conference.rb +37 -0
- data/lib/pubid/cie/identifiers/corrigendum.rb +34 -0
- data/lib/pubid/cie/identifiers/dual_published.rb +41 -0
- data/lib/pubid/cie/identifiers/identical.rb +64 -0
- data/lib/pubid/cie/identifiers/joint_published.rb +52 -0
- data/lib/pubid/cie/identifiers/proceedings.rb +41 -0
- data/lib/pubid/cie/identifiers/standard.rb +93 -0
- data/lib/pubid/cie/identifiers/supplement.rb +47 -0
- data/lib/pubid/cie/identifiers/tutorial_bundle.rb +24 -0
- data/lib/pubid/cie/identifiers.rb +19 -0
- data/lib/pubid/cie/parser.rb +396 -0
- data/lib/pubid/cie/single_identifier.rb +69 -0
- data/lib/pubid/cie/supplement_identifier.rb +39 -0
- data/lib/pubid/cie/urn_generator.rb +126 -0
- data/lib/pubid/cie/urn_parser.rb +28 -0
- data/lib/pubid/cie.rb +83 -0
- data/lib/pubid/components/adoption.rb +104 -0
- data/lib/pubid/components/code.rb +47 -0
- data/lib/pubid/components/date.rb +72 -0
- data/lib/pubid/components/edition.rb +35 -0
- data/lib/pubid/components/iteration.rb +32 -0
- data/lib/pubid/components/language.rb +39 -0
- data/lib/pubid/components/locality.rb +19 -0
- data/lib/pubid/components/publisher.rb +39 -0
- data/lib/pubid/components/relationship.rb +151 -0
- data/lib/pubid/components/stage.rb +45 -0
- data/lib/pubid/components/supplement.rb +184 -0
- data/lib/pubid/components/type.rb +48 -0
- data/lib/pubid/components/typed_stage.rb +58 -0
- data/lib/pubid/components.rb +19 -0
- data/lib/pubid/core/pattern_doc_generator.rb +272 -0
- data/lib/pubid/core/update_codes.rb +98 -0
- data/lib/pubid/core.rb +8 -0
- data/lib/pubid/csa/builder.rb +671 -0
- data/lib/pubid/csa/components/code.rb +9 -0
- data/lib/pubid/csa/components.rb +9 -0
- data/lib/pubid/csa/composite_identifier.rb +38 -0
- data/lib/pubid/csa/identifier.rb +570 -0
- data/lib/pubid/csa/identifiers/base.rb +10 -0
- data/lib/pubid/csa/identifiers/bundled.rb +141 -0
- data/lib/pubid/csa/identifiers/canadian_adopted.rb +82 -0
- data/lib/pubid/csa/identifiers/cec.rb +66 -0
- data/lib/pubid/csa/identifiers/combined.rb +158 -0
- data/lib/pubid/csa/identifiers/csa_adopted.rb +78 -0
- data/lib/pubid/csa/identifiers/package.rb +65 -0
- data/lib/pubid/csa/identifiers/series.rb +23 -0
- data/lib/pubid/csa/identifiers/standard.rb +10 -0
- data/lib/pubid/csa/identifiers.rb +17 -0
- data/lib/pubid/csa/parser.rb +449 -0
- data/lib/pubid/csa/renderer.rb +300 -0
- data/lib/pubid/csa/single_identifier.rb +119 -0
- data/lib/pubid/csa/urn_generator.rb +87 -0
- data/lib/pubid/csa/urn_parser.rb +33 -0
- data/lib/pubid/csa/wrapper_identifier.rb +64 -0
- data/lib/pubid/csa.rb +80 -0
- data/lib/pubid/doi/builder.rb +18 -0
- data/lib/pubid/doi/identifier.rb +49 -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 +59 -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 +88 -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 +45 -0
- data/lib/pubid/ecma/identifier.rb +147 -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 +76 -0
- data/lib/pubid/ecma/renderer.rb +67 -0
- data/lib/pubid/ecma/urn_generator.rb +46 -0
- data/lib/pubid/ecma/urn_parser.rb +51 -0
- data/lib/pubid/ecma.rb +67 -0
- data/lib/pubid/errors.rb +79 -0
- data/lib/pubid/etsi/builder.rb +142 -0
- data/lib/pubid/etsi/components/code.rb +43 -0
- data/lib/pubid/etsi/components/version.rb +32 -0
- data/lib/pubid/etsi/components.rb +10 -0
- data/lib/pubid/etsi/identifier.rb +4 -0
- data/lib/pubid/etsi/identifiers/amendment.rb +15 -0
- data/lib/pubid/etsi/identifiers/base.rb +74 -0
- data/lib/pubid/etsi/identifiers/corrigendum.rb +15 -0
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +222 -0
- data/lib/pubid/etsi/identifiers/supplement_identifier.rb +123 -0
- data/lib/pubid/etsi/identifiers.rb +13 -0
- data/lib/pubid/etsi/parser.rb +139 -0
- data/lib/pubid/etsi/renderer.rb +48 -0
- data/lib/pubid/etsi/urn_generator.rb +76 -0
- data/lib/pubid/etsi/urn_parser.rb +34 -0
- data/lib/pubid/etsi.rb +71 -0
- data/lib/pubid/export/auditor.rb +89 -0
- data/lib/pubid/export/exporter.rb +33 -0
- data/lib/pubid/export/flavor_exporter.rb +250 -0
- data/lib/pubid/export/result.rb +97 -0
- data/lib/pubid/export.rb +12 -0
- data/lib/pubid/format_detector.rb +16 -0
- data/lib/pubid/format_registry.rb +42 -0
- data/lib/pubid/gb/builder.rb +45 -0
- data/lib/pubid/gb/identifier.rb +67 -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 +47 -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 +105 -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 +102 -0
- data/lib/pubid/iala/identifier.rb +90 -0
- data/lib/pubid/iala/identifiers/advice.rb +15 -0
- data/lib/pubid/iala/identifiers/annex.rb +57 -0
- data/lib/pubid/iala/identifiers/general_assembly.rb +19 -0
- data/lib/pubid/iala/identifiers/guideline.rb +17 -0
- data/lib/pubid/iala/identifiers/letter.rb +16 -0
- data/lib/pubid/iala/identifiers/manual.rb +18 -0
- data/lib/pubid/iala/identifiers/model_course.rb +17 -0
- data/lib/pubid/iala/identifiers/recommendation.rb +17 -0
- data/lib/pubid/iala/identifiers/report.rb +16 -0
- data/lib/pubid/iala/identifiers/resolution.rb +16 -0
- data/lib/pubid/iala/identifiers/standard.rb +17 -0
- data/lib/pubid/iala/identifiers.rb +19 -0
- data/lib/pubid/iala/parser.rb +138 -0
- data/lib/pubid/iala/renderer.rb +36 -0
- data/lib/pubid/iala/urn_generator.rb +49 -0
- data/lib/pubid/iala/urn_parser.rb +67 -0
- data/lib/pubid/iala.rb +71 -0
- data/lib/pubid/iana/builder.rb +22 -0
- data/lib/pubid/iana/identifier.rb +140 -0
- data/lib/pubid/iana/identifiers/registry.rb +69 -0
- data/lib/pubid/iana/identifiers.rb +9 -0
- data/lib/pubid/iana/parser.rb +38 -0
- data/lib/pubid/iana/renderer.rb +32 -0
- data/lib/pubid/iana/urn_generator.rb +19 -0
- data/lib/pubid/iana/urn_parser.rb +24 -0
- data/lib/pubid/iana.rb +69 -0
- data/lib/pubid/identifier.rb +1118 -0
- data/lib/pubid/identifier_metadata.rb +148 -0
- data/lib/pubid/idf/builder.rb +82 -0
- data/lib/pubid/idf/identifier.rb +79 -0
- data/lib/pubid/idf/identifiers/amendment.rb +28 -0
- data/lib/pubid/idf/identifiers/corrigendum.rb +28 -0
- data/lib/pubid/idf/identifiers/international_standard.rb +124 -0
- data/lib/pubid/idf/identifiers/reviewed_method.rb +101 -0
- data/lib/pubid/idf/identifiers.rb +13 -0
- data/lib/pubid/idf/parser.rb +144 -0
- data/lib/pubid/idf/renderer.rb +84 -0
- data/lib/pubid/idf/single_identifier.rb +19 -0
- data/lib/pubid/idf/supplement_identifier.rb +35 -0
- data/lib/pubid/idf/urn_generator.rb +49 -0
- data/lib/pubid/idf/urn_parser.rb +25 -0
- data/lib/pubid/idf.rb +89 -0
- data/lib/pubid/iec/builder.rb +458 -0
- data/lib/pubid/iec/components/code.rb +36 -0
- data/lib/pubid/iec/components/consolidated_amendment.rb +59 -0
- data/lib/pubid/iec/components/publisher.rb +35 -0
- data/lib/pubid/iec/components/sheet.rb +32 -0
- data/lib/pubid/iec/components/trf_info.rb +38 -0
- data/lib/pubid/iec/components/vap_suffix.rb +41 -0
- data/lib/pubid/iec/components.rb +14 -0
- data/lib/pubid/iec/identifier.rb +341 -0
- data/lib/pubid/iec/identifiers/amendment.rb +97 -0
- data/lib/pubid/iec/identifiers/base.rb +54 -0
- data/lib/pubid/iec/identifiers/component_specification.rb +29 -0
- data/lib/pubid/iec/identifiers/conformity_assessment.rb +28 -0
- data/lib/pubid/iec/identifiers/consolidated_identifier.rb +85 -0
- data/lib/pubid/iec/identifiers/corrigendum.rb +93 -0
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +148 -0
- data/lib/pubid/iec/identifiers/guide.rb +86 -0
- data/lib/pubid/iec/identifiers/international_standard.rb +162 -0
- data/lib/pubid/iec/identifiers/interpretation_sheet.rb +103 -0
- data/lib/pubid/iec/identifiers/operational_document.rb +29 -0
- data/lib/pubid/iec/identifiers/publicly_available_specification.rb +88 -0
- data/lib/pubid/iec/identifiers/sheet_identifier.rb +68 -0
- data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +30 -0
- data/lib/pubid/iec/identifiers/systems_reference_document.rb +29 -0
- data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
- data/lib/pubid/iec/identifiers/technical_report.rb +114 -0
- data/lib/pubid/iec/identifiers/technical_specification.rb +114 -0
- data/lib/pubid/iec/identifiers/technology_report.rb +28 -0
- data/lib/pubid/iec/identifiers/test_report_form.rb +35 -0
- data/lib/pubid/iec/identifiers/vap_identifier.rb +76 -0
- data/lib/pubid/iec/identifiers/white_paper.rb +29 -0
- data/lib/pubid/iec/identifiers/working_document.rb +62 -0
- data/lib/pubid/iec/identifiers.rb +31 -0
- data/lib/pubid/iec/parser.rb +443 -0
- data/lib/pubid/iec/renderer.rb +267 -0
- data/lib/pubid/iec/rendering_style.rb +113 -0
- data/lib/pubid/iec/single_identifier.rb +72 -0
- data/lib/pubid/iec/supplement_identifier.rb +178 -0
- data/lib/pubid/iec/urn_generator.rb +245 -0
- data/lib/pubid/iec/urn_parser.rb +128 -0
- data/lib/pubid/iec.rb +64 -0
- data/lib/pubid/ieee/aiee/builder.rb +85 -0
- data/lib/pubid/ieee/aiee/identifier.rb +89 -0
- data/lib/pubid/ieee/aiee/parser.rb +130 -0
- data/lib/pubid/ieee/aiee.rb +11 -0
- data/lib/pubid/ieee/builder.rb +1554 -0
- data/lib/pubid/ieee/compaction.rb +121 -0
- data/lib/pubid/ieee/components/code.rb +110 -0
- data/lib/pubid/ieee/components/draft.rb +147 -0
- data/lib/pubid/ieee/components/relationship.rb +13 -0
- data/lib/pubid/ieee/components/typed_stage.rb +100 -0
- data/lib/pubid/ieee/identifier.rb +5 -0
- data/lib/pubid/ieee/identifiers/adopted_standard.rb +81 -0
- data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
- data/lib/pubid/ieee/identifiers/base.rb +384 -0
- data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
- data/lib/pubid/ieee/identifiers/conformance_identifier.rb +29 -0
- data/lib/pubid/ieee/identifiers/corrigendum.rb +40 -0
- data/lib/pubid/ieee/identifiers/csa_dual_published.rb +62 -0
- data/lib/pubid/ieee/identifiers/dual_identifier.rb +14 -0
- data/lib/pubid/ieee/identifiers/dual_published.rb +79 -0
- data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +115 -0
- data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +48 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +223 -0
- data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +85 -0
- data/lib/pubid/ieee/identifiers/nesc/base.rb +127 -0
- data/lib/pubid/ieee/identifiers/nesc/draft.rb +43 -0
- data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
- data/lib/pubid/ieee/identifiers/nesc/handbook.rb +43 -0
- data/lib/pubid/ieee/identifiers/nesc/redline.rb +35 -0
- data/lib/pubid/ieee/identifiers/nesc/standard.rb +41 -0
- data/lib/pubid/ieee/identifiers/nesc.rb +16 -0
- data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +14 -0
- data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +49 -0
- data/lib/pubid/ieee/identifiers/redlined_standard.rb +26 -0
- data/lib/pubid/ieee/identifiers/si_standard.rb +38 -0
- data/lib/pubid/ieee/identifiers/standard.rb +44 -0
- data/lib/pubid/ieee/identifiers/supplement_identifier.rb +42 -0
- data/lib/pubid/ieee/identifiers.rb +34 -0
- data/lib/pubid/ieee/ire/builder.rb +62 -0
- data/lib/pubid/ieee/ire/identifier.rb +73 -0
- data/lib/pubid/ieee/ire/parser.rb +91 -0
- data/lib/pubid/ieee/ire.rb +11 -0
- data/lib/pubid/ieee/nesc/builder.rb +114 -0
- data/lib/pubid/ieee/nesc/parser.rb +155 -0
- data/lib/pubid/ieee/nesc.rb +10 -0
- data/lib/pubid/ieee/parser.rb +1644 -0
- data/lib/pubid/ieee/pre_parser.rb +301 -0
- data/lib/pubid/ieee/renderer.rb +408 -0
- data/lib/pubid/ieee/typed_stages.rb +183 -0
- data/lib/pubid/ieee/urn_generator.rb +215 -0
- data/lib/pubid/ieee/urn_parser.rb +34 -0
- data/lib/pubid/ieee.rb +163 -0
- data/lib/pubid/ieee_debug.rb +30 -0
- data/lib/pubid/ietf/builder.rb +78 -0
- data/lib/pubid/ietf/identifier.rb +5 -0
- data/lib/pubid/ietf/identifiers/base.rb +72 -0
- data/lib/pubid/ietf/identifiers/bcp.rb +36 -0
- data/lib/pubid/ietf/identifiers/fyi.rb +36 -0
- data/lib/pubid/ietf/identifiers/internet_draft.rb +45 -0
- data/lib/pubid/ietf/identifiers/rfc.rb +27 -0
- data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
- data/lib/pubid/ietf/identifiers/std.rb +36 -0
- data/lib/pubid/ietf/identifiers.rb +14 -0
- data/lib/pubid/ietf/parser.rb +61 -0
- data/lib/pubid/ietf/renderer.rb +64 -0
- data/lib/pubid/ietf/urn_generator.rb +37 -0
- data/lib/pubid/ietf/urn_parser.rb +43 -0
- data/lib/pubid/ietf.rb +85 -0
- data/lib/pubid/iho/builder.rb +37 -0
- data/lib/pubid/iho/identifier.rb +7 -0
- data/lib/pubid/iho/identifiers/base.rb +75 -0
- data/lib/pubid/iho/identifiers/bibliographic.rb +16 -0
- data/lib/pubid/iho/identifiers/circular_letter.rb +15 -0
- data/lib/pubid/iho/identifiers/miscellaneous.rb +16 -0
- data/lib/pubid/iho/identifiers/publication.rb +15 -0
- data/lib/pubid/iho/identifiers/standard.rb +15 -0
- data/lib/pubid/iho/identifiers.rb +13 -0
- data/lib/pubid/iho/parser.rb +68 -0
- data/lib/pubid/iho/renderer.rb +30 -0
- data/lib/pubid/iho/urn_generator.rb +29 -0
- data/lib/pubid/iho/urn_parser.rb +58 -0
- data/lib/pubid/iho.rb +77 -0
- data/lib/pubid/isbn/builder.rb +44 -0
- data/lib/pubid/isbn/check_digit.rb +53 -0
- data/lib/pubid/isbn/identifier.rb +81 -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 +316 -0
- data/lib/pubid/iso/bundled_identifier.rb +138 -0
- data/lib/pubid/iso/combined_identifier.rb +24 -0
- data/lib/pubid/iso/components/code.rb +24 -0
- data/lib/pubid/iso/components/publisher.rb +62 -0
- data/lib/pubid/iso/components.rb +10 -0
- data/lib/pubid/iso/format_resolver.rb +45 -0
- data/lib/pubid/iso/identifier.rb +318 -0
- data/lib/pubid/iso/identifiers/addendum.rb +107 -0
- data/lib/pubid/iso/identifiers/amendment.rb +132 -0
- data/lib/pubid/iso/identifiers/corrigendum.rb +108 -0
- data/lib/pubid/iso/identifiers/data.rb +75 -0
- data/lib/pubid/iso/identifiers/directives.rb +65 -0
- data/lib/pubid/iso/identifiers/directives_supplement.rb +148 -0
- data/lib/pubid/iso/identifiers/extract.rb +30 -0
- data/lib/pubid/iso/identifiers/guide.rb +99 -0
- data/lib/pubid/iso/identifiers/international_standard.rb +168 -0
- data/lib/pubid/iso/identifiers/international_standardized_profile.rb +94 -0
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +95 -0
- data/lib/pubid/iso/identifiers/pas.rb +93 -0
- data/lib/pubid/iso/identifiers/recommendation.rb +45 -0
- data/lib/pubid/iso/identifiers/supplement.rb +95 -0
- data/lib/pubid/iso/identifiers/tc_document.rb +137 -0
- data/lib/pubid/iso/identifiers/technical_report.rb +103 -0
- data/lib/pubid/iso/identifiers/technical_specification.rb +102 -0
- data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +95 -0
- data/lib/pubid/iso/identifiers.rb +32 -0
- data/lib/pubid/iso/normalizer.rb +89 -0
- data/lib/pubid/iso/parser.rb +534 -0
- data/lib/pubid/iso/rendering_style.rb +120 -0
- data/lib/pubid/iso/single_identifier.rb +60 -0
- data/lib/pubid/iso/supplement_identifier.rb +53 -0
- data/lib/pubid/iso/urn_generator.rb +313 -0
- data/lib/pubid/iso/urn_parser.rb +442 -0
- data/lib/pubid/iso/utilities.rb +86 -0
- data/lib/pubid/iso.rb +236 -0
- data/lib/pubid/itu/builder.rb +360 -0
- data/lib/pubid/itu/components/code.rb +84 -0
- data/lib/pubid/itu/components/designation.rb +35 -0
- data/lib/pubid/itu/components/sector.rb +46 -0
- data/lib/pubid/itu/components/series.rb +25 -0
- data/lib/pubid/itu/components.rb +12 -0
- data/lib/pubid/itu/i18n.rb +9 -0
- data/lib/pubid/itu/i18n.yaml +30 -0
- data/lib/pubid/itu/identifier.rb +4 -0
- data/lib/pubid/itu/identifiers/addendum.rb +15 -0
- data/lib/pubid/itu/identifiers/amendment.rb +19 -0
- data/lib/pubid/itu/identifiers/annex.rb +83 -0
- 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 +482 -0
- data/lib/pubid/itu/identifiers/combined_identifier.rb +121 -0
- data/lib/pubid/itu/identifiers/corrigendum.rb +35 -0
- 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 +15 -0
- data/lib/pubid/itu/identifiers/report.rb +39 -0
- data/lib/pubid/itu/identifiers/special_publication.rb +31 -0
- data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
- data/lib/pubid/itu/identifiers/supplement.rb +149 -0
- data/lib/pubid/itu/identifiers.rb +25 -0
- data/lib/pubid/itu/model.rb +111 -0
- data/lib/pubid/itu/parser.rb +679 -0
- data/lib/pubid/itu/urn_generator.rb +135 -0
- data/lib/pubid/itu/urn_parser.rb +31 -0
- data/lib/pubid/itu.rb +78 -0
- data/lib/pubid/jcgm/builder.rb +106 -0
- data/lib/pubid/jcgm/components/publisher.rb +20 -0
- data/lib/pubid/jcgm/components.rb +9 -0
- data/lib/pubid/jcgm/identifier.rb +21 -0
- data/lib/pubid/jcgm/identifiers/amendment.rb +24 -0
- data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
- data/lib/pubid/jcgm/identifiers/guide.rb +21 -0
- data/lib/pubid/jcgm/identifiers/gum_guide.rb +39 -0
- data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
- data/lib/pubid/jcgm/identifiers.rb +13 -0
- data/lib/pubid/jcgm/parser.rb +151 -0
- data/lib/pubid/jcgm/renderer.rb +89 -0
- data/lib/pubid/jcgm/single_identifier.rb +118 -0
- data/lib/pubid/jcgm/supplement_identifier.rb +51 -0
- data/lib/pubid/jcgm/urn_generator.rb +116 -0
- data/lib/pubid/jcgm/urn_parser.rb +177 -0
- data/lib/pubid/jcgm.rb +86 -0
- data/lib/pubid/jis/builder.rb +116 -0
- data/lib/pubid/jis/identifier.rb +194 -0
- data/lib/pubid/jis/identifiers/amendment.rb +16 -0
- data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
- data/lib/pubid/jis/identifiers/explanation.rb +22 -0
- data/lib/pubid/jis/identifiers/japanese_industrial_standard.rb +16 -0
- data/lib/pubid/jis/identifiers/standard.rb +28 -0
- data/lib/pubid/jis/identifiers/technical_report.rb +32 -0
- data/lib/pubid/jis/identifiers/technical_specification.rb +32 -0
- data/lib/pubid/jis/identifiers.rb +17 -0
- data/lib/pubid/jis/parser.rb +135 -0
- data/lib/pubid/jis/renderer.rb +69 -0
- data/lib/pubid/jis/single_identifier.rb +31 -0
- data/lib/pubid/jis/supplement_identifier.rb +50 -0
- data/lib/pubid/jis/urn_generator.rb +25 -0
- data/lib/pubid/jis/urn_parser.rb +23 -0
- data/lib/pubid/jis.rb +69 -0
- data/lib/pubid/lutaml/no_store_registration.rb +30 -0
- data/lib/pubid/nist/builder.rb +481 -0
- data/lib/pubid/nist/caster.rb +1234 -0
- data/lib/pubid/nist/circular_supplement_builder.rb +293 -0
- data/lib/pubid/nist/components/code.rb +27 -0
- data/lib/pubid/nist/components/edition.rb +134 -0
- data/lib/pubid/nist/components/issue_number.rb +28 -0
- data/lib/pubid/nist/components/part.rb +77 -0
- data/lib/pubid/nist/components/stage.rb +53 -0
- data/lib/pubid/nist/components/supplement.rb +191 -0
- data/lib/pubid/nist/components/translation.rb +42 -0
- data/lib/pubid/nist/components/update.rb +103 -0
- data/lib/pubid/nist/components/version.rb +35 -0
- data/lib/pubid/nist/components/volume.rb +32 -0
- data/lib/pubid/nist/components.rb +18 -0
- data/lib/pubid/nist/configuration.rb +87 -0
- data/lib/pubid/nist/identifier.rb +8 -0
- data/lib/pubid/nist/identifiers/base.rb +744 -0
- data/lib/pubid/nist/identifiers/circular.rb +80 -0
- data/lib/pubid/nist/identifiers/circular_supplement.rb +60 -0
- data/lib/pubid/nist/identifiers/commercial_standard.rb +42 -0
- data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +58 -0
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +69 -0
- data/lib/pubid/nist/identifiers/crpl_report.rb +138 -0
- data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +95 -0
- data/lib/pubid/nist/identifiers/grant_contractor_report.rb +36 -0
- data/lib/pubid/nist/identifiers/handbook.rb +58 -0
- data/lib/pubid/nist/identifiers/internal_report.rb +64 -0
- data/lib/pubid/nist/identifiers/letter_circular.rb +46 -0
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +74 -0
- data/lib/pubid/nist/identifiers/monograph.rb +80 -0
- data/lib/pubid/nist/identifiers/ncstar.rb +41 -0
- data/lib/pubid/nist/identifiers/nsrds.rb +41 -0
- data/lib/pubid/nist/identifiers/owmwp.rb +35 -0
- data/lib/pubid/nist/identifiers/report.rb +77 -0
- data/lib/pubid/nist/identifiers/special_publication.rb +46 -0
- data/lib/pubid/nist/identifiers/technical_note.rb +91 -0
- data/lib/pubid/nist/identifiers.rb +33 -0
- data/lib/pubid/nist/parser.rb +752 -0
- data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
- data/lib/pubid/nist/preprocessor.rb +443 -0
- data/lib/pubid/nist/renderer.rb +43 -0
- data/lib/pubid/nist/router.rb +149 -0
- data/lib/pubid/nist/series/base.rb +58 -0
- data/lib/pubid/nist/series/crpl.rb +13 -0
- data/lib/pubid/nist/series/fips.rb +14 -0
- data/lib/pubid/nist/series/ir.rb +57 -0
- data/lib/pubid/nist/series/letter_preserving.rb +15 -0
- data/lib/pubid/nist/series/mono.rb +19 -0
- data/lib/pubid/nist/series/ncstar.rb +20 -0
- data/lib/pubid/nist/series.rb +49 -0
- data/lib/pubid/nist/supplement_identifier.rb +84 -0
- data/lib/pubid/nist/urn_generator.rb +133 -0
- data/lib/pubid/nist/urn_parser.rb +67 -0
- data/lib/pubid/nist.rb +138 -0
- data/lib/pubid/oasis/builder.rb +79 -0
- data/lib/pubid/oasis/identifier.rb +160 -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 +79 -0
- data/lib/pubid/ogc/builder.rb +33 -0
- data/lib/pubid/ogc/identifier.rb +81 -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 +270 -0
- data/lib/pubid/oiml/components/code.rb +37 -0
- data/lib/pubid/oiml/components.rb +9 -0
- data/lib/pubid/oiml/identifier.rb +64 -0
- data/lib/pubid/oiml/identifiers/amendment.rb +13 -0
- data/lib/pubid/oiml/identifiers/annex.rb +29 -0
- data/lib/pubid/oiml/identifiers/basic_publication.rb +15 -0
- data/lib/pubid/oiml/identifiers/bulletin.rb +137 -0
- data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
- data/lib/pubid/oiml/identifiers/document.rb +15 -0
- data/lib/pubid/oiml/identifiers/errata.rb +15 -0
- data/lib/pubid/oiml/identifiers/expert_report.rb +15 -0
- data/lib/pubid/oiml/identifiers/guide.rb +15 -0
- data/lib/pubid/oiml/identifiers/recommendation.rb +15 -0
- data/lib/pubid/oiml/identifiers/seminar_report.rb +15 -0
- data/lib/pubid/oiml/identifiers/vocabulary.rb +15 -0
- data/lib/pubid/oiml/identifiers.rb +20 -0
- data/lib/pubid/oiml/parser.rb +274 -0
- data/lib/pubid/oiml/renderer.rb +232 -0
- data/lib/pubid/oiml/single_identifier.rb +113 -0
- data/lib/pubid/oiml/supplement_identifier.rb +88 -0
- data/lib/pubid/oiml/urn_generator.rb +78 -0
- data/lib/pubid/oiml/urn_parser.rb +39 -0
- data/lib/pubid/oiml.rb +81 -0
- data/lib/pubid/omg/builder.rb +19 -0
- data/lib/pubid/omg/identifier.rb +47 -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/parser/common_parse_methods.rb +13 -0
- data/lib/pubid/parser/common_parse_rules.rb +56 -0
- data/lib/pubid/parser/grammar.rb +74 -0
- data/lib/pubid/parser.rb +9 -0
- data/lib/pubid/parsers/base.rb +11 -0
- data/lib/pubid/parsers/mr_string.rb +206 -0
- data/lib/pubid/plateau/builder.rb +54 -0
- data/lib/pubid/plateau/identifier.rb +4 -0
- data/lib/pubid/plateau/identifiers/annex.rb +16 -0
- data/lib/pubid/plateau/identifiers/base.rb +55 -0
- data/lib/pubid/plateau/identifiers/handbook.rb +28 -0
- data/lib/pubid/plateau/identifiers/technical_report.rb +16 -0
- data/lib/pubid/plateau/identifiers.rb +11 -0
- data/lib/pubid/plateau/parser.rb +73 -0
- data/lib/pubid/plateau/renderer.rb +51 -0
- data/lib/pubid/plateau/supplement_identifier.rb +68 -0
- data/lib/pubid/plateau/urn_generator.rb +29 -0
- data/lib/pubid/plateau/urn_parser.rb +43 -0
- data/lib/pubid/plateau.rb +82 -0
- data/lib/pubid/prefixes_support.rb +51 -0
- data/lib/pubid/renderers/annotator.rb +233 -0
- data/lib/pubid/renderers/base.rb +66 -0
- data/lib/pubid/renderers/directives_renderer.rb +75 -0
- data/lib/pubid/renderers/guide_renderer.rb +26 -0
- data/lib/pubid/renderers/human_readable.rb +83 -0
- data/lib/pubid/renderers/iwa_renderer.rb +20 -0
- data/lib/pubid/renderers/mr_string.rb +64 -0
- data/lib/pubid/renderers/supplement_renderer.rb +36 -0
- data/lib/pubid/renderers/urn.rb +11 -0
- data/lib/pubid/renderers.rb +15 -0
- data/lib/pubid/rendering/context.rb +168 -0
- data/lib/pubid/rendering/date.rb +27 -0
- data/lib/pubid/rendering/language.rb +21 -0
- data/lib/pubid/rendering/numbering.rb +42 -0
- data/lib/pubid/rendering/publisher.rb +25 -0
- data/lib/pubid/rendering/stage.rb +38 -0
- data/lib/pubid/rendering/supplement.rb +46 -0
- data/lib/pubid/rendering.rb +13 -0
- data/lib/pubid/sae/builder.rb +32 -0
- data/lib/pubid/sae/components/code.rb +9 -0
- data/lib/pubid/sae/components/date.rb +27 -0
- data/lib/pubid/sae/components/type.rb +23 -0
- data/lib/pubid/sae/components.rb +11 -0
- data/lib/pubid/sae/identifier.rb +4 -0
- data/lib/pubid/sae/identifiers/base.rb +47 -0
- data/lib/pubid/sae/identifiers.rb +8 -0
- data/lib/pubid/sae/parser.rb +55 -0
- data/lib/pubid/sae/renderer.rb +36 -0
- data/lib/pubid/sae/urn_generator.rb +30 -0
- data/lib/pubid/sae/urn_parser.rb +36 -0
- data/lib/pubid/sae.rb +66 -0
- data/lib/pubid/tgpp/builder.rb +41 -0
- data/lib/pubid/tgpp/identifier.rb +107 -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 +78 -0
- data/lib/pubid/tgpp/renderer.rb +52 -0
- data/lib/pubid/tgpp/urn_generator.rb +39 -0
- data/lib/pubid/tgpp/urn_parser.rb +30 -0
- data/lib/pubid/tgpp.rb +83 -0
- data/lib/pubid/type_resolver.rb +59 -0
- data/lib/pubid/un/builder.rb +42 -0
- data/lib/pubid/un/identifier.rb +40 -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/urn_generator/base.rb +110 -0
- data/lib/pubid/urn_parser/base.rb +81 -0
- data/lib/pubid/urn_parser/errors.rb +16 -0
- data/lib/pubid/urn_parser.rb +14 -0
- data/lib/pubid/utils/string_normalizer.rb +196 -0
- data/lib/pubid/utils.rb +7 -0
- data/lib/pubid/version.rb +3 -1
- data/lib/pubid/w3c/builder.rb +55 -0
- data/lib/pubid/w3c/identifier.rb +130 -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 +66 -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 +81 -0
- data/lib/pubid.rb +551 -13
- data/lib/tasks/docs.rake +37 -0
- data/lib/tasks/export.rake +39 -0
- data/lib/tasks/website-data.json +7546 -0
- metadata +875 -171
- data/lib/pubid/registry.rb +0 -30
|
@@ -0,0 +1,1554 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ieee
|
|
5
|
+
# Builder class for constructing IEEE identifier scheme from parsed data
|
|
6
|
+
# Single Responsibility: Transform parsed data into identifier objects
|
|
7
|
+
class Builder
|
|
8
|
+
attr_accessor :original_input
|
|
9
|
+
attr_reader :identifier_class
|
|
10
|
+
|
|
11
|
+
def initialize(identifier_class = Identifier)
|
|
12
|
+
@identifier_class = identifier_class
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Build a scheme object from parsed data
|
|
16
|
+
# @param parsed [Hash, Array] the parsed identifier data
|
|
17
|
+
# @return [identifier] the constructed identifier object
|
|
18
|
+
def build(parsed)
|
|
19
|
+
# Parslet returns a top-level *array* of hashes when a repeated capture
|
|
20
|
+
# (e.g. the two subparts in "7.4-3-2") stops the sibling captures from
|
|
21
|
+
# hash-merging. The dispatch checks below need hash access, so read them
|
|
22
|
+
# off a merged view (`d`); build_single_identifier re-handles the array
|
|
23
|
+
# itself (preserving every subpart), so it still gets the original.
|
|
24
|
+
d = parsed.is_a?(Array) ? merge_parsed_array(parsed) : parsed
|
|
25
|
+
|
|
26
|
+
# Handle CSA dual published patterns
|
|
27
|
+
if d[:ieee_portion] && d[:csa_portion]
|
|
28
|
+
return build_csa_dual_published(parsed)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Handle the historical IEEE/IPCEA cable designation (S-135)
|
|
32
|
+
if d[:s_number]
|
|
33
|
+
return build_s_designation(parsed)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Handle combined AIEE identifiers (from "Nos X and Y" preprocessing)
|
|
37
|
+
if d[:first_aiee] && d[:second_aiee]
|
|
38
|
+
return build_combined_aiee(parsed)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Handle dual published patterns
|
|
42
|
+
if d[:first] && d[:second]
|
|
43
|
+
return build_dual_published(parsed)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Handle IEC/IEEE copublished patterns
|
|
47
|
+
if d[:content]
|
|
48
|
+
return build_iec_ieee_copublished(parsed)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Handle NESC identifiers (National Electrical Safety Code)
|
|
52
|
+
if d[:nesc]
|
|
53
|
+
nesc_builder = Nesc::Builder.new
|
|
54
|
+
return nesc_builder.build(d[:nesc])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Handle AIEE identifiers (American Institute of Electrical Engineers)
|
|
58
|
+
if d[:aiee]
|
|
59
|
+
aiee_builder = Aiee::Builder.new
|
|
60
|
+
return aiee_builder.build(d[:aiee])
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Handle IRE identifiers (Institute of Radio Engineers)
|
|
64
|
+
if d[:ire]
|
|
65
|
+
ire_builder = Ire::Builder.new
|
|
66
|
+
return ire_builder.build(d[:ire])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Handle IEEE/ASTM SI/PSI identifiers (Système International)
|
|
70
|
+
if d[:si_type]
|
|
71
|
+
return build_si_psi_identifier(parsed)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Handle single identifier
|
|
75
|
+
build_single_identifier(parsed)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# Build IEC/IEEE copublished identifier
|
|
81
|
+
def build_iec_ieee_copublished(parsed)
|
|
82
|
+
content = extract_value(parsed[:content])
|
|
83
|
+
|
|
84
|
+
# Parse the content to extract components
|
|
85
|
+
copublished_number = nil
|
|
86
|
+
draft_info = nil
|
|
87
|
+
iec_year = nil
|
|
88
|
+
date_info = nil
|
|
89
|
+
|
|
90
|
+
if content
|
|
91
|
+
# Extract copublished number (everything before IEC: or comma or parenthesis)
|
|
92
|
+
copublished_number = if content.include?("IEC:")
|
|
93
|
+
content.split(" IEC:").first.strip
|
|
94
|
+
elsif content.include?(", ")
|
|
95
|
+
content.split(", ").first.strip
|
|
96
|
+
elsif content.include?(" (")
|
|
97
|
+
content.split(" (").first.strip
|
|
98
|
+
else
|
|
99
|
+
content.strip
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Extract draft info if present
|
|
103
|
+
if copublished_number.include?("/D")
|
|
104
|
+
parts = copublished_number.split("/D")
|
|
105
|
+
copublished_number = parts[0]
|
|
106
|
+
draft_info = "/D#{parts[1] || ''}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Extract IEC year if present
|
|
110
|
+
if content.include?("IEC:")
|
|
111
|
+
iec_part = content.split("IEC:")[1]
|
|
112
|
+
if iec_part
|
|
113
|
+
iec_year = iec_part.split.first
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Extract date info if present
|
|
118
|
+
if content.include?(" (")
|
|
119
|
+
date_part = content.split(" (")[1]
|
|
120
|
+
if date_part&.include?(")")
|
|
121
|
+
date_info = date_part.split(")")[0]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Identifiers::IecIeeeCopublished.new(
|
|
127
|
+
draft_info: draft_info,
|
|
128
|
+
iec_year: iec_year,
|
|
129
|
+
date_info: date_info,
|
|
130
|
+
**copublished_structured(copublished_number),
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Decompose an IEC/IEEE `copublished_number` into the split index columns
|
|
135
|
+
# that reconstruct it losslessly (IecIeeeCopublished#copublished_number is
|
|
136
|
+
# the inverse). First peel a trailing *publication year* (19xx/20xx with
|
|
137
|
+
# its `-`/`:` separator) into `year`/`year_sep` — a bare 4-digit strip
|
|
138
|
+
# would wrongly eat a part like "60076.57-1202" (1202 is a part, not a
|
|
139
|
+
# year). Then tokenise the remainder on `.`/`-`, keeping each part's
|
|
140
|
+
# leading separator (a single code mixes them). So `number` narrows to the
|
|
141
|
+
# bucket, `parts` matches within it, and `separators` renders it back.
|
|
142
|
+
# `year_sep` is omitted when the default `-`. Returns empty for no number.
|
|
143
|
+
def copublished_structured(copublished_number)
|
|
144
|
+
return {} if copublished_number.nil? || copublished_number.empty?
|
|
145
|
+
|
|
146
|
+
remainder, year, year_sep = peel_copublished_year(copublished_number)
|
|
147
|
+
tokens = remainder.scan(/\A[^.\-]+|[.\-][^.\-]+/)
|
|
148
|
+
{ number: tokens.shift }
|
|
149
|
+
.merge(copublished_parts(tokens))
|
|
150
|
+
.merge(copublished_year(year, year_sep))
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# The `parts`/`separators` columns from the tokens after the number.
|
|
154
|
+
def copublished_parts(tokens)
|
|
155
|
+
return {} if tokens.empty?
|
|
156
|
+
|
|
157
|
+
{ parts: tokens.map { |t| t[1..] }, separators: tokens.map { |t| t[0] } }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# The `year`/`year_sep` columns; `year_sep` is omitted when the default `-`.
|
|
161
|
+
def copublished_year(year, year_sep)
|
|
162
|
+
return {} unless year
|
|
163
|
+
|
|
164
|
+
year_sep == "-" ? { year: year } : { year: year, year_sep: year_sep }
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Peel a trailing publication year (19xx/20xx with its `-`/`:` separator)
|
|
168
|
+
# off a copublished number, returning [remainder, year, year_sep].
|
|
169
|
+
def peel_copublished_year(copublished_number)
|
|
170
|
+
return [copublished_number, nil, nil] unless
|
|
171
|
+
copublished_number =~ /([-:])((?:19|20)\d\d)\z/
|
|
172
|
+
|
|
173
|
+
year_sep = Regexp.last_match(1)
|
|
174
|
+
year = Regexp.last_match(2)
|
|
175
|
+
trimmed = copublished_number[0...(copublished_number.length -
|
|
176
|
+
year_sep.length - year.length)]
|
|
177
|
+
[trimmed, year, year_sep]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Build dual published identifier
|
|
181
|
+
def build_dual_published(parsed)
|
|
182
|
+
first_id = build_single_identifier(parsed[:first])
|
|
183
|
+
second_id = build_single_identifier(parsed[:second])
|
|
184
|
+
|
|
185
|
+
Identifiers::DualPublished.new(
|
|
186
|
+
first_identifier: first_id,
|
|
187
|
+
second_identifier: second_id,
|
|
188
|
+
)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Build CSA dual published identifier
|
|
192
|
+
# @param parsed [Hash] parsed CSA dual published data
|
|
193
|
+
# @return [Identifiers::CsaDualPublished] CSA dual published identifier
|
|
194
|
+
def build_csa_dual_published(parsed)
|
|
195
|
+
# Build IEEE portion
|
|
196
|
+
ieee_id = build_single_identifier(parsed[:ieee_portion])
|
|
197
|
+
|
|
198
|
+
# Extract and parse CSA portion using CSA parser
|
|
199
|
+
csa_string = extract_value(parsed[:csa_portion])
|
|
200
|
+
|
|
201
|
+
# Prepend "CSA " prefix if not present (CSA parser expects this format)
|
|
202
|
+
csa_string = "CSA #{csa_string}" unless csa_string.start_with?("CSA",
|
|
203
|
+
"CAN/")
|
|
204
|
+
|
|
205
|
+
# Use CSA parser to parse the CSA portion
|
|
206
|
+
csa_id = Pubid::Csa.parse(csa_string)
|
|
207
|
+
|
|
208
|
+
Identifiers::CsaDualPublished.new(
|
|
209
|
+
ieee_identifier: ieee_id,
|
|
210
|
+
csa_identifier: csa_id,
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Build the historical IEEE/IPCEA cable designation (e.g. S-135).
|
|
215
|
+
#
|
|
216
|
+
# The "S-135" designation is modelled as a plain Standard whose code holds
|
|
217
|
+
# the whole "S-135" string as `number` (prefix nil). It is passed as the
|
|
218
|
+
# `number:` split column directly — NOT as `code:` — so it bypasses
|
|
219
|
+
# Components::Code.parse, which would peel "S" as a prefix and leave an
|
|
220
|
+
# empty number (breaking the relaton index key and the round-trip). This
|
|
221
|
+
# keeps `root.number` == "S-135" and renders the dash back verbatim.
|
|
222
|
+
#
|
|
223
|
+
# The "/IPCEA …" slash co-designation is stored verbatim in `crossref`
|
|
224
|
+
# (rendered as-is); the "(IPCEA …)" parenthetical variant flows through
|
|
225
|
+
# the normal `parenthetical_content` path.
|
|
226
|
+
def build_s_designation(parsed)
|
|
227
|
+
attributes = {
|
|
228
|
+
number: extract_value(parsed[:s_number]),
|
|
229
|
+
publisher: extract_value(parsed[:publisher]) || "IEEE",
|
|
230
|
+
typed_stage: Pubid::Ieee.locate_stage("Std"),
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if parsed[:ipcea_copub]
|
|
234
|
+
attributes[:crossref] = extract_value(parsed[:ipcea_copub])
|
|
235
|
+
end
|
|
236
|
+
handle_parameters(parsed, attributes)
|
|
237
|
+
|
|
238
|
+
Identifiers::Standard.new(**attributes)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Build single identifier
|
|
242
|
+
def build_single_identifier(parsed, building_secondary: false)
|
|
243
|
+
# Parslet can return array of hashes - merge them
|
|
244
|
+
parsed_hash = parsed.is_a?(Array) ? merge_parsed_array(parsed) : parsed
|
|
245
|
+
|
|
246
|
+
# Handle multi-numbered identifiers (cross-reference and joint standards)
|
|
247
|
+
# CRITICAL: Don't recurse when building secondary identifier to prevent infinite loop
|
|
248
|
+
if !building_secondary && parsed_hash[:primary_identifier] && (parsed_hash[:secondary_crossref] || parsed_hash[:secondary_joint])
|
|
249
|
+
return build_multi_numbered_identifier(parsed_hash)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Handle corrigendum supplements (check for base + cor_number)
|
|
253
|
+
# This enables recursive base identifier parsing like ISO/IEC Amendment
|
|
254
|
+
if parsed_hash[:base] && parsed_hash[:cor_number]
|
|
255
|
+
return build_corrigendum_supplement(parsed_hash)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Handle the flat draft + corrigendum form (relaton's `…/D-N/CorM-YYYY`,
|
|
259
|
+
# normalized to `…/Cor M-YYYY/D N`): the parser emits a top-level
|
|
260
|
+
# `corrigendum` hash alongside `draft`/number with NO `:base` subtree, so
|
|
261
|
+
# the supplement path above is skipped. Rebuild a real base standard
|
|
262
|
+
# (carrying the draft) and wrap it, so `to_s` renders correctly from a
|
|
263
|
+
# fresh parse and after a from_hash round-trip. The `!parsed_hash[:base]`
|
|
264
|
+
# guard keeps this disjoint from the nested-base branch above; a
|
|
265
|
+
# `:base` + nested-`corrigendum`-hash shape is not produced by the
|
|
266
|
+
# grammar, so it would fall through to `extract_attributes` (as before).
|
|
267
|
+
if parsed_hash[:corrigendum].is_a?(Hash) && !parsed_hash[:base]
|
|
268
|
+
return build_flat_corrigendum(parsed_hash)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Handle amendment supplements — mirrors the corrigendum path above.
|
|
272
|
+
# Every amendment the grammar produces is FLAT (a top-level `amendment`
|
|
273
|
+
# hash, no `:base`): the `amendment` rule only ever appears inline via
|
|
274
|
+
# `amendment.maybe`, so `build_flat_amendment` carries all real traffic
|
|
275
|
+
# (`IEEE Std …/Amd N-YYYY` and `ISO/IEC/IEEE 8802.x/AmdN-YYYY`). The
|
|
276
|
+
# recursive-base branch below is kept for structural parity with
|
|
277
|
+
# corrigendum (which has a dedicated `corrigendum_identifier` rule
|
|
278
|
+
# emitting a `:base` + top-level `:amd_number`-style shape); no amendment
|
|
279
|
+
# grammar rule emits it today, so it would only fire if one were added.
|
|
280
|
+
if parsed_hash[:base] && parsed_hash[:amd_number]
|
|
281
|
+
return build_amendment_supplement(parsed_hash)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
if parsed_hash[:amendment].is_a?(Hash) && !parsed_hash[:base]
|
|
285
|
+
return build_flat_amendment(parsed_hash)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Handle interpretation supplements (check for base + int_year)
|
|
289
|
+
if parsed_hash[:base] && (parsed_hash[:int_year] || parsed_hash[:interpretation])
|
|
290
|
+
return build_interpretation_supplement(parsed_hash)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# The same document with a TRAILING DATE parses FLAT — no :base subtree,
|
|
294
|
+
# just an :interpretation marker beside the number — so the branch above
|
|
295
|
+
# skipped it and determine_identifier_class built a base-less
|
|
296
|
+
# InterpretationIdentifier that dropped the number, the part and the
|
|
297
|
+
# publisher: "IEEE Std 1003.2-1992/INT, Dec. 1994 Ed." rendered as
|
|
298
|
+
# " 1003.2-1992/INT". Mirrors build_flat_corrigendum / build_flat_amendment.
|
|
299
|
+
if parsed_hash[:interpretation] && !parsed_hash[:base]
|
|
300
|
+
return build_flat_interpretation(parsed_hash)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Handle conformance supplements (check for base + conf_number)
|
|
304
|
+
if parsed_hash[:base] && parsed_hash[:conf_number]
|
|
305
|
+
return build_conformance_supplement(parsed_hash)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Handle joint development patterns from parser
|
|
309
|
+
if parsed_hash[:joint_publishers] || parsed_hash[:iso_stage]
|
|
310
|
+
return build_joint_development(parsed_hash)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
attributes = extract_attributes(parsed_hash)
|
|
314
|
+
|
|
315
|
+
# Handle relationships if present (Pattern 4)
|
|
316
|
+
if parsed_hash[:relationship_type] || parsed_hash[:relationship_clause]
|
|
317
|
+
attributes[:relationships] = build_relationships(parsed_hash)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Route to appropriate identifier class based on content
|
|
321
|
+
identifier_class = determine_identifier_class(attributes)
|
|
322
|
+
rename_supplement_keys(attributes)
|
|
323
|
+
identifier_class.new(**attributes)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Supplement wrappers (Corrigendum/Amendment/Conformance/Interpretation)
|
|
327
|
+
# store their ordinal/year under the uniform `number`/`year`, but the parse
|
|
328
|
+
# tree and class-routing above key on the distinct
|
|
329
|
+
# `cor_*`/`amd_*`/`conf_*`/`int_year` names. Translate them **after**
|
|
330
|
+
# routing, just before construction. Guards ensure a plain standard's own
|
|
331
|
+
# `number`/`year` are never overwritten (it carries none of these keys).
|
|
332
|
+
def rename_supplement_keys(attributes)
|
|
333
|
+
ordinal = attributes.delete(:cor_number) ||
|
|
334
|
+
attributes.delete(:amd_number) || attributes.delete(:conf_number)
|
|
335
|
+
attributes[:number] = ordinal if ordinal
|
|
336
|
+
year = attributes.delete(:cor_year) || attributes.delete(:amd_year) ||
|
|
337
|
+
attributes.delete(:conf_year) || attributes.delete(:int_year)
|
|
338
|
+
attributes[:year] = year if year
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Reconstruct the base identifier string from a parsed `:base` subtree
|
|
342
|
+
# (publisher/copublishers + type + number/part/subpart/year), so it can be
|
|
343
|
+
# recursively re-parsed by the supplement builders (corrigendum/amendment).
|
|
344
|
+
# @param base_data [Hash] the `:base` subtree
|
|
345
|
+
# @return [String] e.g. "IEEE Std 802.1AC-2016" or "535-2013"
|
|
346
|
+
def reconstruct_base_string(base_data)
|
|
347
|
+
base_parts = []
|
|
348
|
+
|
|
349
|
+
# Extract publisher
|
|
350
|
+
if base_data[:publishers]
|
|
351
|
+
pub_data = base_data[:publishers]
|
|
352
|
+
publisher_str = extract_value(pub_data[:publisher])
|
|
353
|
+
|
|
354
|
+
if pub_data[:copublishers] && !pub_data[:copublishers].empty?
|
|
355
|
+
copubs = pub_data[:copublishers]
|
|
356
|
+
copubs = [copubs] unless copubs.is_a?(Array)
|
|
357
|
+
copub_strs = copubs.filter_map do |cp|
|
|
358
|
+
extract_value(cp[:copublisher])
|
|
359
|
+
end
|
|
360
|
+
publisher_str += "/#{copub_strs.join('/')}" if !copub_strs.empty?
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
base_parts << publisher_str
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Extract type
|
|
367
|
+
if base_data[:type]
|
|
368
|
+
base_parts << extract_value(base_data[:type])
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Extract number with parts and year
|
|
372
|
+
# Build the complete code string: "802.1AC-2016" or "535-2013" or "C37.41-2016"
|
|
373
|
+
number_str = extract_value(base_data[:number])
|
|
374
|
+
|
|
375
|
+
# Add part if present (e.g., ".1AC" or ".41")
|
|
376
|
+
if base_data[:part]
|
|
377
|
+
part_val = extract_value(base_data[:part])
|
|
378
|
+
# Determine separator: dot for most cases, dash for some
|
|
379
|
+
separator = number_str.match?(/^[A-Z]/) ? "." : "." # Letter prefix uses dot
|
|
380
|
+
number_str += separator + part_val
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Add subpart if present
|
|
384
|
+
if base_data[:subpart]
|
|
385
|
+
subparts = base_data[:subpart]
|
|
386
|
+
subparts = [subparts] unless subparts.is_a?(Array)
|
|
387
|
+
subparts.each do |sp|
|
|
388
|
+
subpart_val = extract_value(sp)
|
|
389
|
+
number_str += ".#{subpart_val}" if subpart_val
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Add year with dash (e.g., "-2016")
|
|
394
|
+
if base_data[:year]
|
|
395
|
+
year_val = extract_value(base_data[:year])
|
|
396
|
+
number_str += "-#{year_val}"
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
base_parts << number_str
|
|
400
|
+
base_parts.join(" ")
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Build corrigendum supplement with recursive base parsing
|
|
404
|
+
# @param parsed_hash [Hash] parsed data with base and supplement info
|
|
405
|
+
# @return [Identifiers::Corrigendum] corrigendum identifier
|
|
406
|
+
def build_corrigendum_supplement(parsed_hash)
|
|
407
|
+
# Recursively parse the base identifier reconstructed from the subtree.
|
|
408
|
+
base = Identifier.parse(reconstruct_base_string(parsed_hash[:base]))
|
|
409
|
+
|
|
410
|
+
# Extract corrigendum attributes (parse-tree keys are cor_*; the
|
|
411
|
+
# identifier stores them as the uniform `number`/`year`).
|
|
412
|
+
cor_number = extract_value(parsed_hash[:cor_number])
|
|
413
|
+
cor_year = extract_value(parsed_hash[:cor_year])
|
|
414
|
+
|
|
415
|
+
# Create Corrigendum with parsed base
|
|
416
|
+
Identifiers::Corrigendum.new(
|
|
417
|
+
base: base,
|
|
418
|
+
number: cor_number,
|
|
419
|
+
year: cor_year,
|
|
420
|
+
)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# Build a Corrigendum from the flat parse tree produced by the combined
|
|
424
|
+
# `…/Cor M-YYYY/D N` form, where the corrigendum lives in a top-level
|
|
425
|
+
# `corrigendum` hash and there is no `:base` subtree. Peel the corrigendum
|
|
426
|
+
# off, build the remaining attributes into the base standard (with its
|
|
427
|
+
# draft) via the normal single-identifier path, then wrap.
|
|
428
|
+
# @param parsed_hash [Hash] flat parsed data with a :corrigendum hash
|
|
429
|
+
# @return [Identifiers::Corrigendum]
|
|
430
|
+
def build_flat_corrigendum(parsed_hash)
|
|
431
|
+
cor_data = parsed_hash[:corrigendum]
|
|
432
|
+
cor_number = extract_value(cor_data[:cor_number])
|
|
433
|
+
cor_year = extract_value(cor_data[:cor_year]) if cor_data[:cor_year]
|
|
434
|
+
|
|
435
|
+
base_hash = parsed_hash.reject { |key, _| key == :corrigendum }
|
|
436
|
+
base = build_single_identifier(base_hash)
|
|
437
|
+
|
|
438
|
+
Identifiers::Corrigendum.new(
|
|
439
|
+
base: base,
|
|
440
|
+
number: cor_number,
|
|
441
|
+
year: cor_year,
|
|
442
|
+
)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# Build an interpretation from a FLAT parse tree — the trailing-date form,
|
|
446
|
+
# where the :interpretation marker sits beside the base's own keys instead
|
|
447
|
+
# of over a :base subtree.
|
|
448
|
+
#
|
|
449
|
+
# The trailing date is the INTERPRETATION's date (an interpretation of the
|
|
450
|
+
# 1992 edition of 1003.2, issued in Dec 1994), so it goes on the wrapper;
|
|
451
|
+
# the base keeps its own `year`. That matches the nested form, whose
|
|
452
|
+
# `int_year` also lands on the wrapper.
|
|
453
|
+
# @param parsed_hash [Hash] flat parsed data carrying :interpretation
|
|
454
|
+
# @return [Identifiers::InterpretationIdentifier]
|
|
455
|
+
def build_flat_interpretation(parsed_hash)
|
|
456
|
+
int_year = extract_value(parsed_hash[:trailing_year]) if parsed_hash[:trailing_year]
|
|
457
|
+
|
|
458
|
+
base_hash = parsed_hash.reject do |key, _|
|
|
459
|
+
%i[interpretation trailing_month trailing_year].include?(key)
|
|
460
|
+
end
|
|
461
|
+
base = build_single_identifier(base_hash)
|
|
462
|
+
|
|
463
|
+
# The trailing MONTH is deliberately dropped, matching the nested form
|
|
464
|
+
# (whose `int_year` carries no month either). It was not preserved
|
|
465
|
+
# before this change, so nothing is lost; and setting it fed the URN's
|
|
466
|
+
# month_day_component, which put "Dec." — a word with a dot — into a
|
|
467
|
+
# URN segment.
|
|
468
|
+
Identifiers::InterpretationIdentifier.new(
|
|
469
|
+
base: base,
|
|
470
|
+
year: int_year,
|
|
471
|
+
)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Build amendment supplement with recursive base parsing. Mirrors
|
|
475
|
+
# {#build_corrigendum_supplement} — reconstructs the base identifier
|
|
476
|
+
# string, recursively parses it, and wraps it in an Amendment.
|
|
477
|
+
# @param parsed_hash [Hash] parsed data with base and amendment info
|
|
478
|
+
# @return [Identifiers::Amendment] amendment identifier
|
|
479
|
+
def build_amendment_supplement(parsed_hash)
|
|
480
|
+
base = Identifier.parse(reconstruct_base_string(parsed_hash[:base]))
|
|
481
|
+
|
|
482
|
+
amd_number = extract_value(parsed_hash[:amd_number])
|
|
483
|
+
amd_year = extract_value(parsed_hash[:amd_year])
|
|
484
|
+
|
|
485
|
+
Identifiers::Amendment.new(
|
|
486
|
+
base: base,
|
|
487
|
+
number: amd_number,
|
|
488
|
+
year: amd_year,
|
|
489
|
+
)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Build an Amendment from the flat parse tree produced by the common
|
|
493
|
+
# `…/Amd N-YYYY` form, where the amendment lives in a top-level
|
|
494
|
+
# `amendment` hash and there is no `:base` subtree. Peel the amendment
|
|
495
|
+
# off, build the remaining attributes into the base standard via the
|
|
496
|
+
# normal single-identifier path, then wrap. Mirrors
|
|
497
|
+
# {#build_flat_corrigendum}.
|
|
498
|
+
# @param parsed_hash [Hash] flat parsed data with an :amendment hash
|
|
499
|
+
# @return [Identifiers::Amendment]
|
|
500
|
+
def build_flat_amendment(parsed_hash)
|
|
501
|
+
amd_data = parsed_hash[:amendment]
|
|
502
|
+
amd_number = extract_value(amd_data[:amd_number])
|
|
503
|
+
amd_year = extract_value(amd_data[:amd_year]) if amd_data[:amd_year]
|
|
504
|
+
|
|
505
|
+
base_hash = parsed_hash.reject { |key, _| key == :amendment }
|
|
506
|
+
base = build_single_identifier(base_hash)
|
|
507
|
+
|
|
508
|
+
Identifiers::Amendment.new(
|
|
509
|
+
base: base,
|
|
510
|
+
number: amd_number,
|
|
511
|
+
year: amd_year,
|
|
512
|
+
)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Build interpretation supplement with recursive base parsing
|
|
516
|
+
# @param parsed_hash [Hash] parsed data with base and supplement info
|
|
517
|
+
# @return [Identifiers::InterpretationIdentifier] interpretation identifier
|
|
518
|
+
def build_interpretation_supplement(parsed_hash)
|
|
519
|
+
# Reconstruct base identifier string from parsed components (same logic as corrigendum)
|
|
520
|
+
base_parts = []
|
|
521
|
+
base_data = parsed_hash[:base]
|
|
522
|
+
|
|
523
|
+
# Extract publisher
|
|
524
|
+
if base_data[:publishers]
|
|
525
|
+
pub_data = base_data[:publishers]
|
|
526
|
+
publisher_str = extract_value(pub_data[:publisher])
|
|
527
|
+
|
|
528
|
+
if pub_data[:copublishers] && !pub_data[:copublishers].empty?
|
|
529
|
+
copubs = pub_data[:copublishers]
|
|
530
|
+
copubs = [copubs] unless copubs.is_a?(Array)
|
|
531
|
+
copub_strs = copubs.filter_map do |cp|
|
|
532
|
+
extract_value(cp[:copublisher])
|
|
533
|
+
end
|
|
534
|
+
publisher_str += "/#{copub_strs.join('/')}" if !copub_strs.empty?
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
base_parts << publisher_str
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
# Extract type
|
|
541
|
+
if base_data[:type]
|
|
542
|
+
base_parts << extract_value(base_data[:type])
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# Extract number with parts and year
|
|
546
|
+
number_str = extract_value(base_data[:number])
|
|
547
|
+
|
|
548
|
+
# Add part if present
|
|
549
|
+
if base_data[:part]
|
|
550
|
+
part_val = extract_value(base_data[:part])
|
|
551
|
+
separator = number_str.match?(/^[A-Z]/) ? "." : "."
|
|
552
|
+
number_str += separator + part_val
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# Add subpart if present
|
|
556
|
+
if base_data[:subpart]
|
|
557
|
+
subparts = base_data[:subpart]
|
|
558
|
+
subparts = [subparts] unless subparts.is_a?(Array)
|
|
559
|
+
subparts.each do |sp|
|
|
560
|
+
subpart_val = extract_value(sp)
|
|
561
|
+
number_str += ".#{subpart_val}" if subpart_val
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
# Add year with dash
|
|
566
|
+
if base_data[:year]
|
|
567
|
+
year_val = extract_value(base_data[:year])
|
|
568
|
+
number_str += "-#{year_val}"
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
base_parts << number_str
|
|
572
|
+
|
|
573
|
+
# Build base string and recursively parse it
|
|
574
|
+
base_string = base_parts.join(" ")
|
|
575
|
+
|
|
576
|
+
# Recursively parse base identifier using Base.parse
|
|
577
|
+
base = Identifier.parse(base_string)
|
|
578
|
+
|
|
579
|
+
# Extract interpretation attributes
|
|
580
|
+
int_year = extract_value(parsed_hash[:int_year])
|
|
581
|
+
|
|
582
|
+
# Create InterpretationIdentifier with parsed base (int_year -> year)
|
|
583
|
+
Identifiers::InterpretationIdentifier.new(
|
|
584
|
+
base: base,
|
|
585
|
+
year: int_year,
|
|
586
|
+
)
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# Build conformance supplement with recursive base parsing
|
|
590
|
+
# @param parsed_hash [Hash] parsed data with base and supplement info
|
|
591
|
+
# @return [Identifiers::ConformanceIdentifier] conformance identifier
|
|
592
|
+
def build_conformance_supplement(parsed_hash)
|
|
593
|
+
# Reconstruct base identifier string from parsed components (same logic as corrigendum)
|
|
594
|
+
base_parts = []
|
|
595
|
+
base_data = parsed_hash[:base]
|
|
596
|
+
|
|
597
|
+
# Extract publisher
|
|
598
|
+
if base_data[:publishers]
|
|
599
|
+
pub_data = base_data[:publishers]
|
|
600
|
+
publisher_str = extract_value(pub_data[:publisher])
|
|
601
|
+
|
|
602
|
+
if pub_data[:copublishers] && !pub_data[:copublishers].empty?
|
|
603
|
+
copubs = pub_data[:copublishers]
|
|
604
|
+
copubs = [copubs] unless copubs.is_a?(Array)
|
|
605
|
+
copub_strs = copubs.filter_map do |cp|
|
|
606
|
+
extract_value(cp[:copublisher])
|
|
607
|
+
end
|
|
608
|
+
publisher_str += "/#{copub_strs.join('/')}" if !copub_strs.empty?
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
base_parts << publisher_str
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
# Extract type
|
|
615
|
+
if base_data[:type]
|
|
616
|
+
base_parts << extract_value(base_data[:type])
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# Extract number with parts and year
|
|
620
|
+
number_str = extract_value(base_data[:number])
|
|
621
|
+
|
|
622
|
+
# Add part if present
|
|
623
|
+
if base_data[:part]
|
|
624
|
+
part_val = extract_value(base_data[:part])
|
|
625
|
+
separator = number_str.match?(/^[A-Z]/) ? "." : "."
|
|
626
|
+
number_str += separator + part_val
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
# Add subpart if present
|
|
630
|
+
if base_data[:subpart]
|
|
631
|
+
subparts = base_data[:subpart]
|
|
632
|
+
subparts = [subparts] unless subparts.is_a?(Array)
|
|
633
|
+
subparts.each do |sp|
|
|
634
|
+
subpart_val = extract_value(sp)
|
|
635
|
+
number_str += ".#{subpart_val}" if subpart_val
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# Add year with dash
|
|
640
|
+
if base_data[:year]
|
|
641
|
+
year_val = extract_value(base_data[:year])
|
|
642
|
+
number_str += "-#{year_val}"
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
base_parts << number_str
|
|
646
|
+
|
|
647
|
+
# Build base string and recursively parse it
|
|
648
|
+
base_string = base_parts.join(" ")
|
|
649
|
+
|
|
650
|
+
# Recursively parse base identifier using Base.parse
|
|
651
|
+
base = Identifier.parse(base_string)
|
|
652
|
+
|
|
653
|
+
# Extract conformance attributes
|
|
654
|
+
conf_number = extract_value(parsed_hash[:conf_number])
|
|
655
|
+
conf_year = extract_value(parsed_hash[:conf_year])
|
|
656
|
+
|
|
657
|
+
# Create ConformanceIdentifier with parsed base (conf_* -> number/year)
|
|
658
|
+
Identifiers::ConformanceIdentifier.new(
|
|
659
|
+
base: base,
|
|
660
|
+
number: conf_number,
|
|
661
|
+
year: conf_year,
|
|
662
|
+
)
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# Build joint development identifier from parsed data
|
|
666
|
+
def build_joint_development(parsed)
|
|
667
|
+
attributes = {}
|
|
668
|
+
|
|
669
|
+
# Extract publishers from joint_publishers
|
|
670
|
+
if parsed[:joint_publishers]
|
|
671
|
+
joint_pub_str = extract_value(parsed[:joint_publishers])
|
|
672
|
+
attributes[:publishers] = joint_pub_str.split("/")
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
# Build code with parts if present
|
|
676
|
+
code_parts = []
|
|
677
|
+
code_parts << extract_value(parsed[:part]) if parsed[:part]
|
|
678
|
+
|
|
679
|
+
code_str = extract_value(parsed[:number])
|
|
680
|
+
if code_str && !code_parts.empty?
|
|
681
|
+
code_str += ".#{code_parts.join('.')}"
|
|
682
|
+
end
|
|
683
|
+
attributes[:code] = code_str
|
|
684
|
+
|
|
685
|
+
# Extract year (and optional numeric month, e.g. the -MM of a historical
|
|
686
|
+
# "…-2018-05" ISO-stage date). The joint ISO/IEC rules also use the
|
|
687
|
+
# `edition` rule, whose year is captured as :edition_year (parser.rb);
|
|
688
|
+
# it is promoted to the identity only when no base :year was captured.
|
|
689
|
+
if parsed[:year]
|
|
690
|
+
attributes[:year] = extract_value(parsed[:year])
|
|
691
|
+
elsif parsed[:edition_year]
|
|
692
|
+
attributes[:year] = extract_value(parsed[:edition_year])
|
|
693
|
+
end
|
|
694
|
+
attributes[:month] = extract_value(parsed[:month]) if parsed[:month]
|
|
695
|
+
|
|
696
|
+
# Extract edition, from relaton's "/E-<n>" suffix (normalized to
|
|
697
|
+
# "Edition <n>.0"). nil-residue hand-off item 1.
|
|
698
|
+
attributes[:edition] = extract_value(parsed[:edition]) if parsed[:edition]
|
|
699
|
+
if parsed[:edition_month]
|
|
700
|
+
attributes[:edition_month] = extract_value(parsed[:edition_month])
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
# Extract draft version if present (e.g., D8 from /D8). This applies to
|
|
704
|
+
# both the ISO-led (bucket 5: "…FDIS P15289/D-3-2017") and IEEE-led
|
|
705
|
+
# forms, so it lives before the lead-party split.
|
|
706
|
+
if parsed[:draft_version]
|
|
707
|
+
draft_ver = extract_value(parsed[:draft_version])
|
|
708
|
+
# Remove leading 'D' if present since draft_version already has it
|
|
709
|
+
draft_ver = draft_ver.sub(/^D/, "") if draft_ver
|
|
710
|
+
attributes[:ieee_draft] = "D#{draft_ver}" if draft_ver
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
# Detect lead party based on pattern
|
|
714
|
+
if parsed[:iso_stage]
|
|
715
|
+
# ISO format - lead party is ISO
|
|
716
|
+
attributes[:lead_party] = "ISO"
|
|
717
|
+
attributes[:iso_stage] = extract_value(parsed[:iso_stage])
|
|
718
|
+
|
|
719
|
+
# Create typed_stage for ISO stage
|
|
720
|
+
stage_abbr = attributes[:iso_stage]
|
|
721
|
+
if stage_abbr
|
|
722
|
+
attributes[:typed_stage] =
|
|
723
|
+
Pubid::Ieee.locate_stage(stage_abbr)
|
|
724
|
+
end
|
|
725
|
+
else
|
|
726
|
+
# IEEE format - lead party is IEEE
|
|
727
|
+
attributes[:lead_party] = "IEEE"
|
|
728
|
+
|
|
729
|
+
# Mark as project (P prefix)
|
|
730
|
+
attributes[:type] = "P"
|
|
731
|
+
|
|
732
|
+
# Create typed_stage for IEEE project
|
|
733
|
+
attributes[:typed_stage] =
|
|
734
|
+
Pubid::Ieee.locate_stage("P")
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
Identifiers::JointDevelopment.new(**attributes)
|
|
738
|
+
end
|
|
739
|
+
|
|
740
|
+
# Build SI/PSI identifier from parsed data
|
|
741
|
+
# @param parsed [Hash] parsed SI/PSI data
|
|
742
|
+
# @return [Identifiers::SiStandard] SI or PSI identifier (both use same class)
|
|
743
|
+
def build_si_psi_identifier(parsed)
|
|
744
|
+
attributes = {}
|
|
745
|
+
|
|
746
|
+
# Extract SI type (SI or PSI)
|
|
747
|
+
si_type = extract_value(parsed[:si_type])
|
|
748
|
+
|
|
749
|
+
# Extract publishers (should be "IEEE/ASTM")
|
|
750
|
+
if parsed[:publishers]
|
|
751
|
+
publishers_str = extract_value(parsed[:publishers])
|
|
752
|
+
# Split by slash to get individual publishers
|
|
753
|
+
pubs = publishers_str.split("/")
|
|
754
|
+
attributes[:publisher] = pubs.first
|
|
755
|
+
attributes[:copublisher] = pubs.drop(1) if pubs.length > 1
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
# Extract number
|
|
759
|
+
attributes[:code] = extract_value(parsed[:number])
|
|
760
|
+
|
|
761
|
+
# For PSI (draft), create proper Draft component object
|
|
762
|
+
if si_type == "PSI"
|
|
763
|
+
if parsed[:draft_version]
|
|
764
|
+
draft_version = extract_value(parsed[:draft_version])
|
|
765
|
+
# Create Draft component (Lutaml::Model object)
|
|
766
|
+
attributes[:draft_obj] =
|
|
767
|
+
Components::Draft.new(version: draft_version)
|
|
768
|
+
end
|
|
769
|
+
# Set PSI typed_stage (draft stage)
|
|
770
|
+
attributes[:typed_stage] = Identifiers::SiStandard::TYPED_STAGES.find do |ts|
|
|
771
|
+
ts.abbr.include?("PSI")
|
|
772
|
+
end
|
|
773
|
+
else
|
|
774
|
+
# Set SI typed_stage (published stage)
|
|
775
|
+
attributes[:typed_stage] = Identifiers::SiStandard::TYPED_STAGES.find do |ts|
|
|
776
|
+
ts.abbr.include?("SI")
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
# Extract year and month
|
|
781
|
+
attributes[:year] = extract_value(parsed[:year]) if parsed[:year]
|
|
782
|
+
attributes[:month] = extract_value(parsed[:month]) if parsed[:month]
|
|
783
|
+
|
|
784
|
+
# Handle relationships if present
|
|
785
|
+
if parsed[:relationship_type] || parsed[:relationship_clause]
|
|
786
|
+
attributes[:relationships] = build_relationships(parsed)
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
# Handle parenthetical content
|
|
790
|
+
handle_parameters(parsed, attributes)
|
|
791
|
+
|
|
792
|
+
# BOTH SI and PSI use SiStandard class - just different typed_stages
|
|
793
|
+
Identifiers::SiStandard.new(**attributes)
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
# Build multi-numbered identifier from parsed data
|
|
797
|
+
# @param parsed [Hash] parsed multi-numbered data
|
|
798
|
+
# @return [Identifiers::MultiNumberedIdentifier] multi-numbered identifier
|
|
799
|
+
def build_multi_numbered_identifier(parsed)
|
|
800
|
+
# Build primary identifier
|
|
801
|
+
primary_id = build_single_identifier(parsed[:primary_identifier],
|
|
802
|
+
building_secondary: false)
|
|
803
|
+
|
|
804
|
+
# Build secondary identifier based on format
|
|
805
|
+
if parsed[:secondary_crossref]
|
|
806
|
+
# Cross-reference format: /C62.22.1-1996
|
|
807
|
+
# Build directly to avoid re-parsing which could cause infinite recursion
|
|
808
|
+
crossref = parsed[:secondary_crossref]
|
|
809
|
+
# Pattern: slash >> "C" >> digits >> dot >> digits >> dot >> digits >> dash >> year_digits
|
|
810
|
+
# The parsed crossref is a string - extract the number part
|
|
811
|
+
# Format: C62.22.1-1996 where C is part of the crossref notation
|
|
812
|
+
# The captured slice keeps the leading slash, which is a SEPARATOR in
|
|
813
|
+
# the printed reference, not part of the number. Storing it made the
|
|
814
|
+
# secondary's code "/C62.22.1-1996", which then failed the renderer's
|
|
815
|
+
# own cross-reference test (`/^C\d+\./`) and fell through to the
|
|
816
|
+
# " and " join. Strip it.
|
|
817
|
+
secondary_id = Identifiers::Standard.new(
|
|
818
|
+
publisher: "IEEE",
|
|
819
|
+
number: extract_value(crossref).to_s.sub(%r{\A/}, ""),
|
|
820
|
+
)
|
|
821
|
+
elsif parsed[:secondary_joint]
|
|
822
|
+
# Joint standard format: ", Std 1177-1989"
|
|
823
|
+
# Build from parsed components
|
|
824
|
+
secondary_id = build_single_identifier(parsed[:secondary_joint],
|
|
825
|
+
building_secondary: true)
|
|
826
|
+
else
|
|
827
|
+
secondary_id = nil
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
Identifiers::MultiNumberedIdentifier.new(
|
|
831
|
+
primary_identifier: primary_id,
|
|
832
|
+
secondary_identifier: secondary_id,
|
|
833
|
+
)
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
# Determine which identifier class to use based on attributes
|
|
837
|
+
# CRITICAL: Use flavor module for type-based decisions, NOT hardcoded logic here
|
|
838
|
+
# Builder's job is ONLY to cast types, not make business decisions
|
|
839
|
+
def determine_identifier_class(attributes)
|
|
840
|
+
# Check for AIEE publisher FIRST (AIEE has its own identifier class)
|
|
841
|
+
# This must be checked before type-based routing because AIEE uses "No" as type
|
|
842
|
+
if attributes[:publisher] == "AIEE"
|
|
843
|
+
return Ieee::Aiee::Identifier
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# Get type from attributes and use flavor module to locate class
|
|
847
|
+
type_code = attributes[:type]
|
|
848
|
+
|
|
849
|
+
# Use flavor module for type-to-class mapping
|
|
850
|
+
if type_code
|
|
851
|
+
klass = Pubid::Ieee.locate_type(type_code)
|
|
852
|
+
return klass if klass
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
# Non-type-based routing (structural patterns, not business logic)
|
|
856
|
+
# These are structural checks, not type decisions
|
|
857
|
+
|
|
858
|
+
# Check for SI standards (handles both SI and PSI via typed_stage)
|
|
859
|
+
if ["SI", "PSI"].include?(type_code)
|
|
860
|
+
return Identifiers::SiStandard
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
# Check for interpretation supplements (structural: has interpretation flag or int_year)
|
|
864
|
+
if attributes[:interpretation] || attributes[:int_year]
|
|
865
|
+
return Identifiers::InterpretationIdentifier
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
# Check for conformance supplements (structural: has conf_number)
|
|
869
|
+
if attributes[:conf_number]
|
|
870
|
+
return Identifiers::ConformanceIdentifier
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
# Check for corrigendum supplements (structural: has cor_number)
|
|
874
|
+
if attributes[:cor_number]
|
|
875
|
+
return Identifiers::Corrigendum
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
# Check for amendment supplements (structural: has amd_number)
|
|
879
|
+
if attributes[:amd_number]
|
|
880
|
+
return Identifiers::Amendment
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
# Check for multi-numbered standards (structural: has crossref or joint patterns)
|
|
884
|
+
# These are handled at the build() method level, not here
|
|
885
|
+
# (cross-reference patterns like /C62.22.1-1996 and joint standards)
|
|
886
|
+
|
|
887
|
+
# Check for adopted standards (parenthetical adoptions)
|
|
888
|
+
if attributes[:adoption] || (attributes[:parameters] && attributes[:parameters][:adoption])
|
|
889
|
+
return Identifiers::AdoptedStandard
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# A redline is a plain Standard carrying `redline: true` (a distinct
|
|
893
|
+
# document from its base) — NOT the RedlinedStandard wrapper, which
|
|
894
|
+
# expects a nested `base` the flat build path never sets. render_base
|
|
895
|
+
# restores the " - Redline" suffix from the flag.
|
|
896
|
+
|
|
897
|
+
# Default to the concrete Standard leaf (a plain published standard).
|
|
898
|
+
# Routing to a leaf — rather than instantiating the shared base
|
|
899
|
+
# Ieee::Identifier — is what lets `number` be a reliable :string index
|
|
900
|
+
# key (see Identifiers::Standard).
|
|
901
|
+
Identifiers::Standard
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
# Detect lead party for joint development identifiers
|
|
905
|
+
# @param attributes [Hash] the identifier attributes
|
|
906
|
+
# @return [String] the lead party ("IEEE", "ISO", or "IEC")
|
|
907
|
+
def detect_lead_party(attributes)
|
|
908
|
+
# Rule 1: Check for P prefix in code (IEEE-led)
|
|
909
|
+
if attributes[:code]&.start_with?("P") || attributes[:type] == "P"
|
|
910
|
+
return "IEEE"
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
# Rule 2: Check for IEEE draft notation in original input (IEEE-led)
|
|
914
|
+
if original_input&.match?(/\/D\d+/)
|
|
915
|
+
return "IEEE"
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
# Rule 3: Check for ISO stage codes (ISO-led)
|
|
919
|
+
iso_stages = %w[FDIS DIS CD WD PWI NP]
|
|
920
|
+
if attributes[:typed_stage]
|
|
921
|
+
stage_abbr = attributes[:typed_stage].abbr
|
|
922
|
+
stage_abbr = [stage_abbr] unless stage_abbr.is_a?(Array)
|
|
923
|
+
if stage_abbr.any? { |abbr| iso_stages.include?(abbr) }
|
|
924
|
+
return "ISO"
|
|
925
|
+
end
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
# Rule 4: Check for colon before year in original input (ISO-led)
|
|
929
|
+
if original_input&.match?(/:\d{4}/)
|
|
930
|
+
return "ISO"
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
# Rule 5: Default to first publisher
|
|
934
|
+
attributes[:publisher] || "IEEE"
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
# Merge an array of parsed hashes into a single hash
|
|
938
|
+
# @param parsed_array [Array<Hash>] array of parsed hashes
|
|
939
|
+
# @return [Hash] merged hash
|
|
940
|
+
def merge_parsed_array(parsed_array)
|
|
941
|
+
parsed_array.inject({}) do |result, hash|
|
|
942
|
+
result.merge(hash)
|
|
943
|
+
end
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
# Extract and normalize attributes from parsed data
|
|
947
|
+
# @param parsed [Hash] the parsed data
|
|
948
|
+
# @return [Hash] normalized attributes for identifier
|
|
949
|
+
def extract_attributes(parsed)
|
|
950
|
+
attributes = {}
|
|
951
|
+
|
|
952
|
+
# Handle publishers
|
|
953
|
+
if parsed[:publishers]
|
|
954
|
+
pub_data = parsed[:publishers]
|
|
955
|
+
attributes[:publisher] = extract_value(pub_data[:publisher])
|
|
956
|
+
|
|
957
|
+
if pub_data[:copublishers]
|
|
958
|
+
copubs = pub_data[:copublishers]
|
|
959
|
+
copubs = [copubs] unless copubs.is_a?(Array)
|
|
960
|
+
attributes[:copublisher] = copubs.filter_map do |cp|
|
|
961
|
+
extract_value(cp[:copublisher])
|
|
962
|
+
end
|
|
963
|
+
end
|
|
964
|
+
elsif parsed[:publisher]
|
|
965
|
+
attributes[:publisher] = extract_value(parsed[:publisher])
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
# Build code component with parts and subparts
|
|
969
|
+
code_parts = []
|
|
970
|
+
code_parts << extract_value(parsed[:part]) if parsed[:part]
|
|
971
|
+
if parsed[:subpart]
|
|
972
|
+
subparts = parsed[:subpart]
|
|
973
|
+
subparts = [subparts] unless subparts.is_a?(Array)
|
|
974
|
+
code_parts.concat(subparts.filter_map { |sp| extract_value(sp) })
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
# Create code string with parts
|
|
978
|
+
code_str = extract_value(parsed[:number])
|
|
979
|
+
|
|
980
|
+
# Extract type and draft_status for typed_stage lookup
|
|
981
|
+
type_value = extract_value(parsed[:type])
|
|
982
|
+
draft_status_value = extract_value(parsed[:draft_status])
|
|
983
|
+
|
|
984
|
+
# Handle case where parser captured number without "P" prefix
|
|
985
|
+
# Check original input to see if there was a P before the number
|
|
986
|
+
# The ieee_p_identifier rule consumes P without capturing it
|
|
987
|
+
if !type_value && original_input&.match?(/IEEE\s+P/)
|
|
988
|
+
type_value = "P"
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
# Handle ANSI P prefix patterns (e.g., "ANSI PN42.34-2015")
|
|
992
|
+
if !type_value && original_input&.match?(/ANSI\s+P/)
|
|
993
|
+
# Extract P as type since it was in the original but parser stripped it
|
|
994
|
+
type_value = "P"
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
# NOTE: "P" is a project/draft stage indicator, NOT a code prefix
|
|
998
|
+
# It should be reflected in typed_stage, not in the Code component
|
|
999
|
+
# Do NOT prepend "P" to code_str - code.prefix should remain nil for project drafts
|
|
1000
|
+
|
|
1001
|
+
# Special case: For IEEE/CSA dual published patterns, strip P prefix from code
|
|
1002
|
+
# Pattern: "IEEE/CSA P844.1-2017" -> code should be "844.1" not "P844.1"
|
|
1003
|
+
if code_str&.start_with?("P") && original_input&.include?("/CSA")
|
|
1004
|
+
# Check if the copublisher attribute indicates CSA
|
|
1005
|
+
pub_data = parsed[:publishers]
|
|
1006
|
+
has_csa_copub = if pub_data && pub_data[:copublishers]
|
|
1007
|
+
copubs = pub_data[:copublishers]
|
|
1008
|
+
copubs = [copubs] unless copubs.is_a?(Array)
|
|
1009
|
+
copubs.any? do |cp|
|
|
1010
|
+
extract_value(cp[:copublisher])&.include?("CSA")
|
|
1011
|
+
end
|
|
1012
|
+
else
|
|
1013
|
+
original_input&.include?("/CSA")
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
if has_csa_copub
|
|
1017
|
+
code_str = code_str.sub(/^P/, "")
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
if code_str && !code_parts.empty?
|
|
1022
|
+
code_str += ".#{code_parts.join('.')}"
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
# Year detection: If code_str ends with year-like pattern (dash + 4 digits, 1884-2099)
|
|
1026
|
+
# and there's no year attribute yet, treat it as a year
|
|
1027
|
+
# Examples: "535-2013", "802.1AC-2016", "C37.41-2016"
|
|
1028
|
+
# AIEE established in 1884, so years range from 1884 to 2099
|
|
1029
|
+
# ONLY apply this when there are NO code_parts (meaning parser didn't capture parts separately)
|
|
1030
|
+
# This prevents breaking legitimate dual-published identifiers
|
|
1031
|
+
# Match ending with dash followed by 4 digits only (not dot, to preserve 802.1AC patterns)
|
|
1032
|
+
if code_str && !parsed[:year] && code_parts.empty? && (match = code_str.match(/^(.+)-(\d{4})$/))
|
|
1033
|
+
potential_year = match[2].to_i
|
|
1034
|
+
if potential_year.between?(1884, 2099)
|
|
1035
|
+
# This is a year - extract it
|
|
1036
|
+
code_str = match[1] # Remove year from code
|
|
1037
|
+
parsed[:year] = match[2] # Add to parsed for extraction below
|
|
1038
|
+
end
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
attributes[:code] = code_str
|
|
1042
|
+
|
|
1043
|
+
# Extract year - check for edition_month parsed separately
|
|
1044
|
+
if parsed[:year]
|
|
1045
|
+
year_str = extract_value(parsed[:year])
|
|
1046
|
+
attributes[:year] = year_str
|
|
1047
|
+
elsif parsed[:edition_year]
|
|
1048
|
+
# The `edition` rule captures its own year under :edition_year (not
|
|
1049
|
+
# :year) so it never collides with the base -YYYY (see parser.rb).
|
|
1050
|
+
# With no base year the edition's year IS the document date and is
|
|
1051
|
+
# promoted to the identity (e.g. "IEEE Std 802.11 Edition 3.0-2009"
|
|
1052
|
+
# -> year 2009). When a base year exists it wins above and
|
|
1053
|
+
# :edition_year is dropped — the edition ordinal is still kept.
|
|
1054
|
+
attributes[:year] = extract_value(parsed[:edition_year])
|
|
1055
|
+
elsif parsed[:trailing_year]
|
|
1056
|
+
# No base -YYYY identity year: the trailing "Month YYYY" IS the
|
|
1057
|
+
# document date (e.g. "IEEE Std 519, May 1993"), so promote it.
|
|
1058
|
+
# When a base year exists it wins (the IEEE approval/identity year)
|
|
1059
|
+
# and the trailing date is intentionally dropped rather than
|
|
1060
|
+
# fabricating a wrong month/year pairing. The trailing captures use
|
|
1061
|
+
# distinct keys (:trailing_month/:trailing_year) so they never collide
|
|
1062
|
+
# with the base :year (Parslet no longer warns "Duplicate subtrees").
|
|
1063
|
+
attributes[:year] = extract_value(parsed[:trailing_year])
|
|
1064
|
+
if parsed[:trailing_month]
|
|
1065
|
+
attributes[:month] = extract_value(parsed[:trailing_month])
|
|
1066
|
+
end
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
# Extract edition_month if parsed separately
|
|
1070
|
+
if parsed[:edition_month]
|
|
1071
|
+
attributes[:edition_month] = extract_value(parsed[:edition_month])
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
# Set type attribute for backward compatibility (after P extraction)
|
|
1075
|
+
# NOTE: "P" IS a type code that maps to ProjectDraftIdentifier via flavor module
|
|
1076
|
+
# Type can be: "Std", "No", "P" (project draft), etc.
|
|
1077
|
+
attributes[:type] = type_value if type_value
|
|
1078
|
+
|
|
1079
|
+
# Lookup typed_stage from registry
|
|
1080
|
+
typed_stage_abbr = determine_stage_abbr(type_value, draft_status_value,
|
|
1081
|
+
parsed)
|
|
1082
|
+
if typed_stage_abbr
|
|
1083
|
+
attributes[:typed_stage] =
|
|
1084
|
+
Pubid::Ieee.locate_stage(typed_stage_abbr)
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
attributes[:draft_status] = draft_status_value
|
|
1088
|
+
|
|
1089
|
+
# Optional attributes (excluding part/subpart since they're in code)
|
|
1090
|
+
extract_optional(parsed, attributes, :edition)
|
|
1091
|
+
extract_optional(parsed, attributes, :revision)
|
|
1092
|
+
|
|
1093
|
+
# Month/day - always extract if present (but not if already extracted from year)
|
|
1094
|
+
unless attributes[:edition_month]
|
|
1095
|
+
extract_optional(parsed, attributes,
|
|
1096
|
+
:month)
|
|
1097
|
+
end
|
|
1098
|
+
extract_optional(parsed, attributes, :day)
|
|
1099
|
+
|
|
1100
|
+
# Handle draft (can be complex)
|
|
1101
|
+
handle_draft(parsed, attributes)
|
|
1102
|
+
|
|
1103
|
+
# Default draft version 1 when the type indicates a Draft but the
|
|
1104
|
+
# parser found no explicit version (issue #205). Real-world IEEE
|
|
1105
|
+
# drafts always have at least version 1; the missing suffix is a
|
|
1106
|
+
# source-data omission, not an undrafted document.
|
|
1107
|
+
apply_default_draft_version(attributes, type_value)
|
|
1108
|
+
|
|
1109
|
+
# Handle corrigendum
|
|
1110
|
+
handle_corrigendum(parsed, attributes)
|
|
1111
|
+
|
|
1112
|
+
# Handle amendment
|
|
1113
|
+
handle_amendment(parsed, attributes)
|
|
1114
|
+
|
|
1115
|
+
# Handle interpretation (already extracted as boolean)
|
|
1116
|
+
# attributes[:interpretation] = true if parsed[:interpretation]
|
|
1117
|
+
|
|
1118
|
+
# Handle conformance
|
|
1119
|
+
handle_conformance(parsed, attributes)
|
|
1120
|
+
|
|
1121
|
+
# Handle ASHRAE copub
|
|
1122
|
+
handle_ashrae_copub(parsed, attributes)
|
|
1123
|
+
|
|
1124
|
+
# Handle IEEE crossref
|
|
1125
|
+
handle_ieee_crossref(parsed, attributes)
|
|
1126
|
+
|
|
1127
|
+
# Handle reaffirmed
|
|
1128
|
+
handle_reaffirmed(parsed, attributes)
|
|
1129
|
+
|
|
1130
|
+
# Handle additional parameters
|
|
1131
|
+
handle_parameters(parsed, attributes)
|
|
1132
|
+
|
|
1133
|
+
# Book nickname
|
|
1134
|
+
if parsed[:nickname]
|
|
1135
|
+
attributes[:nickname] = extract_value(parsed[:nickname])
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
# Interpretation
|
|
1139
|
+
attributes[:interpretation] = true if parsed[:interpretation]
|
|
1140
|
+
|
|
1141
|
+
# Redline
|
|
1142
|
+
attributes[:redline] = true if parsed[:redline]
|
|
1143
|
+
|
|
1144
|
+
attributes
|
|
1145
|
+
end
|
|
1146
|
+
|
|
1147
|
+
# Determine stage abbreviation for TYPED_STAGE lookup
|
|
1148
|
+
# @param type_value [String] the type value (e.g., "Std", "P")
|
|
1149
|
+
# @param draft_status_value [String] the draft status (e.g., "Unapproved")
|
|
1150
|
+
# @param parsed [Hash] the full parsed data
|
|
1151
|
+
# @return [String, nil] the abbreviation to use for stage lookup
|
|
1152
|
+
def determine_stage_abbr(type_value, _draft_status_value, parsed)
|
|
1153
|
+
# Check for specific draft notation (D1, D2, etc.)
|
|
1154
|
+
if parsed[:draft]
|
|
1155
|
+
draft_data = parsed[:draft]
|
|
1156
|
+
if draft_data.is_a?(Array)
|
|
1157
|
+
draft_data = draft_data.inject({}) do |r, e|
|
|
1158
|
+
r.merge(e)
|
|
1159
|
+
end
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
if draft_data.is_a?(Hash) && draft_data[:draft_version]
|
|
1163
|
+
dv = draft_data[:draft_version]
|
|
1164
|
+
version = if dv.is_a?(Array)
|
|
1165
|
+
dv.map do |v|
|
|
1166
|
+
extract_value(v)
|
|
1167
|
+
end.join
|
|
1168
|
+
else
|
|
1169
|
+
extract_value(dv)
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
# Construct draft notation like "D1", "D2", etc.
|
|
1173
|
+
if version
|
|
1174
|
+
draft_abbr = "D#{version}"
|
|
1175
|
+
# Check if this specific draft stage is in registry
|
|
1176
|
+
stage = Pubid::Ieee.locate_stage(draft_abbr)
|
|
1177
|
+
return draft_abbr if stage&.abbr&.include?(draft_abbr)
|
|
1178
|
+
end
|
|
1179
|
+
end
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
# Check type value for known abbreviations
|
|
1183
|
+
if type_value
|
|
1184
|
+
# Remove leading "P" and check if it exists in registry
|
|
1185
|
+
if type_value.start_with?("P")
|
|
1186
|
+
# Could be just "P" prefix or "P" as type indicator
|
|
1187
|
+
# If the type is literally "P" followed by numbers, it's a project identifier
|
|
1188
|
+
# Return "P" to get the generic project typed_stage
|
|
1189
|
+
return "P"
|
|
1190
|
+
elsif type_value == "Std"
|
|
1191
|
+
return "Std"
|
|
1192
|
+
elsif type_value.match?(/^No\.?$/)
|
|
1193
|
+
return type_value
|
|
1194
|
+
end
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
# Default to "Std" for published standards
|
|
1198
|
+
"Std"
|
|
1199
|
+
end
|
|
1200
|
+
|
|
1201
|
+
# Extract a simple value from parsed data
|
|
1202
|
+
# @param value [Object] the value to extract
|
|
1203
|
+
# @return [String, nil] the extracted string value
|
|
1204
|
+
def extract_value(value)
|
|
1205
|
+
return nil if value.nil?
|
|
1206
|
+
return nil if value.is_a?(Array) && value.empty?
|
|
1207
|
+
|
|
1208
|
+
if value.is_a?(Array)
|
|
1209
|
+
joined = value.join
|
|
1210
|
+
return joined.length.positive? ? joined : nil
|
|
1211
|
+
end
|
|
1212
|
+
|
|
1213
|
+
str_value = value.to_s.strip
|
|
1214
|
+
str_value.length.positive? ? str_value : nil
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
# Extract optional attribute if present
|
|
1218
|
+
def extract_optional(parsed, attributes, key)
|
|
1219
|
+
value = extract_value(parsed[key])
|
|
1220
|
+
attributes[key] = value if value
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
# Default draft version to "1" when the identifier type indicates a
|
|
1224
|
+
# Draft but the parser found no explicit version (issue #205).
|
|
1225
|
+
def apply_default_draft_version(attributes, type_value)
|
|
1226
|
+
return if attributes[:draft] || attributes[:draft_obj]
|
|
1227
|
+
return unless type_value.to_s == "Draft Std"
|
|
1228
|
+
|
|
1229
|
+
attributes[:draft] = "D1"
|
|
1230
|
+
# Carry the identifier's year into the draft object so the renderer
|
|
1231
|
+
# doesn't drop it (the renderer suppresses the `-YYYY` suffix when
|
|
1232
|
+
# a draft is attached, expecting the year to live inside /D...).
|
|
1233
|
+
attributes[:draft_obj] =
|
|
1234
|
+
Components::Draft.new(version: "1", year: attributes[:year])
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
# Handle draft information
|
|
1238
|
+
def handle_draft(parsed, attributes)
|
|
1239
|
+
draft_data = parsed[:draft] || parsed[:digit_draft]
|
|
1240
|
+
return unless draft_data
|
|
1241
|
+
|
|
1242
|
+
# Draft can be an array of hash elements or a single hash. The grammar's
|
|
1243
|
+
# `draft_version.repeat(1,2)` splits a dotted designator like "1.2.6"
|
|
1244
|
+
# into ["1.2", ".6"], so DON'T let a plain merge overwrite it (that
|
|
1245
|
+
# dropped every part but the last — "1.2.6" -> ".6"). Collect ALL the
|
|
1246
|
+
# draft_version parts into an array (the version extraction below joins
|
|
1247
|
+
# them back into one verbatim string) and merge the remaining keys.
|
|
1248
|
+
if draft_data.is_a?(Array)
|
|
1249
|
+
hashes = draft_data.select { |e| e.is_a?(Hash) }
|
|
1250
|
+
versions = hashes.filter_map { |e| e[:draft_version] }
|
|
1251
|
+
merged = hashes.inject({}) { |result, elem| result.merge(elem) }
|
|
1252
|
+
merged[:draft_version] = versions unless versions.empty?
|
|
1253
|
+
draft_data = merged
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
# Extract draft version and revision
|
|
1257
|
+
version = nil
|
|
1258
|
+
revision = nil
|
|
1259
|
+
month = nil
|
|
1260
|
+
year = nil
|
|
1261
|
+
day = nil
|
|
1262
|
+
comma_before_month = false
|
|
1263
|
+
|
|
1264
|
+
if draft_data.is_a?(Hash)
|
|
1265
|
+
if draft_data[:draft_version]
|
|
1266
|
+
dv = draft_data[:draft_version]
|
|
1267
|
+
version = if dv.is_a?(Array)
|
|
1268
|
+
dv.map { |v| extract_value(v) }.join
|
|
1269
|
+
else
|
|
1270
|
+
extract_value(dv)
|
|
1271
|
+
end
|
|
1272
|
+
# Normalize a leading hyphen ("/D-3.0" -> "3.0"); the draft
|
|
1273
|
+
# designator is otherwise held verbatim so no digit is lost.
|
|
1274
|
+
version = version.sub(/\A-/, "") if version
|
|
1275
|
+
end
|
|
1276
|
+
|
|
1277
|
+
revision = extract_value(draft_data[:revision]) if draft_data[:revision]
|
|
1278
|
+
|
|
1279
|
+
# Extract date information from draft data
|
|
1280
|
+
month_slice = draft_data[:month]
|
|
1281
|
+
month = extract_value(month_slice) if month_slice
|
|
1282
|
+
year = extract_value(draft_data[:year]) if draft_data[:year]
|
|
1283
|
+
day = extract_value(draft_data[:day]) if draft_data[:day]
|
|
1284
|
+
|
|
1285
|
+
# Detect comma before month and space before draft by checking the original input
|
|
1286
|
+
if original_input
|
|
1287
|
+
if month
|
|
1288
|
+
# Look for ", Month" pattern in the original input
|
|
1289
|
+
comma_before_month = original_input.match?(/,\s+#{Regexp.escape(month)}/i)
|
|
1290
|
+
end
|
|
1291
|
+
|
|
1292
|
+
# Check if there's a space before /D in the original input
|
|
1293
|
+
if version && original_input.match?(/\s+\/D#{Regexp.escape(version)}/i)
|
|
1294
|
+
attributes[:space_before_draft] = true
|
|
1295
|
+
end
|
|
1296
|
+
end
|
|
1297
|
+
else
|
|
1298
|
+
version = extract_value(draft_data)
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
# Create Draft component object if we have version info
|
|
1302
|
+
if version
|
|
1303
|
+
draft_obj = Components::Draft.new(
|
|
1304
|
+
version: version,
|
|
1305
|
+
revision: revision,
|
|
1306
|
+
month: month,
|
|
1307
|
+
year: year,
|
|
1308
|
+
day: day,
|
|
1309
|
+
)
|
|
1310
|
+
draft_obj.comma_before_month = comma_before_month
|
|
1311
|
+
attributes[:draft_obj] = draft_obj
|
|
1312
|
+
attributes[:draft] = draft_obj.to_s
|
|
1313
|
+
end
|
|
1314
|
+
end
|
|
1315
|
+
|
|
1316
|
+
# Handle corrigendum information
|
|
1317
|
+
def handle_corrigendum(parsed, attributes)
|
|
1318
|
+
if parsed[:corrigendum].is_a?(Hash)
|
|
1319
|
+
cor_data = parsed[:corrigendum]
|
|
1320
|
+
attributes[:cor_number] = extract_value(cor_data[:cor_number])
|
|
1321
|
+
if cor_data[:cor_year]
|
|
1322
|
+
attributes[:cor_year] =
|
|
1323
|
+
extract_value(cor_data[:cor_year])
|
|
1324
|
+
end
|
|
1325
|
+
elsif parsed[:corrigendum]
|
|
1326
|
+
attributes[:corrigendum] = extract_value(parsed[:corrigendum])
|
|
1327
|
+
end
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
# Handle amendment information
|
|
1331
|
+
def handle_amendment(parsed, attributes)
|
|
1332
|
+
if parsed[:amendment].is_a?(Hash)
|
|
1333
|
+
amd_data = parsed[:amendment]
|
|
1334
|
+
attributes[:amd_number] = extract_value(amd_data[:amd_number])
|
|
1335
|
+
if amd_data[:amd_year]
|
|
1336
|
+
attributes[:amd_year] =
|
|
1337
|
+
extract_value(amd_data[:amd_year])
|
|
1338
|
+
end
|
|
1339
|
+
elsif parsed[:amendment]
|
|
1340
|
+
attributes[:amendment] = extract_value(parsed[:amendment])
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
# Handle reaffirmed information
|
|
1345
|
+
def handle_reaffirmed(parsed, attributes)
|
|
1346
|
+
if parsed[:reaffirmed].is_a?(Hash)
|
|
1347
|
+
reaf_data = parsed[:reaffirmed]
|
|
1348
|
+
attributes[:reaffirmed] = extract_value(reaf_data[:year])
|
|
1349
|
+
elsif parsed[:reaffirmed]
|
|
1350
|
+
attributes[:reaffirmed] = extract_value(parsed[:reaffirmed])
|
|
1351
|
+
end
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
# Handle conformance document information
|
|
1355
|
+
def handle_conformance(parsed, attributes)
|
|
1356
|
+
if parsed[:conformance].is_a?(Hash)
|
|
1357
|
+
conf_data = parsed[:conformance]
|
|
1358
|
+
attributes[:conf_number] = extract_value(conf_data[:conf_number])
|
|
1359
|
+
if conf_data[:conf_year]
|
|
1360
|
+
attributes[:conf_year] = extract_value(conf_data[:conf_year])
|
|
1361
|
+
end
|
|
1362
|
+
elsif parsed[:conformance]
|
|
1363
|
+
attributes[:conformance] = extract_value(parsed[:conformance])
|
|
1364
|
+
end
|
|
1365
|
+
end
|
|
1366
|
+
|
|
1367
|
+
# Handle ASHRAE joint publication information
|
|
1368
|
+
def handle_ashrae_copub(parsed, attributes)
|
|
1369
|
+
if parsed[:ashrae_copub].is_a?(Hash)
|
|
1370
|
+
ashrae_data = parsed[:ashrae_copub]
|
|
1371
|
+
attributes[:ashrae_number] =
|
|
1372
|
+
extract_value(ashrae_data[:ashrae_number])
|
|
1373
|
+
if ashrae_data[:ashrae_year]
|
|
1374
|
+
attributes[:ashrae_year] = extract_value(ashrae_data[:ashrae_year])
|
|
1375
|
+
end
|
|
1376
|
+
elsif parsed[:ashrae_copub]
|
|
1377
|
+
attributes[:ashrae_copub] = extract_value(parsed[:ashrae_copub])
|
|
1378
|
+
end
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
# Handle IEEE cross-reference information
|
|
1382
|
+
def handle_ieee_crossref(parsed, attributes)
|
|
1383
|
+
if parsed[:ieee_crossref].is_a?(Hash)
|
|
1384
|
+
parsed[:ieee_crossref]
|
|
1385
|
+
# Extract the cross-reference string (e.g., "C62.22.1-1996")
|
|
1386
|
+
# Store it for rendering
|
|
1387
|
+
attributes[:crossref] =
|
|
1388
|
+
"/C#{extract_value(crossref).to_s.sub(/^\//, '')}"
|
|
1389
|
+
elsif parsed[:ieee_crossref]
|
|
1390
|
+
attributes[:crossref] = extract_value(parsed[:ieee_crossref])
|
|
1391
|
+
end
|
|
1392
|
+
end
|
|
1393
|
+
|
|
1394
|
+
# Handle additional parameters
|
|
1395
|
+
def handle_parameters(parsed, attributes)
|
|
1396
|
+
if parsed[:parameters].is_a?(Hash)
|
|
1397
|
+
param_data = parsed[:parameters]
|
|
1398
|
+
|
|
1399
|
+
# Handle parenthetical content (for multi-part adoptions like "ANSI Y32.21-1976, NCTA 006-0975")
|
|
1400
|
+
if param_data[:parenthetical_content]
|
|
1401
|
+
attributes[:parenthetical_content] =
|
|
1402
|
+
extract_value(param_data[:parenthetical_content])
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
if param_data[:revision_of]
|
|
1406
|
+
attributes[:revision_of] =
|
|
1407
|
+
extract_value(param_data[:revision_of])
|
|
1408
|
+
end
|
|
1409
|
+
if param_data[:amendment_to]
|
|
1410
|
+
attributes[:amendment_to] =
|
|
1411
|
+
extract_value(param_data[:amendment_to])
|
|
1412
|
+
end
|
|
1413
|
+
if param_data[:adoption]
|
|
1414
|
+
attributes[:adoption] =
|
|
1415
|
+
extract_value(param_data[:adoption])
|
|
1416
|
+
end
|
|
1417
|
+
if param_data[:note]
|
|
1418
|
+
attributes[:note] =
|
|
1419
|
+
extract_value(param_data[:note])
|
|
1420
|
+
end
|
|
1421
|
+
end
|
|
1422
|
+
end
|
|
1423
|
+
|
|
1424
|
+
# Build relationships from parsed relationship clause (Pattern 4)
|
|
1425
|
+
# @param parsed_hash [Hash] the parsed data containing relationship information
|
|
1426
|
+
# @return [Array<Components::Relationship>] array of Relationship objects
|
|
1427
|
+
def build_relationships(parsed_hash)
|
|
1428
|
+
return [] unless parsed_hash[:relationship_type] || parsed_hash[:relationship_clause]
|
|
1429
|
+
|
|
1430
|
+
relationships = []
|
|
1431
|
+
|
|
1432
|
+
# Main relationship
|
|
1433
|
+
if parsed_hash[:relationship_type]
|
|
1434
|
+
rel_type = extract_relationship_type(parsed_hash[:relationship_type])
|
|
1435
|
+
related = parse_identifier_list(parsed_hash[:related_ids])
|
|
1436
|
+
|
|
1437
|
+
# Handle "as amended by" clause
|
|
1438
|
+
amendments = nil
|
|
1439
|
+
approved_flag = false
|
|
1440
|
+
|
|
1441
|
+
if parsed_hash[:amendments]
|
|
1442
|
+
# Check if it's the "and its approved amendments" flag
|
|
1443
|
+
if parsed_hash[:amendments].is_a?(Hash) && parsed_hash[:amendments][:approved_amendments]
|
|
1444
|
+
approved_flag = true
|
|
1445
|
+
else
|
|
1446
|
+
amendments = parse_identifier_list(parsed_hash[:amendments])
|
|
1447
|
+
end
|
|
1448
|
+
end
|
|
1449
|
+
|
|
1450
|
+
relationships << Components::Relationship.new(
|
|
1451
|
+
relationship_type: rel_type,
|
|
1452
|
+
related_identifiers: related,
|
|
1453
|
+
intermediate_amendments: amendments,
|
|
1454
|
+
approved_amendments_flag: approved_flag,
|
|
1455
|
+
)
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
# Additional relationships (separated by " / ")
|
|
1459
|
+
if parsed_hash[:additional_rels]
|
|
1460
|
+
additional = parsed_hash[:additional_rels]
|
|
1461
|
+
additional = [additional] unless additional.is_a?(Array)
|
|
1462
|
+
|
|
1463
|
+
additional.each do |rel_data|
|
|
1464
|
+
rel_type = extract_relationship_type(rel_data[:relationship_type])
|
|
1465
|
+
related = parse_identifier_list(rel_data[:related_ids])
|
|
1466
|
+
|
|
1467
|
+
# Handle "as amended by" clause for additional relationships
|
|
1468
|
+
amendments = nil
|
|
1469
|
+
approved_flag = false
|
|
1470
|
+
|
|
1471
|
+
if rel_data[:amendments]
|
|
1472
|
+
if rel_data[:amendments].is_a?(Hash) && rel_data[:amendments][:approved_amendments]
|
|
1473
|
+
approved_flag = true
|
|
1474
|
+
else
|
|
1475
|
+
amendments = parse_identifier_list(rel_data[:amendments])
|
|
1476
|
+
end
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
relationships << Components::Relationship.new(
|
|
1480
|
+
relationship_type: rel_type,
|
|
1481
|
+
related_identifiers: related,
|
|
1482
|
+
intermediate_amendments: amendments,
|
|
1483
|
+
approved_amendments_flag: approved_flag,
|
|
1484
|
+
)
|
|
1485
|
+
end
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1488
|
+
relationships
|
|
1489
|
+
end
|
|
1490
|
+
|
|
1491
|
+
# Extract relationship type from parsed hash
|
|
1492
|
+
# @param type_hash [Hash] hash with relationship type key
|
|
1493
|
+
# @return [String] the relationship type constant name
|
|
1494
|
+
def extract_relationship_type(type_hash)
|
|
1495
|
+
return nil unless type_hash.is_a?(Hash)
|
|
1496
|
+
|
|
1497
|
+
# type_hash has key like :revision_of, :amendment_to, etc.
|
|
1498
|
+
type_hash.keys.first.to_s
|
|
1499
|
+
end
|
|
1500
|
+
|
|
1501
|
+
# Parse a list of identifier strings into identifier objects
|
|
1502
|
+
# @param list_data [Hash, Array, nil] the parsed identifier list data
|
|
1503
|
+
# @return [Array<Identifier>] array of parsed identifier objects
|
|
1504
|
+
def parse_identifier_list(list_data)
|
|
1505
|
+
return [] unless list_data
|
|
1506
|
+
|
|
1507
|
+
# Extract identifier strings from parsed data
|
|
1508
|
+
id_strings = extract_identifier_strings(list_data)
|
|
1509
|
+
|
|
1510
|
+
# Recursively parse each identifier string
|
|
1511
|
+
id_strings.map do |id_str|
|
|
1512
|
+
# Use Identifier.parse for recursive parsing
|
|
1513
|
+
Identifier.parse(id_str)
|
|
1514
|
+
rescue Parslet::ParseFailed
|
|
1515
|
+
# If parsing fails, create minimal identifier with just the string
|
|
1516
|
+
# This maintains graceful degradation
|
|
1517
|
+
Identifier.new(parenthetical_content: id_str)
|
|
1518
|
+
end
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
# Extract identifier strings from parsed list data
|
|
1522
|
+
# @param list_data [Hash, Array] the parsed list data
|
|
1523
|
+
# @return [Array<String>] array of identifier strings
|
|
1524
|
+
def extract_identifier_strings(list_data)
|
|
1525
|
+
if list_data.is_a?(Array)
|
|
1526
|
+
# Array of id hashes: [{id: "..."}, {id: "..."}]
|
|
1527
|
+
list_data.map { |item| item[:id].to_s.strip }
|
|
1528
|
+
elsif list_data.is_a?(Hash) && list_data[:id]
|
|
1529
|
+
# Single id hash: {id: "..."}
|
|
1530
|
+
[list_data[:id].to_s.strip]
|
|
1531
|
+
else
|
|
1532
|
+
[]
|
|
1533
|
+
end
|
|
1534
|
+
end
|
|
1535
|
+
|
|
1536
|
+
# Build combined AIEE identifier from "and"-separated identifiers
|
|
1537
|
+
# @param parsed [Hash] parsed combined AIEE data
|
|
1538
|
+
# @return [Identifiers::CombinedAiee] combined AIEE identifier
|
|
1539
|
+
def build_combined_aiee(parsed)
|
|
1540
|
+
# Build each AIEE identifier using AIEE builder
|
|
1541
|
+
aiee_builder = Aiee::Builder.new
|
|
1542
|
+
first_id = aiee_builder.build(parsed[:first_aiee])
|
|
1543
|
+
second_id = aiee_builder.build(parsed[:second_aiee])
|
|
1544
|
+
|
|
1545
|
+
# Create a simple combined identifier (reuse DualPublished pattern)
|
|
1546
|
+
Identifiers::DualPublished.new(
|
|
1547
|
+
first_identifier: first_id,
|
|
1548
|
+
second_identifier: second_id,
|
|
1549
|
+
separator: " and ",
|
|
1550
|
+
)
|
|
1551
|
+
end
|
|
1552
|
+
end
|
|
1553
|
+
end
|
|
1554
|
+
end
|