pubid 1.15.19 → 2.0.0.pre.alpha.2
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 +2041 -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/ccsds/update_codes.yaml +1 -0
- data/data/iec/update_codes.yaml +67 -0
- data/data/ieee/update_codes.yaml +104 -0
- data/data/iso/update_codes.yaml +21 -0
- data/data/nist/update_codes.yaml +89 -0
- data/data/plateau/update_codes.yaml +6 -0
- data/lib/pubid/amca/builder.rb +176 -0
- data/lib/pubid/amca/identifier.rb +57 -0
- data/lib/pubid/amca/identifiers/base.rb +64 -0
- data/lib/pubid/amca/identifiers/interpretation.rb +51 -0
- data/lib/pubid/amca/identifiers/publication.rb +47 -0
- data/lib/pubid/amca/identifiers/standard.rb +22 -0
- data/lib/pubid/amca/identifiers.rb +12 -0
- data/lib/pubid/amca/parser.rb +153 -0
- data/lib/pubid/amca/scheme.rb +16 -0
- data/lib/pubid/amca/single_identifier.rb +33 -0
- data/lib/pubid/amca/urn_generator.rb +50 -0
- data/lib/pubid/amca.rb +26 -0
- data/lib/pubid/ansi/builder.rb +52 -0
- data/lib/pubid/ansi/identifier.rb +55 -0
- data/lib/pubid/ansi/identifiers/american_national_standard.rb +12 -0
- data/lib/pubid/ansi/identifiers/standard.rb +16 -0
- data/lib/pubid/ansi/identifiers.rb +11 -0
- data/lib/pubid/ansi/parser.rb +91 -0
- data/lib/pubid/ansi/scheme.rb +15 -0
- data/lib/pubid/ansi/single_identifier.rb +45 -0
- data/lib/pubid/ansi/urn_generator.rb +76 -0
- data/lib/pubid/ansi.rb +27 -0
- data/lib/pubid/api/builder.rb +85 -0
- data/lib/pubid/api/components/code.rb +9 -0
- data/lib/pubid/api/identifier.rb +68 -0
- data/lib/pubid/api/identifiers/base.rb +24 -0
- data/lib/pubid/api/identifiers/bulletin.rb +15 -0
- data/lib/pubid/api/identifiers/continuous_operations_standard.rb +15 -0
- data/lib/pubid/api/identifiers/mpms.rb +44 -0
- data/lib/pubid/api/identifiers/publication.rb +15 -0
- data/lib/pubid/api/identifiers/recommended_practice.rb +15 -0
- data/lib/pubid/api/identifiers/specification.rb +15 -0
- data/lib/pubid/api/identifiers/standard.rb +15 -0
- data/lib/pubid/api/identifiers/technical_report.rb +15 -0
- data/lib/pubid/api/identifiers/typeless_standard.rb +27 -0
- data/lib/pubid/api/parser.rb +140 -0
- data/lib/pubid/api/scheme.rb +66 -0
- data/lib/pubid/api/single_identifier.rb +46 -0
- data/lib/pubid/api/urn_generator.rb +41 -0
- data/lib/pubid/api.rb +17 -0
- data/lib/pubid/ashrae/builder.rb +498 -0
- data/lib/pubid/ashrae/identifier.rb +57 -0
- data/lib/pubid/ashrae/identifiers/addenda_package.rb +46 -0
- data/lib/pubid/ashrae/identifiers/addendum.rb +55 -0
- data/lib/pubid/ashrae/identifiers/base.rb +23 -0
- data/lib/pubid/ashrae/identifiers/combined_addenda.rb +51 -0
- data/lib/pubid/ashrae/identifiers/errata.rb +40 -0
- data/lib/pubid/ashrae/identifiers/guideline.rb +38 -0
- data/lib/pubid/ashrae/identifiers/interpretation.rb +39 -0
- data/lib/pubid/ashrae/identifiers/standard.rb +38 -0
- data/lib/pubid/ashrae/identifiers.rb +16 -0
- data/lib/pubid/ashrae/parser.rb +724 -0
- data/lib/pubid/ashrae/scheme.rb +53 -0
- data/lib/pubid/ashrae/single_identifier.rb +23 -0
- data/lib/pubid/ashrae/supplement_identifier.rb +23 -0
- data/lib/pubid/ashrae/urn_generator.rb +59 -0
- data/lib/pubid/ashrae.rb +21 -0
- data/lib/pubid/asme/builder.rb +153 -0
- data/lib/pubid/asme/components/code.rb +18 -0
- data/lib/pubid/asme/identifier.rb +61 -0
- data/lib/pubid/asme/identifiers/base.rb +70 -0
- data/lib/pubid/asme/identifiers/standard.rb +12 -0
- data/lib/pubid/asme/identifiers.rb +10 -0
- data/lib/pubid/asme/parser.rb +308 -0
- data/lib/pubid/asme/scheme.rb +37 -0
- data/lib/pubid/asme/single_identifier.rb +29 -0
- data/lib/pubid/asme/urn_generator.rb +133 -0
- data/lib/pubid/asme.rb +21 -0
- data/lib/pubid/astm/builder.rb +159 -0
- data/lib/pubid/astm/components/code.rb +33 -0
- data/lib/pubid/astm/identifier.rb +92 -0
- data/lib/pubid/astm/identifiers/adjunct.rb +21 -0
- data/lib/pubid/astm/identifiers/base.rb +13 -0
- data/lib/pubid/astm/identifiers/data_series.rb +25 -0
- data/lib/pubid/astm/identifiers/iso_dual_published.rb +74 -0
- data/lib/pubid/astm/identifiers/manual.rb +40 -0
- data/lib/pubid/astm/identifiers/monograph.rb +25 -0
- data/lib/pubid/astm/identifiers/research_report.rb +18 -0
- data/lib/pubid/astm/identifiers/standard.rb +52 -0
- data/lib/pubid/astm/identifiers/technical_report.rb +23 -0
- data/lib/pubid/astm/identifiers/work_in_progress.rb +21 -0
- data/lib/pubid/astm/parser.rb +244 -0
- data/lib/pubid/astm/scheme.rb +55 -0
- data/lib/pubid/astm/single_identifier.rb +25 -0
- data/lib/pubid/astm/urn_generator.rb +99 -0
- data/lib/pubid/astm.rb +38 -0
- data/lib/pubid/bsi/builder.rb +1483 -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 +87 -0
- data/lib/pubid/bsi/identifiers/addendum_document.rb +64 -0
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +95 -0
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +82 -0
- data/lib/pubid/bsi/identifiers/aerospace_standard.rb +118 -0
- data/lib/pubid/bsi/identifiers/amendment.rb +40 -0
- data/lib/pubid/bsi/identifiers/base.rb +11 -0
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +27 -0
- data/lib/pubid/bsi/identifiers/british_standard.rb +33 -0
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +114 -0
- data/lib/pubid/bsi/identifiers/committee_document.rb +51 -0
- data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +152 -0
- data/lib/pubid/bsi/identifiers/corrigendum.rb +28 -0
- data/lib/pubid/bsi/identifiers/detailed_specification.rb +69 -0
- data/lib/pubid/bsi/identifiers/disc.rb +56 -0
- data/lib/pubid/bsi/identifiers/draft_document.rb +71 -0
- data/lib/pubid/bsi/identifiers/electronic_book.rb +52 -0
- data/lib/pubid/bsi/identifiers/expert_commentary.rb +47 -0
- data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +82 -0
- data/lib/pubid/bsi/identifiers/flex.rb +61 -0
- data/lib/pubid/bsi/identifiers/handbook.rb +39 -0
- data/lib/pubid/bsi/identifiers/index.rb +62 -0
- data/lib/pubid/bsi/identifiers/method.rb +76 -0
- data/lib/pubid/bsi/identifiers/national_annex.rb +73 -0
- data/lib/pubid/bsi/identifiers/practice_guide.rb +27 -0
- data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +79 -0
- data/lib/pubid/bsi/identifiers/published_document.rb +79 -0
- data/lib/pubid/bsi/identifiers/section.rb +62 -0
- data/lib/pubid/bsi/identifiers/set.rb +46 -0
- data/lib/pubid/bsi/identifiers/standalone_amendment.rb +40 -0
- data/lib/pubid/bsi/identifiers/supplement_document.rb +51 -0
- data/lib/pubid/bsi/identifiers/supplementary_index.rb +81 -0
- data/lib/pubid/bsi/identifiers/technical_specification.rb +79 -0
- data/lib/pubid/bsi/identifiers/test_method.rb +67 -0
- data/lib/pubid/bsi/identifiers/value_added_publication.rb +52 -0
- data/lib/pubid/bsi/identifiers.rb +52 -0
- data/lib/pubid/bsi/model.rb +196 -0
- data/lib/pubid/bsi/parser.rb +659 -0
- data/lib/pubid/bsi/scheme.rb +243 -0
- data/lib/pubid/bsi/single_identifier.rb +129 -0
- data/lib/pubid/bsi/urn_generator.rb +84 -0
- data/lib/pubid/bsi.rb +32 -0
- data/lib/pubid/builder/base.rb +138 -0
- data/lib/pubid/bundled_identifier.rb +126 -0
- data/lib/pubid/ccsds/builder.rb +56 -0
- data/lib/pubid/ccsds/identifier.rb +84 -0
- data/lib/pubid/ccsds/identifiers/base.rb +89 -0
- data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +70 -0
- data/lib/pubid/ccsds/identifiers/corrigendum.rb +39 -0
- data/lib/pubid/ccsds/identifiers.rb +10 -0
- data/lib/pubid/ccsds/parser.rb +71 -0
- data/lib/pubid/ccsds/scheme.rb +57 -0
- data/lib/pubid/ccsds/single_identifier.rb +77 -0
- data/lib/pubid/ccsds/supplement_identifier.rb +33 -0
- data/lib/pubid/ccsds/urn_generator.rb +115 -0
- data/lib/pubid/ccsds.rb +21 -0
- data/lib/pubid/cen_cenelec/builder.rb +330 -0
- data/lib/pubid/cen_cenelec/identifier.rb +52 -0
- data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +40 -0
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +29 -0
- data/lib/pubid/cen_cenelec/identifiers/base.rb +75 -0
- data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +27 -0
- data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +61 -0
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +35 -0
- data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +41 -0
- data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +37 -0
- data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +28 -0
- data/lib/pubid/cen_cenelec/identifiers/fragment.rb +22 -0
- data/lib/pubid/cen_cenelec/identifiers/guide.rb +27 -0
- data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +27 -0
- data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +27 -0
- data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +35 -0
- data/lib/pubid/cen_cenelec/identifiers.rb +32 -0
- data/lib/pubid/cen_cenelec/parser.rb +144 -0
- data/lib/pubid/cen_cenelec/scheme.rb +164 -0
- data/lib/pubid/cen_cenelec/single_identifier.rb +130 -0
- data/lib/pubid/cen_cenelec/supplement_identifier.rb +48 -0
- data/lib/pubid/cen_cenelec/urn_generator.rb +129 -0
- data/lib/pubid/cen_cenelec.rb +21 -0
- data/lib/pubid/cie/builder.rb +399 -0
- data/lib/pubid/cie/components/code.rb +72 -0
- data/lib/pubid/cie/components/language.rb +58 -0
- data/lib/pubid/cie/identifier.rb +71 -0
- data/lib/pubid/cie/identifiers/bundle.rb +20 -0
- data/lib/pubid/cie/identifiers/conference.rb +32 -0
- data/lib/pubid/cie/identifiers/corrigendum.rb +40 -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/standard.rb +58 -0
- data/lib/pubid/cie/identifiers/supplement.rb +45 -0
- data/lib/pubid/cie/identifiers/tutorial_bundle.rb +20 -0
- data/lib/pubid/cie/identifiers.rb +17 -0
- data/lib/pubid/cie/parser.rb +347 -0
- data/lib/pubid/cie/scheme.rb +64 -0
- data/lib/pubid/cie/single_identifier.rb +30 -0
- data/lib/pubid/cie/supplement_identifier.rb +26 -0
- data/lib/pubid/cie/urn_generator.rb +123 -0
- data/lib/pubid/cie.rb +28 -0
- data/lib/pubid/components/code.rb +33 -0
- data/lib/pubid/components/date.rb +49 -0
- data/lib/pubid/components/edition.rb +32 -0
- data/lib/pubid/components/factory.rb +50 -0
- data/lib/pubid/components/language.rb +37 -0
- data/lib/pubid/components/locality.rb +10 -0
- data/lib/pubid/components/publisher.rb +36 -0
- data/lib/pubid/components/stage.rb +54 -0
- data/lib/pubid/components/type.rb +58 -0
- data/lib/pubid/components/typed_stage.rb +59 -0
- data/lib/pubid/components.rb +16 -0
- data/lib/pubid/core/pattern_doc_generator.rb +272 -0
- data/lib/pubid/core/update_codes.rb +77 -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 +27 -0
- data/lib/pubid/csa/identifier.rb +513 -0
- data/lib/pubid/csa/identifiers/base.rb +133 -0
- data/lib/pubid/csa/identifiers/bundled.rb +125 -0
- data/lib/pubid/csa/identifiers/canadian_adopted.rb +82 -0
- data/lib/pubid/csa/identifiers/cec.rb +129 -0
- data/lib/pubid/csa/identifiers/combined.rb +130 -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 +127 -0
- data/lib/pubid/csa/identifiers/standard.rb +10 -0
- data/lib/pubid/csa/identifiers.rb +17 -0
- data/lib/pubid/csa/parser.rb +445 -0
- data/lib/pubid/csa/scheme.rb +44 -0
- data/lib/pubid/csa/single_identifier.rb +30 -0
- data/lib/pubid/csa/urn_generator.rb +80 -0
- data/lib/pubid/csa/wrapper_identifier.rb +31 -0
- data/lib/pubid/csa.rb +25 -0
- data/lib/pubid/etsi/builder.rb +133 -0
- data/lib/pubid/etsi/components/code.rb +42 -0
- data/lib/pubid/etsi/components/version.rb +37 -0
- data/lib/pubid/etsi/components.rb +10 -0
- data/lib/pubid/etsi/identifier.rb +57 -0
- data/lib/pubid/etsi/identifiers/amendment.rb +15 -0
- data/lib/pubid/etsi/identifiers/base.rb +38 -0
- data/lib/pubid/etsi/identifiers/corrigendum.rb +15 -0
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +19 -0
- data/lib/pubid/etsi/identifiers/supplement_identifier.rb +91 -0
- data/lib/pubid/etsi/identifiers.rb +14 -0
- data/lib/pubid/etsi/parser.rb +133 -0
- data/lib/pubid/etsi/scheme.rb +42 -0
- data/lib/pubid/etsi/urn_generator.rb +76 -0
- data/lib/pubid/etsi.rb +21 -0
- data/lib/pubid/export/auditor.rb +89 -0
- data/lib/pubid/export/data_class_exporter.rb +59 -0
- data/lib/pubid/export/exporter.rb +74 -0
- data/lib/pubid/export/flavor_exporter.rb +402 -0
- data/lib/pubid/export/ieee_exporter.rb +78 -0
- data/lib/pubid/export/itu_exporter.rb +66 -0
- data/lib/pubid/export/nist_exporter.rb +64 -0
- data/lib/pubid/export/registry_exporter.rb +90 -0
- data/lib/pubid/export/result.rb +97 -0
- data/lib/pubid/export/scheme_exporter.rb +70 -0
- data/lib/pubid/export.rb +18 -0
- data/lib/pubid/format_detector.rb +16 -0
- data/lib/pubid/format_registry.rb +42 -0
- data/lib/pubid/identifier.rb +242 -0
- data/lib/pubid/identifier_metadata.rb +148 -0
- data/lib/pubid/identifier_registry.rb +198 -0
- data/lib/pubid/idf/builder.rb +82 -0
- data/lib/pubid/idf/identifier.rb +129 -0
- data/lib/pubid/idf/identifiers/amendment.rb +27 -0
- data/lib/pubid/idf/identifiers/corrigendum.rb +27 -0
- data/lib/pubid/idf/identifiers/international_standard.rb +123 -0
- data/lib/pubid/idf/identifiers/reviewed_method.rb +100 -0
- data/lib/pubid/idf/identifiers.rb +13 -0
- data/lib/pubid/idf/parser.rb +143 -0
- data/lib/pubid/idf/scheme.rb +61 -0
- data/lib/pubid/idf/single_identifier.rb +19 -0
- data/lib/pubid/idf/supplement_identifier.rb +43 -0
- data/lib/pubid/idf/urn_generator.rb +84 -0
- data/lib/pubid/idf.rb +25 -0
- data/lib/pubid/iec/builder.rb +458 -0
- data/lib/pubid/iec/components/code.rb +60 -0
- data/lib/pubid/iec/components/consolidated_amendment.rb +59 -0
- data/lib/pubid/iec/components/publisher.rb +36 -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/identifier.rb +256 -0
- data/lib/pubid/iec/identifiers/amendment.rb +94 -0
- data/lib/pubid/iec/identifiers/base.rb +82 -0
- data/lib/pubid/iec/identifiers/component_specification.rb +39 -0
- data/lib/pubid/iec/identifiers/conformity_assessment.rb +39 -0
- data/lib/pubid/iec/identifiers/consolidated_identifier.rb +82 -0
- data/lib/pubid/iec/identifiers/corrigendum.rb +94 -0
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +137 -0
- data/lib/pubid/iec/identifiers/guide.rb +104 -0
- data/lib/pubid/iec/identifiers/international_standard.rb +147 -0
- data/lib/pubid/iec/identifiers/interpretation_sheet.rb +104 -0
- data/lib/pubid/iec/identifiers/operational_document.rb +39 -0
- data/lib/pubid/iec/identifiers/publicly_available_specification.rb +101 -0
- data/lib/pubid/iec/identifiers/sheet_identifier.rb +62 -0
- data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +40 -0
- data/lib/pubid/iec/identifiers/systems_reference_document.rb +40 -0
- data/lib/pubid/iec/identifiers/technical_report.rb +132 -0
- data/lib/pubid/iec/identifiers/technical_specification.rb +132 -0
- data/lib/pubid/iec/identifiers/technology_report.rb +39 -0
- data/lib/pubid/iec/identifiers/test_report_form.rb +78 -0
- data/lib/pubid/iec/identifiers/vap_identifier.rb +73 -0
- data/lib/pubid/iec/identifiers/white_paper.rb +39 -0
- data/lib/pubid/iec/identifiers/working_document.rb +96 -0
- data/lib/pubid/iec/parser.rb +417 -0
- data/lib/pubid/iec/rendering_style.rb +113 -0
- data/lib/pubid/iec/scheme.rb +71 -0
- data/lib/pubid/iec/single_identifier.rb +80 -0
- data/lib/pubid/iec/supplement_identifier.rb +161 -0
- data/lib/pubid/iec/urn_generator.rb +79 -0
- data/lib/pubid/iec/urn_parser.rb +90 -0
- data/lib/pubid/iec.rb +85 -0
- data/lib/pubid/ieee/aiee/builder.rb +71 -0
- data/lib/pubid/ieee/aiee/identifier.rb +105 -0
- data/lib/pubid/ieee/aiee/parser.rb +130 -0
- data/lib/pubid/ieee/aiee.rb +11 -0
- data/lib/pubid/ieee/builder.rb +1237 -0
- data/lib/pubid/ieee/components/code.rb +102 -0
- data/lib/pubid/ieee/components/draft.rb +93 -0
- data/lib/pubid/ieee/components/relationship.rb +157 -0
- data/lib/pubid/ieee/components/typed_stage.rb +100 -0
- data/lib/pubid/ieee/identifier.rb +54 -0
- data/lib/pubid/ieee/identifiers/adopted_standard.rb +33 -0
- data/lib/pubid/ieee/identifiers/base.rb +591 -0
- data/lib/pubid/ieee/identifiers/conformance_identifier.rb +35 -0
- data/lib/pubid/ieee/identifiers/corrigendum.rb +37 -0
- data/lib/pubid/ieee/identifiers/csa_dual_published.rb +51 -0
- data/lib/pubid/ieee/identifiers/dual_identifier.rb +18 -0
- data/lib/pubid/ieee/identifiers/dual_published.rb +28 -0
- data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +27 -0
- data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +34 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +172 -0
- data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +51 -0
- data/lib/pubid/ieee/identifiers/nesc/base.rb +56 -0
- data/lib/pubid/ieee/identifiers/nesc/draft.rb +28 -0
- data/lib/pubid/ieee/identifiers/nesc/handbook.rb +32 -0
- data/lib/pubid/ieee/identifiers/nesc/redline.rb +26 -0
- data/lib/pubid/ieee/identifiers/nesc/standard.rb +26 -0
- data/lib/pubid/ieee/identifiers/nesc.rb +15 -0
- data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +20 -0
- data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +26 -0
- data/lib/pubid/ieee/identifiers/redlined_standard.rb +33 -0
- data/lib/pubid/ieee/identifiers/si_standard.rb +73 -0
- data/lib/pubid/ieee/identifiers/standard.rb +41 -0
- data/lib/pubid/ieee/identifiers/supplement_identifier.rb +23 -0
- data/lib/pubid/ieee/identifiers.rb +33 -0
- data/lib/pubid/ieee/ire/builder.rb +61 -0
- data/lib/pubid/ieee/ire/identifier.rb +58 -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 +101 -0
- data/lib/pubid/ieee/nesc/parser.rb +154 -0
- data/lib/pubid/ieee/nesc.rb +10 -0
- data/lib/pubid/ieee/parser.rb +1226 -0
- data/lib/pubid/ieee/scheme.rb +90 -0
- data/lib/pubid/ieee/typed_stages.rb +172 -0
- data/lib/pubid/ieee/urn_generator.rb +188 -0
- data/lib/pubid/ieee.rb +32 -0
- data/lib/pubid/ieee_debug.rb +31 -0
- data/lib/pubid/iho/builder.rb +37 -0
- data/lib/pubid/iho/identifier.rb +61 -0
- data/lib/pubid/iho/identifiers/base.rb +41 -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 +14 -0
- data/lib/pubid/iho/parser.rb +68 -0
- data/lib/pubid/iho/scheme.rb +29 -0
- data/lib/pubid/iho/urn_generator.rb +29 -0
- data/lib/pubid/iho.rb +21 -0
- data/lib/pubid/iso/builder.rb +309 -0
- data/lib/pubid/iso/bundled_identifier.rb +85 -0
- data/lib/pubid/iso/combined_identifier.rb +22 -0
- data/lib/pubid/iso/components/code.rb +36 -0
- data/lib/pubid/iso/components/publisher.rb +60 -0
- data/lib/pubid/iso/components.rb +12 -0
- data/lib/pubid/iso/format_resolver.rb +45 -0
- data/lib/pubid/iso/identifier.rb +330 -0
- data/lib/pubid/iso/identifiers/addendum.rb +104 -0
- data/lib/pubid/iso/identifiers/amendment.rb +128 -0
- data/lib/pubid/iso/identifiers/base.rb +115 -0
- data/lib/pubid/iso/identifiers/corrigendum.rb +108 -0
- data/lib/pubid/iso/identifiers/data.rb +76 -0
- data/lib/pubid/iso/identifiers/directives.rb +59 -0
- data/lib/pubid/iso/identifiers/directives_supplement.rb +119 -0
- data/lib/pubid/iso/identifiers/extract.rb +30 -0
- data/lib/pubid/iso/identifiers/guide.rb +100 -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 +89 -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 +87 -0
- data/lib/pubid/iso/identifiers/tc_document.rb +108 -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 +33 -0
- data/lib/pubid/iso/parser.rb +512 -0
- data/lib/pubid/iso/rendering_style.rb +120 -0
- data/lib/pubid/iso/scheme.rb +193 -0
- data/lib/pubid/iso/single_identifier.rb +64 -0
- data/lib/pubid/iso/supplement_identifier.rb +27 -0
- data/lib/pubid/iso/urn_generator.rb +426 -0
- data/lib/pubid/iso/urn_parser.rb +437 -0
- data/lib/pubid/iso/utilities.rb +86 -0
- data/lib/pubid/iso.rb +50 -0
- data/lib/pubid/itu/builder.rb +171 -0
- data/lib/pubid/itu/components/code.rb +39 -0
- data/lib/pubid/itu/components/sector.rb +35 -0
- data/lib/pubid/itu/components/series.rb +29 -0
- data/lib/pubid/itu/i18n.rb +9 -0
- data/lib/pubid/itu/i18n.yaml +30 -0
- data/lib/pubid/itu/identifier.rb +118 -0
- data/lib/pubid/itu/identifiers/amendment.rb +43 -0
- data/lib/pubid/itu/identifiers/annex.rb +74 -0
- data/lib/pubid/itu/identifiers/base.rb +154 -0
- data/lib/pubid/itu/identifiers/combined_identifier.rb +47 -0
- data/lib/pubid/itu/identifiers/corrigendum.rb +44 -0
- data/lib/pubid/itu/identifiers/recommendation.rb +16 -0
- data/lib/pubid/itu/identifiers/special_publication.rb +31 -0
- data/lib/pubid/itu/identifiers/supplement.rb +46 -0
- data/lib/pubid/itu/identifiers.rb +16 -0
- data/lib/pubid/itu/model.rb +111 -0
- data/lib/pubid/itu/parser.rb +225 -0
- data/lib/pubid/itu/scheme.rb +174 -0
- data/lib/pubid/itu/urn_generator.rb +105 -0
- data/lib/pubid/itu.rb +22 -0
- data/lib/pubid/jcgm/builder.rb +88 -0
- data/lib/pubid/jcgm/components/publisher.rb +20 -0
- data/lib/pubid/jcgm/components.rb +9 -0
- data/lib/pubid/jcgm/identifier.rb +54 -0
- data/lib/pubid/jcgm/identifiers/amendment.rb +35 -0
- data/lib/pubid/jcgm/identifiers/guide.rb +21 -0
- data/lib/pubid/jcgm/identifiers/gum_guide.rb +51 -0
- data/lib/pubid/jcgm/identifiers.rb +11 -0
- data/lib/pubid/jcgm/parser.rb +84 -0
- data/lib/pubid/jcgm/scheme.rb +60 -0
- data/lib/pubid/jcgm/single_identifier.rb +48 -0
- data/lib/pubid/jcgm/supplement_identifier.rb +16 -0
- data/lib/pubid/jcgm/urn_generator.rb +110 -0
- data/lib/pubid/jcgm.rb +31 -0
- data/lib/pubid/jis/builder.rb +124 -0
- data/lib/pubid/jis/components/code.rb +59 -0
- data/lib/pubid/jis/components.rb +9 -0
- data/lib/pubid/jis/identifier.rb +61 -0
- data/lib/pubid/jis/identifiers/amendment.rb +16 -0
- data/lib/pubid/jis/identifiers/base.rb +72 -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 +27 -0
- data/lib/pubid/jis/identifiers/technical_report.rb +31 -0
- data/lib/pubid/jis/identifiers/technical_specification.rb +31 -0
- data/lib/pubid/jis/identifiers.rb +17 -0
- data/lib/pubid/jis/parser.rb +109 -0
- data/lib/pubid/jis/scheme.rb +49 -0
- data/lib/pubid/jis/single_identifier.rb +37 -0
- data/lib/pubid/jis/supplement_identifier.rb +47 -0
- data/lib/pubid/jis/urn_generator.rb +25 -0
- data/lib/pubid/jis.rb +23 -0
- data/lib/pubid/lutaml/no_store_registration.rb +30 -0
- data/lib/pubid/nist/builder.rb +2269 -0
- data/lib/pubid/nist/components/code.rb +38 -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/publisher.rb +24 -0
- data/lib/pubid/nist/components/stage.rb +53 -0
- data/lib/pubid/nist/components/supplement.rb +188 -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 +19 -0
- data/lib/pubid/nist/configuration.rb +77 -0
- data/lib/pubid/nist/identifier.rb +62 -0
- data/lib/pubid/nist/identifiers/base.rb +578 -0
- data/lib/pubid/nist/identifiers/circular.rb +68 -0
- data/lib/pubid/nist/identifiers/circular_supplement.rb +50 -0
- data/lib/pubid/nist/identifiers/commercial_standard.rb +41 -0
- data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +56 -0
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +56 -0
- data/lib/pubid/nist/identifiers/crpl_report.rb +132 -0
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +104 -0
- data/lib/pubid/nist/identifiers/grant_contractor_report.rb +35 -0
- data/lib/pubid/nist/identifiers/handbook.rb +50 -0
- data/lib/pubid/nist/identifiers/internal_report.rb +56 -0
- data/lib/pubid/nist/identifiers/letter_circular.rb +45 -0
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +65 -0
- data/lib/pubid/nist/identifiers/monograph.rb +69 -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 +67 -0
- data/lib/pubid/nist/identifiers/special_publication.rb +36 -0
- data/lib/pubid/nist/identifiers/technical_note.rb +90 -0
- data/lib/pubid/nist/identifiers.rb +33 -0
- data/lib/pubid/nist/parser.rb +1117 -0
- data/lib/pubid/nist/scheme.rb +199 -0
- data/lib/pubid/nist/supplement_identifier.rb +67 -0
- data/lib/pubid/nist/urn_generator.rb +133 -0
- data/lib/pubid/nist.rb +37 -0
- data/lib/pubid/oiml/builder.rb +189 -0
- data/lib/pubid/oiml/components/code.rb +20 -0
- data/lib/pubid/oiml/components.rb +9 -0
- data/lib/pubid/oiml/identifier.rb +61 -0
- data/lib/pubid/oiml/identifiers/amendment.rb +13 -0
- data/lib/pubid/oiml/identifiers/annex.rb +62 -0
- data/lib/pubid/oiml/identifiers/base.rb +36 -0
- data/lib/pubid/oiml/identifiers/basic_publication.rb +13 -0
- data/lib/pubid/oiml/identifiers/document.rb +13 -0
- data/lib/pubid/oiml/identifiers/expert_report.rb +13 -0
- data/lib/pubid/oiml/identifiers/guide.rb +13 -0
- data/lib/pubid/oiml/identifiers/recommendation.rb +13 -0
- data/lib/pubid/oiml/identifiers/seminar_report.rb +13 -0
- data/lib/pubid/oiml/identifiers/vocabulary.rb +13 -0
- data/lib/pubid/oiml/identifiers.rb +18 -0
- data/lib/pubid/oiml/parser.rb +173 -0
- data/lib/pubid/oiml/scheme.rb +46 -0
- data/lib/pubid/oiml/single_identifier.rb +90 -0
- data/lib/pubid/oiml/supplement_identifier.rb +43 -0
- data/lib/pubid/oiml/urn_generator.rb +64 -0
- data/lib/pubid/oiml.rb +26 -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.rb +8 -0
- data/lib/pubid/parsers/base.rb +11 -0
- data/lib/pubid/parsers/mr_string.rb +93 -0
- data/lib/pubid/plateau/builder.rb +50 -0
- data/lib/pubid/plateau/identifier.rb +57 -0
- data/lib/pubid/plateau/identifiers/annex.rb +16 -0
- data/lib/pubid/plateau/identifiers/base.rb +51 -0
- data/lib/pubid/plateau/identifiers/handbook.rb +34 -0
- data/lib/pubid/plateau/identifiers/technical_report.rb +20 -0
- data/lib/pubid/plateau/identifiers.rb +12 -0
- data/lib/pubid/plateau/parser.rb +63 -0
- data/lib/pubid/plateau/scheme.rb +45 -0
- data/lib/pubid/plateau/supplement_identifier.rb +72 -0
- data/lib/pubid/plateau/urn_generator.rb +29 -0
- data/lib/pubid/plateau.rb +26 -0
- data/lib/pubid/renderers/base.rb +53 -0
- data/lib/pubid/renderers/directives_renderer.rb +61 -0
- data/lib/pubid/renderers/guide_renderer.rb +24 -0
- data/lib/pubid/renderers/human_readable.rb +70 -0
- data/lib/pubid/renderers/iwa_renderer.rb +20 -0
- data/lib/pubid/renderers/mr_string.rb +16 -0
- data/lib/pubid/renderers/supplement_renderer.rb +36 -0
- data/lib/pubid/renderers/urn.rb +11 -0
- data/lib/pubid/renderers.rb +14 -0
- data/lib/pubid/rendering/base.rb +73 -0
- data/lib/pubid/rendering/common.rb +211 -0
- data/lib/pubid/rendering/context.rb +159 -0
- data/lib/pubid/rendering/date.rb +27 -0
- data/lib/pubid/rendering/format.rb +25 -0
- data/lib/pubid/rendering/language.rb +21 -0
- data/lib/pubid/rendering/numbering.rb +24 -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 +16 -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 +19 -0
- data/lib/pubid/sae/components/type.rb +19 -0
- data/lib/pubid/sae/components.rb +11 -0
- data/lib/pubid/sae/identifier.rb +37 -0
- data/lib/pubid/sae/identifiers/base.rb +42 -0
- data/lib/pubid/sae/identifiers.rb +9 -0
- data/lib/pubid/sae/parser.rb +55 -0
- data/lib/pubid/sae/scheme.rb +47 -0
- data/lib/pubid/sae/urn_generator.rb +38 -0
- data/lib/pubid/sae.rb +19 -0
- data/lib/pubid/scheme.rb +219 -0
- data/lib/pubid/urn_generator/base.rb +110 -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.rb +137 -13
- data/lib/tasks/docs.rake +37 -0
- data/lib/tasks/export.rake +38 -0
- data/lib/tasks/website-data.json +7488 -0
- metadata +616 -171
- data/lib/pubid/registry.rb +0 -30
|
@@ -0,0 +1,1483 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Bsi
|
|
5
|
+
class Builder < Pubid::Builder::Base
|
|
6
|
+
def initialize(scheme)
|
|
7
|
+
@scheme = scheme
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.build(parsed_data, scheme = Scheme.new)
|
|
11
|
+
new(scheme).build(parsed_data)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def build(data)
|
|
15
|
+
data = flatten_array(data) if data.is_a?(Array)
|
|
16
|
+
|
|
17
|
+
# Store original data to check if BSI prefix was present
|
|
18
|
+
@original_data = data.dup
|
|
19
|
+
|
|
20
|
+
# Check for StandaloneAmendment first (very specific pattern)
|
|
21
|
+
if data[:standalone_amendment] || data[:parenthesized_amd]
|
|
22
|
+
return build_standalone_amendment(data)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Check for CommitteeDocument
|
|
26
|
+
if data[:committee_document]
|
|
27
|
+
return build_committee_document(data[:committee_document])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Check for Index identifier first
|
|
31
|
+
if data[:index_identifier]
|
|
32
|
+
return build_index(data[:index_identifier])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check for Supplementary Index identifier
|
|
36
|
+
if data[:supplementary_index_identifier]
|
|
37
|
+
return build_supplementary_index(data[:supplementary_index_identifier])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Check for Explanatory Supplement identifier
|
|
41
|
+
if data[:explanatory_supplement_identifier]
|
|
42
|
+
return build_explanatory_supplement(data[:explanatory_supplement_identifier])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check for Method identifier
|
|
46
|
+
if data[:method_identifier]
|
|
47
|
+
return build_method(data[:method_identifier])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Check for Test Method identifier
|
|
51
|
+
if data[:test_method_identifier]
|
|
52
|
+
return build_test_method(data[:test_method_identifier])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Check for Section identifier
|
|
56
|
+
if data[:section_identifier]
|
|
57
|
+
return build_section(data[:section_identifier])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Check for Detailed Specification identifier
|
|
61
|
+
if data[:detailed_specification]
|
|
62
|
+
return build_detailed_specification(data[:detailed_specification])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Check for DISC identifier
|
|
66
|
+
if data[:disc_identifier]
|
|
67
|
+
return build_disc(data[:disc_identifier])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Check for Aerospace identifier with letter suffix edition
|
|
71
|
+
if data[:aerospace_identifier]
|
|
72
|
+
return build_aerospace_identifier(data[:aerospace_identifier])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Check for SupplementDocument first
|
|
76
|
+
if data[:supplement_document]
|
|
77
|
+
return build_supplement_document(data[:supplement_document])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Check for AddendumDocument
|
|
81
|
+
if data[:addendum_document]
|
|
82
|
+
return build_addendum_document(data[:addendum_document])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Check for BundledIdentifier
|
|
86
|
+
if data[:bundled_parts] || data[:bundled_list]
|
|
87
|
+
return build_bundled_identifier(data)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Check for Set identifier
|
|
91
|
+
if data[:set]
|
|
92
|
+
return build_set(data[:set])
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Extract supplements before processing
|
|
96
|
+
supplements_data = extract_supplements(data)
|
|
97
|
+
|
|
98
|
+
# Check for Value-Added Publication wrapper first
|
|
99
|
+
if data[:pdf_format] || data[:tc_format] || data[:book_format]
|
|
100
|
+
return build_value_added_publication(data, supplements_data)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Check for National Annex first (most specific)
|
|
104
|
+
# NationalAnnex can have:
|
|
105
|
+
# - Own supplements: "NA+A1:2012 to BASE"
|
|
106
|
+
# - Adopted string: "NA to BS EN 1234"
|
|
107
|
+
if data[:na_prefix]
|
|
108
|
+
return build_national_annex(data, supplements_data)
|
|
109
|
+
elsif data[:adopted_string]
|
|
110
|
+
# Check for multi-level adoptions
|
|
111
|
+
identifier = build_adopted_identifier(data)
|
|
112
|
+
|
|
113
|
+
# Wrap with consolidated if supplements present
|
|
114
|
+
if supplements_data.any?
|
|
115
|
+
identifier = wrap_with_consolidated(identifier,
|
|
116
|
+
supplements_data)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Wrap with ExpertCommentary if needed
|
|
120
|
+
identifier = wrap_with_expert_commentary(identifier) if data[:expert_commentary]
|
|
121
|
+
|
|
122
|
+
return identifier
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Determine identifier class using Scheme
|
|
126
|
+
identifier = locate_identifier_klass(data).new
|
|
127
|
+
assign_attributes(identifier, data)
|
|
128
|
+
|
|
129
|
+
# Wrap with consolidated if supplements present
|
|
130
|
+
if supplements_data.any?
|
|
131
|
+
identifier = wrap_with_consolidated(identifier,
|
|
132
|
+
supplements_data)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Wrap with ExpertCommentary if needed
|
|
136
|
+
identifier = wrap_with_expert_commentary(identifier) if data[:expert_commentary]
|
|
137
|
+
|
|
138
|
+
identifier
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
def build_index(data)
|
|
144
|
+
# Extract values from the parsed data
|
|
145
|
+
data[:publisher]&.to_s
|
|
146
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
147
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
148
|
+
year_val = data[:year].to_i if data[:year]
|
|
149
|
+
|
|
150
|
+
# Extract index_suffix information
|
|
151
|
+
index_suffix_data = data[:index_suffix]
|
|
152
|
+
format = "space" # default
|
|
153
|
+
issue_number = nil
|
|
154
|
+
|
|
155
|
+
if index_suffix_data.is_a?(Hash)
|
|
156
|
+
if index_suffix_data[:colon_sep]
|
|
157
|
+
format = "colon"
|
|
158
|
+
elsif index_suffix_data[:issue_number]
|
|
159
|
+
issue_number = index_suffix_data[:issue_number].to_s
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Build attributes hash (conditional arguments must be handled separately)
|
|
164
|
+
attrs = {
|
|
165
|
+
number: Components::Code.new(value: number_val),
|
|
166
|
+
issue_number: issue_number,
|
|
167
|
+
index_format: format,
|
|
168
|
+
}
|
|
169
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
170
|
+
|
|
171
|
+
Identifiers::Index.new(attrs)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def build_supplementary_index(data)
|
|
175
|
+
# Extract values from the parsed data
|
|
176
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
177
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
178
|
+
year_val = data[:year].to_i if data[:year]
|
|
179
|
+
|
|
180
|
+
# Build attributes hash
|
|
181
|
+
attrs = {
|
|
182
|
+
number: Components::Code.new(value: number_val),
|
|
183
|
+
}
|
|
184
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
185
|
+
|
|
186
|
+
Identifiers::SupplementaryIndex.new(attrs)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def build_explanatory_supplement(data)
|
|
190
|
+
# Extract values from the parsed data
|
|
191
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
192
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
193
|
+
year_val = data[:year].to_i if data[:year]
|
|
194
|
+
|
|
195
|
+
# Extract part from parts array (e.g., [{part: "1"}] -> "1")
|
|
196
|
+
part_val = nil
|
|
197
|
+
if data[:parts].is_a?(Array) && !data[:parts].empty?
|
|
198
|
+
# Parts come as [{part: "1"}], so we need to extract the :part key
|
|
199
|
+
first_part = data[:parts][0]
|
|
200
|
+
if first_part.is_a?(Hash) && first_part[:part]
|
|
201
|
+
part_val = first_part[:part].to_s
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Build attributes hash
|
|
206
|
+
attrs = {
|
|
207
|
+
number: Components::Code.new(value: number_val),
|
|
208
|
+
}
|
|
209
|
+
attrs[:part] = Components::Code.new(value: part_val) if part_val
|
|
210
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
211
|
+
|
|
212
|
+
Identifiers::ExplanatorySupplement.new(attrs)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def build_method(data)
|
|
216
|
+
# Extract values from the parsed data
|
|
217
|
+
data[:publisher]&.to_s
|
|
218
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
219
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
220
|
+
year_val = data[:year].to_i if data[:year]
|
|
221
|
+
|
|
222
|
+
# Extract part from parts array (e.g., [{part: "1"}] -> "1")
|
|
223
|
+
part_val = nil
|
|
224
|
+
if data[:parts].is_a?(Array) && !data[:parts].empty?
|
|
225
|
+
# Parts come as [{part: "1"}], so we need to extract the :part key
|
|
226
|
+
first_part = data[:parts][0]
|
|
227
|
+
if first_part.is_a?(Hash) && first_part[:part]
|
|
228
|
+
part_val = first_part[:part].to_s
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Extract method_suffix information
|
|
233
|
+
method_suffix_data = data[:method_suffix]
|
|
234
|
+
method_code = nil
|
|
235
|
+
method_to = nil
|
|
236
|
+
method_and = nil
|
|
237
|
+
is_plural = false
|
|
238
|
+
|
|
239
|
+
if method_suffix_data.is_a?(Hash)
|
|
240
|
+
method_code = method_suffix_data[:method_code].to_s if method_suffix_data[:method_code]
|
|
241
|
+
method_to = method_suffix_data[:method_to].to_s if method_suffix_data[:method_to]
|
|
242
|
+
method_and = method_suffix_data[:method_and].to_s if method_suffix_data[:method_and]
|
|
243
|
+
# is_plural is true when we have method_to or method_and
|
|
244
|
+
is_plural = !method_to.nil? || !method_and.nil?
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Build attributes hash
|
|
248
|
+
attrs = {
|
|
249
|
+
number: Components::Code.new(value: number_val),
|
|
250
|
+
method_code: method_code,
|
|
251
|
+
method_to: method_to,
|
|
252
|
+
method_and: method_and,
|
|
253
|
+
is_plural: is_plural,
|
|
254
|
+
}
|
|
255
|
+
attrs[:part] = Components::Code.new(value: part_val) if part_val
|
|
256
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
257
|
+
|
|
258
|
+
Identifiers::Method.new(attrs)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def build_test_method(data)
|
|
262
|
+
# Extract values from the parsed data
|
|
263
|
+
# Format: BS {number}:{test_series}:{test_id}:{year}
|
|
264
|
+
publisher_val = data[:publisher].to_s if data[:publisher]
|
|
265
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
266
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
267
|
+
year_val = data[:year].to_i if data[:year]
|
|
268
|
+
|
|
269
|
+
# Extract test_method_suffix information
|
|
270
|
+
test_method_suffix_data = data[:test_method_suffix]
|
|
271
|
+
test_series = nil
|
|
272
|
+
test_id = nil
|
|
273
|
+
|
|
274
|
+
if test_method_suffix_data.is_a?(Hash)
|
|
275
|
+
test_series = test_method_suffix_data[:test_series].to_s if test_method_suffix_data[:test_series]
|
|
276
|
+
test_id = test_method_suffix_data[:test_id].to_s if test_method_suffix_data[:test_id]
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Build attributes hash
|
|
280
|
+
attrs = {
|
|
281
|
+
number: Components::Code.new(value: number_val),
|
|
282
|
+
test_series: test_series,
|
|
283
|
+
test_id: test_id,
|
|
284
|
+
}
|
|
285
|
+
if publisher_val
|
|
286
|
+
attrs[:publisher] =
|
|
287
|
+
Components::Publisher.new(body: publisher_val)
|
|
288
|
+
end
|
|
289
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
290
|
+
|
|
291
|
+
Identifiers::TestMethod.new(attrs)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def build_section(data)
|
|
295
|
+
# Extract values from the parsed data
|
|
296
|
+
# Publisher can come from :publisher (BS) or :type (DD, PD, etc.)
|
|
297
|
+
publisher_val = data[:publisher]&.to_s || data[:type]&.to_s
|
|
298
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
299
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
300
|
+
year_val = data[:year].to_i if data[:year]
|
|
301
|
+
|
|
302
|
+
# Extract section_suffix information
|
|
303
|
+
section_suffix_data = data[:section_suffix]
|
|
304
|
+
section_id = nil
|
|
305
|
+
format = "space" # default
|
|
306
|
+
|
|
307
|
+
if section_suffix_data.is_a?(Hash)
|
|
308
|
+
section_id = section_suffix_data[:section_id].to_s if section_suffix_data[:section_id]
|
|
309
|
+
format = "colon" if section_suffix_data[:colon_sep]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Build attributes hash (conditional arguments must be handled separately)
|
|
313
|
+
attrs = {
|
|
314
|
+
number: Components::Code.new(value: number_val),
|
|
315
|
+
section_id: section_id,
|
|
316
|
+
section_format: format,
|
|
317
|
+
}
|
|
318
|
+
if publisher_val
|
|
319
|
+
attrs[:publisher] =
|
|
320
|
+
Components::Publisher.new(body: publisher_val)
|
|
321
|
+
end
|
|
322
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
323
|
+
|
|
324
|
+
Identifiers::Section.new(attrs)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def build_detailed_specification(data)
|
|
328
|
+
# Extract values from the parsed data
|
|
329
|
+
# Format: "BS {number} N{code}:year" or "BS {number} C{range}:year"
|
|
330
|
+
publisher_val = data[:publisher].to_s if data[:publisher]
|
|
331
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
332
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
333
|
+
year_val = data[:year].to_i if data[:year]
|
|
334
|
+
|
|
335
|
+
# Extract detailed_spec_suffix information
|
|
336
|
+
detailed_spec_data = data[:detailed_spec_suffix]
|
|
337
|
+
spec_code = nil
|
|
338
|
+
if detailed_spec_data.is_a?(Hash) && detailed_spec_data[:spec_code]
|
|
339
|
+
spec_code = detailed_spec_data[:spec_code].to_s
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Build attributes hash
|
|
343
|
+
attrs = {
|
|
344
|
+
number: Components::Code.new(value: number_val),
|
|
345
|
+
}
|
|
346
|
+
attrs[:spec_code] = Components::Code.new(value: spec_code) if spec_code
|
|
347
|
+
if publisher_val
|
|
348
|
+
attrs[:publisher] =
|
|
349
|
+
Components::Publisher.new(body: publisher_val)
|
|
350
|
+
end
|
|
351
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
352
|
+
|
|
353
|
+
Identifiers::DetailedSpecification.new(attrs)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def build_disc(data)
|
|
357
|
+
# Extract values from the parsed data
|
|
358
|
+
# DISC format: "DISC PD {number}[-{part}]:{year}"
|
|
359
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
360
|
+
number_val ||= data[:number].to_s if data[:number]
|
|
361
|
+
year_val = data[:year].to_i if data[:year]
|
|
362
|
+
|
|
363
|
+
# Extract part from parts array (if present)
|
|
364
|
+
part_val = nil
|
|
365
|
+
if data[:parts]&.any?
|
|
366
|
+
parts_array = Array(data[:parts])
|
|
367
|
+
if parts_array.first && parts_array.first[:part]
|
|
368
|
+
part_val = parts_array.first[:part].to_s
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Build attributes hash
|
|
373
|
+
attrs = {
|
|
374
|
+
number: Components::Code.new(value: number_val),
|
|
375
|
+
}
|
|
376
|
+
attrs[:part] = Components::Code.new(value: part_val) if part_val
|
|
377
|
+
attrs[:publisher] = Components::Publisher.new(body: "DISC")
|
|
378
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
379
|
+
|
|
380
|
+
Identifiers::Disc.new(attrs)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def build_aerospace_identifier(data)
|
|
384
|
+
# Extract values from the parsed data
|
|
385
|
+
# Format: "BS AU {number}{letter_edition}[-{part}{letter_edition}]:{year}"
|
|
386
|
+
prefix_val = data[:prefix][:prefix] if data[:prefix].is_a?(Hash)
|
|
387
|
+
prefix_val ||= data[:prefix].to_s if data[:prefix]
|
|
388
|
+
|
|
389
|
+
# Extract number and letter edition
|
|
390
|
+
number_val = data[:number].to_s if data[:number]
|
|
391
|
+
|
|
392
|
+
# Letter edition is a sibling of number in the AST
|
|
393
|
+
edition_val = nil
|
|
394
|
+
if data[:letter_edition].is_a?(Hash)
|
|
395
|
+
edition_val = data[:letter_edition][:letter_edition].to_s
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Extract part directly (from :part key) or from :part_with_letter_edition
|
|
399
|
+
part_val = nil
|
|
400
|
+
part_edition_val = nil
|
|
401
|
+
|
|
402
|
+
# First check for direct :part key (when part_with_letter_edition is used in parser)
|
|
403
|
+
if data[:part]
|
|
404
|
+
if data[:part].is_a?(Hash)
|
|
405
|
+
part_val = data[:part][:part].to_s if data[:part][:part]
|
|
406
|
+
part_edition_val = data[:part][:letter_edition].to_s if data[:part][:letter_edition]
|
|
407
|
+
else
|
|
408
|
+
part_val = data[:part].to_s
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# Also check for :part_with_letter_edition key (for alternative patterns)
|
|
413
|
+
if !part_val && data[:part_with_letter_edition].is_a?(Hash)
|
|
414
|
+
part_val = data[:part_with_letter_edition][:part].to_s if data[:part_with_letter_edition][:part]
|
|
415
|
+
part_edition_val = data[:part_with_letter_edition][:letter_edition].to_s if data[:part_with_letter_edition][:letter_edition]
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Extract iteration (optional, may be empty)
|
|
419
|
+
iteration_val = nil
|
|
420
|
+
if data[:iteration] && data[:iteration][:iteration] && !data[:iteration][:iteration].empty?
|
|
421
|
+
iteration_val = data[:iteration][:iteration].to_s
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Extract year
|
|
425
|
+
year_val = data[:year].to_i if data[:year]
|
|
426
|
+
|
|
427
|
+
# Use part edition if present, otherwise use number edition
|
|
428
|
+
final_edition = part_edition_val || edition_val
|
|
429
|
+
|
|
430
|
+
# Build attributes hash
|
|
431
|
+
attrs = {
|
|
432
|
+
prefix: prefix_val,
|
|
433
|
+
number: Components::Code.new(value: number_val),
|
|
434
|
+
}
|
|
435
|
+
attrs[:part] = Components::Code.new(value: part_val) if part_val
|
|
436
|
+
attrs[:iteration] = iteration_val if iteration_val
|
|
437
|
+
attrs[:edition] = final_edition if final_edition
|
|
438
|
+
attrs[:publisher] = Components::Publisher.new(body: "BS")
|
|
439
|
+
attrs[:date] = Components::Date.new(year: year_val) if year_val
|
|
440
|
+
|
|
441
|
+
Identifiers::AerospaceStandard.new(attrs)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def build_bundled_identifier(data)
|
|
445
|
+
if data[:bundled_parts]
|
|
446
|
+
# Parts/Sections format: "BS 4048:Parts 1 and 2:1966"
|
|
447
|
+
parts_data = data[:bundled_parts]
|
|
448
|
+
base_number = parts_data[:number].to_s
|
|
449
|
+
bundle_type = parts_data[:bundle_type].to_s
|
|
450
|
+
part1 = parts_data[:part1].to_s
|
|
451
|
+
part2 = parts_data[:part2].to_s
|
|
452
|
+
year_val = parts_data[:year].to_i if parts_data[:year]
|
|
453
|
+
|
|
454
|
+
# Build base identifier
|
|
455
|
+
base_id = SingleIdentifier.new(
|
|
456
|
+
publisher: Components::Publisher.new(body: "BS"),
|
|
457
|
+
number: Components::Code.new(value: base_number),
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
# Build identifiers for each part
|
|
461
|
+
id1 = SingleIdentifier.new(
|
|
462
|
+
publisher: Components::Publisher.new(body: "BS"),
|
|
463
|
+
number: Components::Code.new(value: base_number),
|
|
464
|
+
part: Components::Code.new(value: part1),
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
id2 = SingleIdentifier.new(
|
|
468
|
+
publisher: Components::Publisher.new(body: "BS"),
|
|
469
|
+
number: Components::Code.new(value: base_number),
|
|
470
|
+
part: Components::Code.new(value: part2),
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
Identifiers::BundledIdentifier.new(
|
|
474
|
+
identifiers: [base_id, id1, id2],
|
|
475
|
+
bundle_type: bundle_type,
|
|
476
|
+
common_year: year_val ? Components::Date.new(year: year_val) : nil,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
elsif data[:bundled_list]
|
|
480
|
+
# List format: "BS SP 10 & 11:1949" or "BS 2SP 68 to BS 2SP 71:1973"
|
|
481
|
+
# bundled_list is an ARRAY of hashes
|
|
482
|
+
list_array = data[:bundled_list]
|
|
483
|
+
|
|
484
|
+
# First element has publisher/prefix/bundle_item
|
|
485
|
+
first_elem = list_array[0]
|
|
486
|
+
publisher_val = first_elem[:publisher]&.to_s || "BS"
|
|
487
|
+
prefix_val = first_elem[:prefix]&.to_s
|
|
488
|
+
|
|
489
|
+
items = []
|
|
490
|
+
separators = []
|
|
491
|
+
|
|
492
|
+
# Process first item
|
|
493
|
+
if first_elem[:bundle_item]
|
|
494
|
+
items << build_bundle_item(first_elem[:bundle_item], publisher_val,
|
|
495
|
+
prefix_val)
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
# Process remaining elements (may be separator+item or just year)
|
|
499
|
+
list_array[1..].each do |elem|
|
|
500
|
+
if elem[:year]
|
|
501
|
+
# Year element - will be extracted separately
|
|
502
|
+
next
|
|
503
|
+
elsif elem[:bundle_item]
|
|
504
|
+
# This element has separator + bundle_item
|
|
505
|
+
# Preserve separator case for "TO" vs "to"
|
|
506
|
+
sep = if elem[:sep_and]
|
|
507
|
+
" and "
|
|
508
|
+
elsif elem[:sep_to]
|
|
509
|
+
# Check if separator includes uppercase TO
|
|
510
|
+
to_case = elem[:sep_to][:to_case]&.to_s
|
|
511
|
+
to_case == "TO" ? " TO " : " to "
|
|
512
|
+
elsif elem[:sep_ampersand]
|
|
513
|
+
" & "
|
|
514
|
+
elsif elem[:sep_semicolon]
|
|
515
|
+
"; "
|
|
516
|
+
elsif elem[:sep_comma]
|
|
517
|
+
","
|
|
518
|
+
else
|
|
519
|
+
" and "
|
|
520
|
+
end
|
|
521
|
+
separators << sep
|
|
522
|
+
items << build_bundle_item(elem[:bundle_item], publisher_val,
|
|
523
|
+
prefix_val)
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Extract year from last element if present
|
|
528
|
+
year_elem = list_array.find { |e| e[:year] }
|
|
529
|
+
year_val = year_elem[:year].to_i if year_elem
|
|
530
|
+
|
|
531
|
+
Identifiers::BundledIdentifier.new(
|
|
532
|
+
identifiers: items,
|
|
533
|
+
separators: separators,
|
|
534
|
+
common_year: year_val ? Components::Date.new(year: year_val) : nil,
|
|
535
|
+
)
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def build_set(data)
|
|
540
|
+
# data is a hash with :set key containing an array of set items
|
|
541
|
+
# The parser returns: {set: [{set_item: {...}}, {set_item: {...}}, ...]}
|
|
542
|
+
# Extract the array from the hash
|
|
543
|
+
items_array = data[:set] || data
|
|
544
|
+
items_array = [items_array] unless items_array.is_a?(Array)
|
|
545
|
+
|
|
546
|
+
identifiers = []
|
|
547
|
+
|
|
548
|
+
items_array.each_with_index do |item, _i|
|
|
549
|
+
# Extract the actual item data from :set_item key
|
|
550
|
+
item_data = item[:set_item] || item
|
|
551
|
+
|
|
552
|
+
# Build string identifier for recursive parsing
|
|
553
|
+
# Note: item_data values are Parslet::Slice objects, need to convert to string
|
|
554
|
+
id_str = ""
|
|
555
|
+
|
|
556
|
+
# Publisher (BS)
|
|
557
|
+
if item_data[:publisher]
|
|
558
|
+
id_str += "#{item_data[:publisher]} "
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
# Adopted org (ISO, IEC, etc.)
|
|
562
|
+
if item_data[:adopted_org]
|
|
563
|
+
id_str += "#{item_data[:adopted_org]} "
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# Number
|
|
567
|
+
if item_data[:number]
|
|
568
|
+
number_val = if item_data[:number].is_a?(Hash)
|
|
569
|
+
item_data[:number][:number]&.to_s
|
|
570
|
+
else
|
|
571
|
+
item_data[:number].to_s
|
|
572
|
+
end
|
|
573
|
+
id_str += number_val.to_s if number_val
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# Add part if present (parts is an array from the parser)
|
|
577
|
+
if item_data[:parts].is_a?(Hash) && item_data[:parts][:parts]
|
|
578
|
+
parts_array = item_data[:parts][:parts]
|
|
579
|
+
if parts_array.is_a?(Array) && parts_array.any?
|
|
580
|
+
part_val = parts_array.first[:part]
|
|
581
|
+
id_str += "-#{part_val}"
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# Add year if present
|
|
586
|
+
if item_data[:year]
|
|
587
|
+
id_str += ":#{item_data[:year]}"
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# Skip if empty string
|
|
591
|
+
next if id_str.strip.empty?
|
|
592
|
+
|
|
593
|
+
# Recursively parse this identifier
|
|
594
|
+
parsed_id = Pubid::Bsi.parse(id_str)
|
|
595
|
+
identifiers << parsed_id if parsed_id
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
Identifiers::Set.new(
|
|
599
|
+
identifiers: identifiers,
|
|
600
|
+
separators: [" + "] * [0, identifiers.length - 1].max,
|
|
601
|
+
)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
def build_bundle_item(item_data, default_publisher, default_prefix)
|
|
605
|
+
# Extract values based on what's present
|
|
606
|
+
if item_data.is_a?(Hash)
|
|
607
|
+
# Check if publisher/prefix were EXPLICITLY present in parse
|
|
608
|
+
has_explicit_publisher = item_data.key?(:publisher)
|
|
609
|
+
has_explicit_prefix = item_data.key?(:prefix)
|
|
610
|
+
|
|
611
|
+
publisher_val = item_data[:publisher]&.to_s || default_publisher
|
|
612
|
+
prefix_val = item_data[:prefix]&.to_s || default_prefix
|
|
613
|
+
number_val = if item_data[:number].is_a?(Hash)
|
|
614
|
+
item_data[:number][:number]&.to_s
|
|
615
|
+
else
|
|
616
|
+
item_data[:number]&.to_s
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# Handle both dash-separated parts and space-separated parts
|
|
620
|
+
parts_val = item_data[:parts]
|
|
621
|
+
space_separated_part_val = item_data[:part]
|
|
622
|
+
else
|
|
623
|
+
# Simple string (alphanumeric like "N001" or just number)
|
|
624
|
+
has_explicit_publisher = false
|
|
625
|
+
has_explicit_prefix = false
|
|
626
|
+
publisher_val = default_publisher
|
|
627
|
+
prefix_val = default_prefix
|
|
628
|
+
number_val = item_data.to_s
|
|
629
|
+
parts_val = nil
|
|
630
|
+
space_separated_part_val = nil
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
id = SingleIdentifier.new(
|
|
634
|
+
publisher: Components::Publisher.new(body: publisher_val),
|
|
635
|
+
)
|
|
636
|
+
id.prefix = prefix_val if prefix_val && !prefix_val.empty?
|
|
637
|
+
id.number = Components::Code.new(value: number_val) if number_val
|
|
638
|
+
|
|
639
|
+
id.explicit_prefix = has_explicit_publisher || has_explicit_prefix
|
|
640
|
+
id.explicit_publisher = has_explicit_publisher
|
|
641
|
+
|
|
642
|
+
# Handle dash-separated parts (from parts array)
|
|
643
|
+
if parts_val.is_a?(Hash) && parts_val[:parts].is_a?(Array)
|
|
644
|
+
parts_array = parts_val[:parts]
|
|
645
|
+
if parts_array.any?
|
|
646
|
+
part_str = parts_array.first[:part].to_s
|
|
647
|
+
id.part = Components::Code.new(value: part_str)
|
|
648
|
+
end
|
|
649
|
+
# Handle space-separated part (direct part attribute)
|
|
650
|
+
elsif space_separated_part_val
|
|
651
|
+
id.part = Components::Code.new(value: space_separated_part_val.to_s)
|
|
652
|
+
# Mark this part as space-separated for rendering
|
|
653
|
+
id.space_separated_part = true
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
id
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
def wrap_with_expert_commentary(base_id)
|
|
660
|
+
# Determine format from original data
|
|
661
|
+
# Check for expert_commentary_full first (highest priority)
|
|
662
|
+
format = if @original_data[:expert_commentary_full]
|
|
663
|
+
"full"
|
|
664
|
+
elsif @original_data[:expert_commentary_topic]
|
|
665
|
+
"abbr_with_topic"
|
|
666
|
+
elsif @original_data[:expert_commentary]
|
|
667
|
+
"abbr"
|
|
668
|
+
else
|
|
669
|
+
"abbr" # Default
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
topic = @original_data[:expert_commentary_topic]&.to_s
|
|
673
|
+
|
|
674
|
+
Identifiers::ExpertCommentary.new(
|
|
675
|
+
base_identifier: base_id,
|
|
676
|
+
format: format,
|
|
677
|
+
topic: topic,
|
|
678
|
+
)
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
def build_supplement_document(data)
|
|
682
|
+
# Handle nested hash from parser (when using .as with alternatives)
|
|
683
|
+
data = data[:supplement_document] if data[:supplement_document].is_a?(Hash)
|
|
684
|
+
|
|
685
|
+
# Extract values from nested hashes (parser returns {:number => {:number => "1000"}})
|
|
686
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
687
|
+
iteration_val = data[:iteration][:iteration][0][:iteration] if data[:iteration].is_a?(Hash) && data[:iteration][:iteration].is_a?(Array) && data[:iteration][:iteration].any?
|
|
688
|
+
iteration_val = nil if iteration_val.is_a?(String) && iteration_val.empty?
|
|
689
|
+
parts_val = data[:parts][:parts] if data[:parts].is_a?(Hash)
|
|
690
|
+
flex_prefix_val = data[:flex_prefix].to_s if data[:flex_prefix]
|
|
691
|
+
|
|
692
|
+
# Check if this is reverse format: "Supplement No. N (YEAR) to BS NUMBER:YEAR"
|
|
693
|
+
if data[:supplement_number] && data[:supplement_year] && data[:publisher] && number_val && data[:base_year]
|
|
694
|
+
# Reverse format
|
|
695
|
+
reverse_format = true
|
|
696
|
+
base_year = data[:base_year]
|
|
697
|
+
else
|
|
698
|
+
reverse_format = false
|
|
699
|
+
base_year = data[:year]
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
# Build base identifier
|
|
703
|
+
base_data = {
|
|
704
|
+
publisher: data[:publisher],
|
|
705
|
+
number: number_val,
|
|
706
|
+
iteration: iteration_val,
|
|
707
|
+
parts: parts_val,
|
|
708
|
+
flex_prefix: flex_prefix_val,
|
|
709
|
+
year: base_year,
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
base_id = build(base_data)
|
|
713
|
+
|
|
714
|
+
# Determine supplement type (with or without "No.")
|
|
715
|
+
# Check if supp_no_prefix is "No." string or if it's nil/absent
|
|
716
|
+
supplement_type = if data[:supp_no_prefix] == "No."
|
|
717
|
+
"No."
|
|
718
|
+
elsif data[:supp_no_prefix]
|
|
719
|
+
data[:supp_no_prefix].to_s
|
|
720
|
+
else
|
|
721
|
+
""
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
Identifiers::SupplementDocument.new(
|
|
725
|
+
base_identifier: base_id,
|
|
726
|
+
supplement_number: data[:supplement_number].to_s,
|
|
727
|
+
supplement_year: data[:supplement_year].to_i,
|
|
728
|
+
supplement_type: supplement_type,
|
|
729
|
+
reverse_format: reverse_format,
|
|
730
|
+
separator: data[:supp_sep].to_s,
|
|
731
|
+
)
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
def build_addendum_document(data)
|
|
735
|
+
# Extract values from nested hashes (parser returns {:number => {:number => "1000"}})
|
|
736
|
+
number_val = data[:number][:number] if data[:number].is_a?(Hash)
|
|
737
|
+
iteration_val = data[:iteration][:iteration][0][:iteration] if data[:iteration].is_a?(Hash) && data[:iteration][:iteration].is_a?(Array) && data[:iteration][:iteration].any?
|
|
738
|
+
iteration_val = nil if iteration_val.is_a?(String) && iteration_val.empty?
|
|
739
|
+
parts_val = data[:parts][:parts] if data[:parts].is_a?(Hash)
|
|
740
|
+
flex_prefix_val = data[:flex_prefix].to_s if data[:flex_prefix]
|
|
741
|
+
|
|
742
|
+
# Build base identifier
|
|
743
|
+
base_data = {
|
|
744
|
+
publisher: data[:publisher],
|
|
745
|
+
number: number_val,
|
|
746
|
+
iteration: iteration_val,
|
|
747
|
+
parts: parts_val,
|
|
748
|
+
flex_prefix: flex_prefix_val,
|
|
749
|
+
year: data[:base_year],
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
base_id = build(base_data)
|
|
753
|
+
|
|
754
|
+
# Determine addendum type (with or without "No.")
|
|
755
|
+
addendum_type = if data[:add_no_prefix] == "No."
|
|
756
|
+
"No."
|
|
757
|
+
elsif data[:add_no_prefix]
|
|
758
|
+
data[:add_no_prefix].to_s
|
|
759
|
+
else
|
|
760
|
+
""
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
# Determine separator - use colon when add_sep is nil and base_year is present
|
|
764
|
+
add_sep = data[:add_sep]
|
|
765
|
+
if add_sep.nil? && data[:base_year]
|
|
766
|
+
add_sep = ":"
|
|
767
|
+
elsif add_sep.nil?
|
|
768
|
+
add_sep = ":"
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
Identifiers::AddendumDocument.new(
|
|
772
|
+
base_identifier: base_id,
|
|
773
|
+
addendum_number: data[:addendum_number].to_s,
|
|
774
|
+
addendum_year: data[:addendum_year].to_i,
|
|
775
|
+
addendum_type: addendum_type,
|
|
776
|
+
separator: add_sep.to_s,
|
|
777
|
+
)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def build_standalone_amendment(data)
|
|
781
|
+
# Extract from either standalone_amendment or parenthesized_amd key
|
|
782
|
+
amd_data = data[:standalone_amendment] || data[:parenthesized_amd]
|
|
783
|
+
|
|
784
|
+
# Handle nested hash if needed
|
|
785
|
+
amd_data = amd_data[:standalone_amendment] || amd_data[:parenthesized_amd] if amd_data.is_a?(Hash) && (amd_data[:standalone_amendment] || amd_data[:parenthesized_amd])
|
|
786
|
+
|
|
787
|
+
amendment_number = amd_data[:amendment_number].to_s if amd_data[:amendment_number]
|
|
788
|
+
corrigendum = !amd_data[:corrigendum].nil?
|
|
789
|
+
parenthesized = !data[:parenthesized_amd].nil?
|
|
790
|
+
|
|
791
|
+
attrs = {
|
|
792
|
+
amendment_number: Components::Code.new(value: amendment_number),
|
|
793
|
+
corrigendum: corrigendum,
|
|
794
|
+
parenthesized: parenthesized,
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
Identifiers::StandaloneAmendment.new(attrs)
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
def build_committee_document(data)
|
|
801
|
+
# Extract values from the parsed data
|
|
802
|
+
# Format: "YY/NNNNNNNN DC"
|
|
803
|
+
year_val = data[:year].to_s if data[:year]
|
|
804
|
+
document_number = data[:document_number].to_s if data[:document_number]
|
|
805
|
+
|
|
806
|
+
# Convert 2-digit year to 4-digit year (assuming 2000s for 00-99)
|
|
807
|
+
# Could also use a more sophisticated algorithm for year conversion
|
|
808
|
+
full_year = year_val ? "20#{year_val}" : nil
|
|
809
|
+
|
|
810
|
+
attrs = {
|
|
811
|
+
document_number: document_number,
|
|
812
|
+
}
|
|
813
|
+
attrs[:date] = Components::Date.new(year: full_year.to_i) if full_year
|
|
814
|
+
|
|
815
|
+
Identifiers::CommitteeDocument.new(attrs)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def build_value_added_publication(data, _supplements_data)
|
|
819
|
+
# Determine format type
|
|
820
|
+
format = if data[:pdf_format]
|
|
821
|
+
"PDF"
|
|
822
|
+
elsif data[:tc_format]
|
|
823
|
+
"TC"
|
|
824
|
+
elsif data[:book_format]
|
|
825
|
+
"BOOK"
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
# Remove VAP format flags from data before building base
|
|
829
|
+
base_data = data.dup
|
|
830
|
+
base_data.delete(:pdf_format)
|
|
831
|
+
base_data.delete(:tc_format)
|
|
832
|
+
base_data.delete(:book_format)
|
|
833
|
+
|
|
834
|
+
# Build base identifier (it will handle supplements via supplements_data)
|
|
835
|
+
base_id = build(base_data)
|
|
836
|
+
|
|
837
|
+
Identifiers::ValueAddedPublication.new(
|
|
838
|
+
base_identifier: base_id,
|
|
839
|
+
format: format,
|
|
840
|
+
)
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
def build_national_annex(data, _supplements_data)
|
|
844
|
+
# Build base identifier (what comes after "NA to")
|
|
845
|
+
base_data = data.dup
|
|
846
|
+
base_data.delete(:na_prefix)
|
|
847
|
+
base_data.delete(:na_supplements)
|
|
848
|
+
# DON'T delete base supplements! The base identifier can have its own supplements
|
|
849
|
+
# base_data.delete(:supplements) # REMOVED - base needs its supplements
|
|
850
|
+
|
|
851
|
+
# Recursively parse the base identifier (it will handle its own supplements)
|
|
852
|
+
base_id = build(base_data)
|
|
853
|
+
|
|
854
|
+
# Extract NA supplements from the CORRECT path: data[:na_prefix][:na_supplements]
|
|
855
|
+
# Parser nests them under na_prefix, not at top level
|
|
856
|
+
na_supp_raw = if data[:na_prefix].is_a?(Hash) && data[:na_prefix][:na_supplements]
|
|
857
|
+
data[:na_prefix][:na_supplements]
|
|
858
|
+
elsif data[:na_supplements]
|
|
859
|
+
# Fallback to top level if structure differs
|
|
860
|
+
data[:na_supplements]
|
|
861
|
+
else
|
|
862
|
+
nil
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
na_supp_data = if na_supp_raw
|
|
866
|
+
extract_supplements_from_array(Array(na_supp_raw))
|
|
867
|
+
else
|
|
868
|
+
[]
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
# Convert NA supplements to Amendment/Corrigendum objects with short year expansion
|
|
872
|
+
na_supps = na_supp_data.map do |supp|
|
|
873
|
+
# Expand short years to full years (15 -> 2015, 18 -> 2018)
|
|
874
|
+
year_val = supp[:year]&.to_s
|
|
875
|
+
if year_val && year_val.length == 2
|
|
876
|
+
year_int = year_val.to_i
|
|
877
|
+
# Assume 20XX for years 00-99
|
|
878
|
+
year_val = (2000 + year_int).to_s
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
if supp[:type] == :amendment
|
|
882
|
+
Identifiers::Amendment.new(
|
|
883
|
+
base_identifier: nil, # NA supplements don't wrap base
|
|
884
|
+
amendment_number: supp[:number],
|
|
885
|
+
amendment_year: year_val&.to_i,
|
|
886
|
+
separator: supp[:separator] || "+",
|
|
887
|
+
)
|
|
888
|
+
else
|
|
889
|
+
Identifiers::Corrigendum.new(
|
|
890
|
+
base_identifier: nil,
|
|
891
|
+
corrigendum_number: supp[:number],
|
|
892
|
+
corrigendum_year: year_val&.to_i,
|
|
893
|
+
separator: supp[:separator] || "+",
|
|
894
|
+
)
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
Identifiers::NationalAnnex.new(
|
|
899
|
+
na_supplements: na_supps,
|
|
900
|
+
base_doc: base_id,
|
|
901
|
+
)
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
def extract_supplements_from_array(supps_array)
|
|
905
|
+
return [] if supps_array.empty?
|
|
906
|
+
|
|
907
|
+
supps_array.map do |s|
|
|
908
|
+
supp_data = s.is_a?(Hash) && s[:supplement] ? s[:supplement] : s
|
|
909
|
+
|
|
910
|
+
# Determine separator - slash vs plus
|
|
911
|
+
separator = supp_data[:amd_sep_slash] ? "/" : "+"
|
|
912
|
+
|
|
913
|
+
{
|
|
914
|
+
type: supp_data[:amd_number] ? :amendment : :corrigendum,
|
|
915
|
+
number: (supp_data[:amd_number] || supp_data[:cor_number])&.to_s,
|
|
916
|
+
year: (supp_data[:amd_year] || supp_data[:cor_year])&.to_s,
|
|
917
|
+
separator: separator,
|
|
918
|
+
}
|
|
919
|
+
end
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
def locate_identifier_klass(parsed_hash)
|
|
923
|
+
# Special case: Flex documents
|
|
924
|
+
return Identifiers::Flex if parsed_hash[:flex_type]
|
|
925
|
+
|
|
926
|
+
# Special case: National Annex prefix
|
|
927
|
+
return Identifiers::NationalAnnex if parsed_hash[:na_prefix]
|
|
928
|
+
|
|
929
|
+
# Special case: Aerospace/Specialized prefix (BS A, BS AU, BS 2A, etc.)
|
|
930
|
+
return Identifiers::AerospaceStandard if parsed_hash[:prefix]
|
|
931
|
+
|
|
932
|
+
# Special case: Handle adopted identifiers
|
|
933
|
+
# Match "EN " followed by digit (not "EN ISO" or "EN IEC")
|
|
934
|
+
return Identifiers::AdoptedEuropeanNorm if parsed_hash[:adopted_string]&.match?(/^EN\s+\d/)
|
|
935
|
+
return Identifiers::AdoptedInternationalStandard if parsed_hash[:adopted_string]
|
|
936
|
+
|
|
937
|
+
# Use type to determine class via Scheme
|
|
938
|
+
type_str = parsed_hash[:type] || parsed_hash[:stage] || ""
|
|
939
|
+
typed_stage = @scheme.locate_typed_stage_by_abbr(type_str)
|
|
940
|
+
@scheme.locate_identifier_klass_by_type_code(typed_stage.type_code)
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
def cast(type, value)
|
|
944
|
+
case type
|
|
945
|
+
when :type
|
|
946
|
+
# Lookup from register
|
|
947
|
+
typed_stage = @scheme.locate_typed_stage_by_abbr(value || "")
|
|
948
|
+
{
|
|
949
|
+
stage: typed_stage.to_stage,
|
|
950
|
+
type: typed_stage.to_type,
|
|
951
|
+
typed_stage: typed_stage,
|
|
952
|
+
original_abbr: value.to_s, # Preserve original abbreviation
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
when :publisher
|
|
956
|
+
Components::Publisher.new(body: value.to_s)
|
|
957
|
+
|
|
958
|
+
when :prefix
|
|
959
|
+
# Specialized prefix (A, AU, C, M, 2A, etc.)
|
|
960
|
+
value&.to_s
|
|
961
|
+
|
|
962
|
+
when :flex_prefix
|
|
963
|
+
# Flex type prefix (CECC, E9111, M, etc.)
|
|
964
|
+
value&.to_s
|
|
965
|
+
|
|
966
|
+
when :number
|
|
967
|
+
Components::Code.new(value: value.to_s)
|
|
968
|
+
|
|
969
|
+
when :parts
|
|
970
|
+
# Extract parts - handle both formats:
|
|
971
|
+
# 1. Multi-level with separate keys: {:part=>"2", :subpart=>"1"}
|
|
972
|
+
# 2. Combined format: {:part=>"2-1"} (split by dash)
|
|
973
|
+
parts_array = Array(value)
|
|
974
|
+
if parts_array.any?
|
|
975
|
+
first_part = parts_array.first
|
|
976
|
+
part_str = first_part[:part].to_s
|
|
977
|
+
|
|
978
|
+
# Check if subpart is already separated (new format from part_with_subpart rule)
|
|
979
|
+
if first_part.key?(:subpart)
|
|
980
|
+
{
|
|
981
|
+
part: Components::Code.new(value: part_str),
|
|
982
|
+
subpart: Components::Code.new(value: first_part[:subpart].to_s),
|
|
983
|
+
}
|
|
984
|
+
else
|
|
985
|
+
# Old format - split on dash to get part and subpart
|
|
986
|
+
part_components = part_str.split("-")
|
|
987
|
+
result = { part: Components::Code.new(value: part_components.first) }
|
|
988
|
+
if part_components.length > 1
|
|
989
|
+
result[:subpart] =
|
|
990
|
+
Components::Code.new(value: part_components[1])
|
|
991
|
+
end
|
|
992
|
+
result
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
when :part
|
|
997
|
+
Components::Code.new(value: value[:part].to_s) if value.is_a?(Hash)
|
|
998
|
+
|
|
999
|
+
when :subpart
|
|
1000
|
+
Components::Code.new(value: value.to_s)
|
|
1001
|
+
|
|
1002
|
+
when :year, :date
|
|
1003
|
+
# Only create date if value is present
|
|
1004
|
+
if value.nil?
|
|
1005
|
+
nil
|
|
1006
|
+
else
|
|
1007
|
+
{ date: Components::Date.new(year: value.to_i) }
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
when :month
|
|
1011
|
+
value.to_i
|
|
1012
|
+
|
|
1013
|
+
when :edition
|
|
1014
|
+
value.to_s
|
|
1015
|
+
|
|
1016
|
+
when :flex_type, :na_prefix
|
|
1017
|
+
# Don't cast, used for class selection only
|
|
1018
|
+
nil
|
|
1019
|
+
|
|
1020
|
+
when :adopted_string
|
|
1021
|
+
# Handle both string and nested hash formats
|
|
1022
|
+
# Parser may return: "EN ISO 13485 Expert Commentary" (string)
|
|
1023
|
+
# or: {:adopted_string_content=>" EN ISO 13485 Expert Commentary"} (hash)
|
|
1024
|
+
if value.is_a?(Hash) && value[:adopted_string_content]
|
|
1025
|
+
value[:adopted_string_content].to_s.strip
|
|
1026
|
+
else
|
|
1027
|
+
value.to_s.strip
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
when :supplements
|
|
1031
|
+
# Handled separately by extract_supplements
|
|
1032
|
+
nil
|
|
1033
|
+
|
|
1034
|
+
when :expert_commentary
|
|
1035
|
+
# Handle nested hash from parser
|
|
1036
|
+
# Parser returns: {:expert_commentary_topic=>"Fire"} or {:expert_commentary_full=>"Expert Commentary"}
|
|
1037
|
+
if value.is_a?(Hash)
|
|
1038
|
+
if value[:expert_commentary_topic]
|
|
1039
|
+
@original_data[:expert_commentary_topic] =
|
|
1040
|
+
value[:expert_commentary_topic].to_s
|
|
1041
|
+
end
|
|
1042
|
+
if value[:expert_commentary_full]
|
|
1043
|
+
@original_data[:expert_commentary_full] =
|
|
1044
|
+
value[:expert_commentary_full].to_s
|
|
1045
|
+
end
|
|
1046
|
+
end
|
|
1047
|
+
true
|
|
1048
|
+
|
|
1049
|
+
when :expert_commentary_full
|
|
1050
|
+
# Don't cast, used for format detection
|
|
1051
|
+
nil
|
|
1052
|
+
|
|
1053
|
+
when :expert_commentary_topic
|
|
1054
|
+
# Don't cast, used for format detection
|
|
1055
|
+
nil
|
|
1056
|
+
|
|
1057
|
+
when :pdf_format, :tc_format, :book_format
|
|
1058
|
+
# Don't cast, used for VAP wrapper construction
|
|
1059
|
+
nil
|
|
1060
|
+
|
|
1061
|
+
when :translation_lang
|
|
1062
|
+
# Extract just the language name (e.g., "German", "Italian")
|
|
1063
|
+
value.to_s.capitalize
|
|
1064
|
+
|
|
1065
|
+
when :translation_upper
|
|
1066
|
+
# Uppercase translation like "SPANISH" -> "Spanish"
|
|
1067
|
+
value.to_s.capitalize
|
|
1068
|
+
|
|
1069
|
+
when :second_number
|
|
1070
|
+
# For collections like PAS 2035/2030
|
|
1071
|
+
Components::Code.new(value: value.to_s)
|
|
1072
|
+
|
|
1073
|
+
when :iteration
|
|
1074
|
+
# For bracket notation like 1000[9]
|
|
1075
|
+
value.to_s
|
|
1076
|
+
|
|
1077
|
+
when :index_identifier
|
|
1078
|
+
# Don't cast, handled by build_index
|
|
1079
|
+
nil
|
|
1080
|
+
|
|
1081
|
+
when :index_suffix
|
|
1082
|
+
# Don't cast, handled by build_index
|
|
1083
|
+
nil
|
|
1084
|
+
|
|
1085
|
+
when :method_identifier
|
|
1086
|
+
# Don't cast, handled by build_method
|
|
1087
|
+
nil
|
|
1088
|
+
|
|
1089
|
+
when :method_suffix
|
|
1090
|
+
# Don't cast, handled by build_method
|
|
1091
|
+
nil
|
|
1092
|
+
|
|
1093
|
+
when :section_identifier
|
|
1094
|
+
# Don't cast, handled by build_section
|
|
1095
|
+
nil
|
|
1096
|
+
|
|
1097
|
+
when :section_suffix
|
|
1098
|
+
# Don't cast, handled by build_section
|
|
1099
|
+
nil
|
|
1100
|
+
|
|
1101
|
+
when :detailed_specification
|
|
1102
|
+
# Don't cast, handled by build_detailed_specification
|
|
1103
|
+
nil
|
|
1104
|
+
|
|
1105
|
+
when :detailed_spec_suffix
|
|
1106
|
+
# Don't cast, handled by build_detailed_specification
|
|
1107
|
+
nil
|
|
1108
|
+
|
|
1109
|
+
when :spec_code
|
|
1110
|
+
Components::Code.new(value: value.to_s)
|
|
1111
|
+
|
|
1112
|
+
when :amendment_number
|
|
1113
|
+
Components::Code.new(value: value.to_s)
|
|
1114
|
+
|
|
1115
|
+
when :corrigendum
|
|
1116
|
+
!value.nil?
|
|
1117
|
+
|
|
1118
|
+
when :parenthesized_amd
|
|
1119
|
+
# Don't cast, used for format detection
|
|
1120
|
+
nil
|
|
1121
|
+
|
|
1122
|
+
when :standalone_amendment
|
|
1123
|
+
# Don't cast, handled by build_standalone_amendment
|
|
1124
|
+
nil
|
|
1125
|
+
|
|
1126
|
+
else
|
|
1127
|
+
value
|
|
1128
|
+
end
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
def build_adopted_identifier(data)
|
|
1132
|
+
# Extract the actual adopted string value from the parsed data
|
|
1133
|
+
# The parser may produce nested hash: {:adopted_string=>{:adopted_string=>"ISO 37101:2016"}}
|
|
1134
|
+
adopted_str_value = data[:adopted_string]
|
|
1135
|
+
adopted_str = if adopted_str_value.is_a?(Hash)
|
|
1136
|
+
adopted_str_value[:adopted_string] || adopted_str_value[:adopted_string_no_expert]
|
|
1137
|
+
else
|
|
1138
|
+
adopted_str_value
|
|
1139
|
+
end
|
|
1140
|
+
adopted_str = adopted_str.to_s.strip if adopted_str
|
|
1141
|
+
|
|
1142
|
+
return nil unless adopted_str && !adopted_str.empty?
|
|
1143
|
+
|
|
1144
|
+
# Check if this is a bare adopted identifier (no BSI/BS/PD prefix)
|
|
1145
|
+
# If data has no publisher/type/na_prefix/flex_type, it's a bare adopted identifier
|
|
1146
|
+
is_bare = !data[:publisher] && !data[:type] && !data[:na_prefix] && !data[:flex_type] && !data[:stage]
|
|
1147
|
+
|
|
1148
|
+
# Extract ExComm suffix before parsing (it should be preserved in data[:expert_commentary])
|
|
1149
|
+
# Remove it from adopted_string so ISO/IEC parsers don't choke on it
|
|
1150
|
+
# Handle all three formats: "Expert Commentary", "ExComm", "ExComm (Fire)"
|
|
1151
|
+
if adopted_str.end_with?("Expert Commentary")
|
|
1152
|
+
adopted_str = adopted_str.sub(/Expert Commentary$/, "")
|
|
1153
|
+
data[:expert_commentary_full] = "Expert Commentary"
|
|
1154
|
+
data[:expert_commentary] = true unless data.key?(:expert_commentary)
|
|
1155
|
+
# Update @original_data so wrap_with_expert_commentary can access it
|
|
1156
|
+
@original_data[:expert_commentary_full] = "Expert Commentary"
|
|
1157
|
+
unless @original_data.key?(:expert_commentary)
|
|
1158
|
+
@original_data[:expert_commentary] =
|
|
1159
|
+
true
|
|
1160
|
+
end
|
|
1161
|
+
elsif adopted_str.end_with?("ExComm (")
|
|
1162
|
+
adopted_str = adopted_str.sub(/ExComm \(.*\)$/, "")
|
|
1163
|
+
data[:expert_commentary_full] = "Expert Commentary"
|
|
1164
|
+
data[:expert_commentary] = true unless data.key?(:expert_commentary)
|
|
1165
|
+
@original_data[:expert_commentary_full] = "Expert Commentary"
|
|
1166
|
+
unless @original_data.key?(:expert_commentary)
|
|
1167
|
+
@original_data[:expert_commentary] =
|
|
1168
|
+
true
|
|
1169
|
+
end
|
|
1170
|
+
elsif adopted_str.include?("ExComm (")
|
|
1171
|
+
# Extract topic from "ExComm (Fire)"
|
|
1172
|
+
topic_match = adopted_str.match(/ExComm\s*\(([^)]+)\)/)
|
|
1173
|
+
adopted_str = adopted_str.sub(/ExComm\s*\(.*\)$/, "")
|
|
1174
|
+
data[:expert_commentary_topic] = topic_match[1] if topic_match
|
|
1175
|
+
data[:expert_commentary] = true unless data.key?(:expert_commentary)
|
|
1176
|
+
if topic_match
|
|
1177
|
+
@original_data[:expert_commentary_topic] =
|
|
1178
|
+
topic_match[1]
|
|
1179
|
+
end
|
|
1180
|
+
unless @original_data.key?(:expert_commentary)
|
|
1181
|
+
@original_data[:expert_commentary] =
|
|
1182
|
+
true
|
|
1183
|
+
end
|
|
1184
|
+
elsif adopted_str.match?(/ExComm\s*$/)
|
|
1185
|
+
# Abbreviated form "ExComm" at the end
|
|
1186
|
+
adopted_str = adopted_str.sub(/ExComm\s*$/, "")
|
|
1187
|
+
data[:expert_commentary] = true unless data.key?(:expert_commentary)
|
|
1188
|
+
unless @original_data.key?(:expert_commentary)
|
|
1189
|
+
@original_data[:expert_commentary] =
|
|
1190
|
+
true
|
|
1191
|
+
end
|
|
1192
|
+
end
|
|
1193
|
+
|
|
1194
|
+
# NEW: Extract translation suffix before parsing
|
|
1195
|
+
# Handle parenthetical format: "(French version)", "(Spanish Translation)"
|
|
1196
|
+
# We need to track whether "version" or "Translation" was present
|
|
1197
|
+
if adopted_str.match?(/\s*\([A-Za-z]+(?:\s+(?:Translation|version))?\)\s*$/)
|
|
1198
|
+
translation_match = adopted_str.match(/\s*\(([A-Za-z]+)(?:\s+(Translation|version))?\)\s*$/)
|
|
1199
|
+
if translation_match
|
|
1200
|
+
data[:translation_lang] = translation_match[1]
|
|
1201
|
+
# Track if "version" or "Translation" suffix was present
|
|
1202
|
+
if translation_match[2]
|
|
1203
|
+
data[:translation_suffix_type] =
|
|
1204
|
+
translation_match[2]
|
|
1205
|
+
end
|
|
1206
|
+
adopted_str = adopted_str.sub(
|
|
1207
|
+
/\s*\([A-Za-z]+(?:\s+(?:Translation|version))?\)\s*$/, ""
|
|
1208
|
+
)
|
|
1209
|
+
end
|
|
1210
|
+
# Handle all-caps format: "FRENCH TRANSLATION"
|
|
1211
|
+
elsif adopted_str.match?(/\s+(SPANISH|FRENCH|GERMAN|ITALIAN)\s+TRANSLATION\s*$/)
|
|
1212
|
+
translation_upper_match = adopted_str.match(/\s+(SPANISH|FRENCH|GERMAN|ITALIAN)\s+TRANSLATION\s*$/)
|
|
1213
|
+
if translation_upper_match
|
|
1214
|
+
data[:translation_upper] = translation_upper_match[1]
|
|
1215
|
+
# Track that "Translation" suffix was present
|
|
1216
|
+
data[:translation_suffix_type] = "Translation"
|
|
1217
|
+
adopted_str = adopted_str.sub(
|
|
1218
|
+
/\s+(SPANISH|FRENCH|GERMAN|ITALIAN)\s+TRANSLATION\s*$/, ""
|
|
1219
|
+
)
|
|
1220
|
+
end
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
# Only extract edition if NOT bare - bare identifiers should preserve edition internally
|
|
1224
|
+
edition_match = is_bare ? nil : adopted_str.match(/\s+ED(\d+)\s*$/)
|
|
1225
|
+
extracted_edition = edition_match ? edition_match[1] : nil
|
|
1226
|
+
# Remove edition from adopted string for recursive parsing (only if extracted)
|
|
1227
|
+
adopted_str_clean = if edition_match
|
|
1228
|
+
adopted_str.sub(/\s+ED\d+\s*$/,
|
|
1229
|
+
"")
|
|
1230
|
+
else
|
|
1231
|
+
adopted_str
|
|
1232
|
+
end
|
|
1233
|
+
|
|
1234
|
+
# Use extracted edition if no edition in data
|
|
1235
|
+
final_edition = data[:edition] || extracted_edition
|
|
1236
|
+
|
|
1237
|
+
# NEW: Extract reaffirmation notation like (R2004) before parsing
|
|
1238
|
+
# This is used for documents that have been reaffirmed
|
|
1239
|
+
# Example: "DD ISO/IEC 11177-1:1995 (R2004)"
|
|
1240
|
+
if adopted_str_clean.match?(/\s+\(R(\d{4})\)\s*$/)
|
|
1241
|
+
reaffirmation_match = adopted_str_clean.match(/\s+\(R(\d{4})\)\s*$/)
|
|
1242
|
+
if reaffirmation_match
|
|
1243
|
+
data[:reaffirmation_year] = reaffirmation_match[1]
|
|
1244
|
+
adopted_str_clean = adopted_str_clean.sub(/\s+\(R\d{4}\)\s*$/, "")
|
|
1245
|
+
end
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
# NEW: Extract BSI-style supplements from adopted_string before delegating to ISO/IEC
|
|
1249
|
+
# BSI uses +A1:2020 format, but ISO/IEC parsers can't handle this
|
|
1250
|
+
# Patterns: +A1:2020, +A11:2021, +AMD1:2001, +C1:2020
|
|
1251
|
+
extracted_supplements = []
|
|
1252
|
+
# Match patterns like: +A1:2020, +A11:2021, +AMD1:2001, +C1:2020, +COR1:2020
|
|
1253
|
+
# Must be at end of string or followed by space (not colon, which is part of date)
|
|
1254
|
+
adopted_str_clean = adopted_str_clean.gsub(/([+])(A(\d+)|AMD(\d+)|C(\d+)|COR(\d+)):(\d{4})(?:\s|$)/) do |_match|
|
|
1255
|
+
separator = $1 # "+" or "/"
|
|
1256
|
+
type_code = $2 || $3 || $4 || $5 || $6
|
|
1257
|
+
$2 || $3 || $4 || $5 || $6
|
|
1258
|
+
year = $7
|
|
1259
|
+
|
|
1260
|
+
# Determine supplement type
|
|
1261
|
+
supp_type = if type_code.start_with?("A", "AMD")
|
|
1262
|
+
:amendment
|
|
1263
|
+
elsif type_code.start_with?("C", "COR")
|
|
1264
|
+
:corrigendum
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
# Extract number from type code (A1 -> 1, AMD1 -> 1, C1 -> 1)
|
|
1268
|
+
supp_number = if type_code.start_with?("AMD")
|
|
1269
|
+
type_code.sub("AMD", "")
|
|
1270
|
+
else
|
|
1271
|
+
type_code.sub(/^[AC]/, "")
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
extracted_supplements << {
|
|
1275
|
+
type: supp_type,
|
|
1276
|
+
number: supp_number,
|
|
1277
|
+
year: year,
|
|
1278
|
+
separator: separator,
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
"" # Remove from adopted_string
|
|
1282
|
+
end.strip
|
|
1283
|
+
|
|
1284
|
+
# Extract AMD without year - "AMD5" or "AMD AA"
|
|
1285
|
+
# These don't have + or / prefix and don't have a year
|
|
1286
|
+
# Note: \s* (optional whitespace) after AMD to handle "AMD5" vs "AMD 5"
|
|
1287
|
+
adopted_str_clean = adopted_str_clean.gsub(/\s+AMD\s*(AA|\d+)(?:\s|$)/i) do |match|
|
|
1288
|
+
amd_number = match.strip.sub(/^AMD\s*/i, "")
|
|
1289
|
+
extracted_supplements << {
|
|
1290
|
+
type: :amendment,
|
|
1291
|
+
number: amd_number,
|
|
1292
|
+
year: nil,
|
|
1293
|
+
separator: nil, # No separator for AMD without year
|
|
1294
|
+
}
|
|
1295
|
+
"" # Remove from adopted_string
|
|
1296
|
+
end.strip
|
|
1297
|
+
|
|
1298
|
+
# Determine the BSI prefix to use (BS, PD, DD)
|
|
1299
|
+
bsi_prefix = if data[:type]
|
|
1300
|
+
data[:type].to_s # PD, DD, etc.
|
|
1301
|
+
elsif data[:publisher]
|
|
1302
|
+
data[:publisher].to_s # BS
|
|
1303
|
+
else
|
|
1304
|
+
"BS" # Default
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
# Multi-level adoption hierarchy (check most specific first):
|
|
1308
|
+
# 1. BS EN ISO/IEC (triple-level)
|
|
1309
|
+
# 2. BS ISO/IEC (double-level)
|
|
1310
|
+
# 3. BS EN (double-level)
|
|
1311
|
+
# 4. Bare ISO/IEC/EN (return as-is)
|
|
1312
|
+
|
|
1313
|
+
adopted_id = nil
|
|
1314
|
+
|
|
1315
|
+
# Check for EN ISO or EN IEC patterns (triple-level)
|
|
1316
|
+
if adopted_str_clean.match?(/EN\s+(ISO\/IEC|IEC|ISO)/)
|
|
1317
|
+
# Parse the ISO/IEC part
|
|
1318
|
+
iso_iec_str = adopted_str_clean.sub(/^EN\s+/, "")
|
|
1319
|
+
|
|
1320
|
+
if iso_iec_str.start_with?("ISO/IEC") || iso_iec_str.include?("ISO/IEC")
|
|
1321
|
+
adopted_id = Pubid::Iso.parse(iso_iec_str)
|
|
1322
|
+
elsif iso_iec_str.start_with?("ISO")
|
|
1323
|
+
adopted_id = Pubid::Iso.parse(iso_iec_str)
|
|
1324
|
+
elsif iso_iec_str.start_with?("IEC")
|
|
1325
|
+
adopted_id = Pubid::Iec.parse(iso_iec_str)
|
|
1326
|
+
end
|
|
1327
|
+
|
|
1328
|
+
# Wrap ISO/IEC identifier in EN adoption
|
|
1329
|
+
if adopted_id
|
|
1330
|
+
adopted_id = Pubid::CenCenelec::Identifiers::AdoptedEuropeanNorm.new(
|
|
1331
|
+
publisher: ["EN"],
|
|
1332
|
+
adopted_identifier: adopted_id,
|
|
1333
|
+
)
|
|
1334
|
+
end
|
|
1335
|
+
|
|
1336
|
+
# Check for direct ISO/IEC patterns (double-level: BS ISO, BS IEC or bare ISO/IEC)
|
|
1337
|
+
elsif adopted_str_clean.start_with?("ISO/IEC") || adopted_str_clean.include?("ISO/IEC")
|
|
1338
|
+
adopted_id = Pubid::Iso.parse(adopted_str_clean)
|
|
1339
|
+
elsif adopted_str_clean.start_with?("ISO")
|
|
1340
|
+
adopted_id = Pubid::Iso.parse(adopted_str_clean)
|
|
1341
|
+
elsif adopted_str_clean.start_with?("IEC")
|
|
1342
|
+
adopted_id = Pubid::Iec.parse(adopted_str_clean)
|
|
1343
|
+
|
|
1344
|
+
# Check for EN patterns (double-level: BS EN or DD/PD CEN) or CEN types
|
|
1345
|
+
elsif adopted_str_clean.start_with?("EN", "CEN", "CLC", "CR", "ES",
|
|
1346
|
+
"ENV", "HD", "CWA")
|
|
1347
|
+
adopted_id = Pubid::CenCenelec.parse(adopted_str_clean)
|
|
1348
|
+
# Check for CISPR
|
|
1349
|
+
elsif adopted_str_clean.start_with?("CISPR")
|
|
1350
|
+
adopted_id = Pubid::Iec.parse(adopted_str_clean)
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
# If this is a bare adopted identifier (no BSI prefix), return it as-is
|
|
1354
|
+
return adopted_id if is_bare && adopted_id
|
|
1355
|
+
|
|
1356
|
+
# Return appropriate wrapper based on adoption type
|
|
1357
|
+
if adopted_id
|
|
1358
|
+
# If adopted_id is a CEN identifier (in Cen module), use AdoptedEuropeanNorm
|
|
1359
|
+
identifier = if adopted_id.class.name.start_with?("Pubid::CenCenelec::")
|
|
1360
|
+
Identifiers::AdoptedEuropeanNorm.new(
|
|
1361
|
+
publisher: Components::Publisher.new(body: bsi_prefix),
|
|
1362
|
+
adopted_identifier: adopted_id,
|
|
1363
|
+
edition: final_edition&.to_s,
|
|
1364
|
+
translation_lang: data[:translation_lang]&.to_s,
|
|
1365
|
+
translation_upper: data[:translation_upper]&.to_s,
|
|
1366
|
+
# Pass expert_commentary data so ConsolidatedIdentifier can render it
|
|
1367
|
+
expert_commentary: data[:expert_commentary],
|
|
1368
|
+
# Pass expert_commentary_topic if present
|
|
1369
|
+
expert_commentary_topic: data[:expert_commentary_topic],
|
|
1370
|
+
# Pass translation_suffix_type for rendering
|
|
1371
|
+
translation_suffix_type: data[:translation_suffix_type]&.to_s,
|
|
1372
|
+
# Pass reaffirmation_year for rendering
|
|
1373
|
+
reaffirmation_year: data[:reaffirmation_year]&.to_s,
|
|
1374
|
+
)
|
|
1375
|
+
else
|
|
1376
|
+
# Otherwise it's ISO/IEC, use AdoptedInternationalStandard
|
|
1377
|
+
Identifiers::AdoptedInternationalStandard.new(
|
|
1378
|
+
publisher: Components::Publisher.new(body: bsi_prefix),
|
|
1379
|
+
adopted_identifier: adopted_id,
|
|
1380
|
+
edition: final_edition&.to_s,
|
|
1381
|
+
translation_lang: data[:translation_lang]&.to_s,
|
|
1382
|
+
translation_upper: data[:translation_upper]&.to_s,
|
|
1383
|
+
# Pass expert_commentary data ONLY if no supplements
|
|
1384
|
+
# When supplements are present, ConsolidatedIdentifier will add ExComm later
|
|
1385
|
+
expert_commentary: data[:expert_commentary] && extracted_supplements.none?,
|
|
1386
|
+
# Pass expert_commentary_topic if present and no supplements
|
|
1387
|
+
expert_commentary_topic: (data[:expert_commentary_topic] if extracted_supplements.none?),
|
|
1388
|
+
# Pass translation_suffix_type for rendering
|
|
1389
|
+
translation_suffix_type: data[:translation_suffix_type]&.to_s,
|
|
1390
|
+
# Pass reaffirmation_year for rendering
|
|
1391
|
+
reaffirmation_year: data[:reaffirmation_year]&.to_s,
|
|
1392
|
+
)
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
# NEW: Wrap with supplements if any were extracted from adopted_string
|
|
1396
|
+
# This must happen BEFORE wrapping with ExpertCommentary so that supplements
|
|
1397
|
+
# render before ExComm suffix
|
|
1398
|
+
if extracted_supplements.any?
|
|
1399
|
+
# When supplements are present, wrap with ConsolidatedIdentifier
|
|
1400
|
+
# Pass expert_commentary data so ConsolidatedIdentifier can render it later
|
|
1401
|
+
identifier = wrap_with_consolidated(
|
|
1402
|
+
identifier,
|
|
1403
|
+
extracted_supplements,
|
|
1404
|
+
expert_commentary: data[:expert_commentary],
|
|
1405
|
+
expert_commentary_topic: data[:expert_commentary_topic],
|
|
1406
|
+
)
|
|
1407
|
+
elsif data[:expert_commentary]
|
|
1408
|
+
# When no supplements but ExComm present, wrap with ExpertCommentary
|
|
1409
|
+
identifier = wrap_with_expert_commentary(identifier)
|
|
1410
|
+
end
|
|
1411
|
+
|
|
1412
|
+
identifier
|
|
1413
|
+
end
|
|
1414
|
+
end
|
|
1415
|
+
|
|
1416
|
+
def wrap_with_consolidated(base_identifier, supplements_data,
|
|
1417
|
+
expert_commentary: nil, expert_commentary_topic: nil)
|
|
1418
|
+
# If expert_commentary data is provided, set it on the base_identifier
|
|
1419
|
+
# This allows ConsolidatedIdentifier to render the ExComm suffix correctly
|
|
1420
|
+
if expert_commentary
|
|
1421
|
+
base_attrs = base_identifier.class.attributes
|
|
1422
|
+
if base_attrs.key?(:expert_commentary)
|
|
1423
|
+
base_identifier.expert_commentary = expert_commentary
|
|
1424
|
+
end
|
|
1425
|
+
if expert_commentary_topic && base_attrs.key?(:expert_commentary_topic)
|
|
1426
|
+
base_identifier.expert_commentary_topic = expert_commentary_topic
|
|
1427
|
+
end
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
supplement_ids = supplements_data.map do |supp|
|
|
1431
|
+
# Expand short years to full years (15 -> 2015, 18 -> 2018)
|
|
1432
|
+
year_val = supp[:year]&.to_s
|
|
1433
|
+
if year_val && year_val.length == 2
|
|
1434
|
+
year_int = year_val.to_i
|
|
1435
|
+
# Assume 20XX for years 00-99
|
|
1436
|
+
year_val = (2000 + year_int).to_s
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
if supp[:type] == :amendment
|
|
1440
|
+
Identifiers::Amendment.new(
|
|
1441
|
+
base_identifier: base_identifier,
|
|
1442
|
+
amendment_number: supp[:number],
|
|
1443
|
+
amendment_year: year_val&.to_i,
|
|
1444
|
+
separator: supp[:separator] || "+",
|
|
1445
|
+
)
|
|
1446
|
+
else
|
|
1447
|
+
Identifiers::Corrigendum.new(
|
|
1448
|
+
base_identifier: base_identifier,
|
|
1449
|
+
corrigendum_number: supp[:number],
|
|
1450
|
+
corrigendum_year: year_val&.to_i,
|
|
1451
|
+
separator: supp[:separator] || "+",
|
|
1452
|
+
)
|
|
1453
|
+
end
|
|
1454
|
+
end
|
|
1455
|
+
|
|
1456
|
+
Identifiers::ConsolidatedIdentifier.new(
|
|
1457
|
+
identifiers: [base_identifier] + supplement_ids,
|
|
1458
|
+
)
|
|
1459
|
+
end
|
|
1460
|
+
|
|
1461
|
+
def extract_supplements(data)
|
|
1462
|
+
return [] unless data[:supplements]
|
|
1463
|
+
|
|
1464
|
+
supps_array = data[:supplements]
|
|
1465
|
+
return [] if supps_array.empty?
|
|
1466
|
+
|
|
1467
|
+
supps_array.map do |s|
|
|
1468
|
+
supp_data = s.is_a?(Hash) && s[:supplement] ? s[:supplement] : s
|
|
1469
|
+
|
|
1470
|
+
# Determine separator - slash vs plus
|
|
1471
|
+
separator = supp_data[:amd_sep_slash] ? "/" : "+"
|
|
1472
|
+
|
|
1473
|
+
{
|
|
1474
|
+
type: supp_data[:amd_number] ? :amendment : :corrigendum,
|
|
1475
|
+
number: (supp_data[:amd_number] || supp_data[:cor_number])&.to_s,
|
|
1476
|
+
year: (supp_data[:amd_year] || supp_data[:cor_year])&.to_s,
|
|
1477
|
+
separator: separator,
|
|
1478
|
+
}
|
|
1479
|
+
end
|
|
1480
|
+
end
|
|
1481
|
+
end
|
|
1482
|
+
end
|
|
1483
|
+
end
|