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.
Files changed (604) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.adoc +2041 -53
  4. data/archived-gems/pubid-ccsds/update_codes.yaml +1 -0
  5. data/archived-gems/pubid-iec/stages.yaml +129 -0
  6. data/archived-gems/pubid-iec/update_codes.yaml +67 -0
  7. data/archived-gems/pubid-ieee/update_codes.yaml +104 -0
  8. data/archived-gems/pubid-iso/stages.yaml +106 -0
  9. data/archived-gems/pubid-iso/update_codes.yaml +4 -0
  10. data/archived-gems/pubid-itu/i18n.yaml +13 -0
  11. data/archived-gems/pubid-itu/series.yaml +42 -0
  12. data/archived-gems/pubid-nist/publishers.yaml +6 -0
  13. data/archived-gems/pubid-nist/series.yaml +121 -0
  14. data/archived-gems/pubid-nist/stages.yaml +16 -0
  15. data/archived-gems/pubid-nist/update_codes.yaml +93 -0
  16. data/archived-gems/pubid-plateau/update_codes.yaml +6 -0
  17. data/data/ccsds/update_codes.yaml +1 -0
  18. data/data/iec/update_codes.yaml +67 -0
  19. data/data/ieee/update_codes.yaml +104 -0
  20. data/data/iso/update_codes.yaml +21 -0
  21. data/data/nist/update_codes.yaml +89 -0
  22. data/data/plateau/update_codes.yaml +6 -0
  23. data/lib/pubid/amca/builder.rb +176 -0
  24. data/lib/pubid/amca/identifier.rb +57 -0
  25. data/lib/pubid/amca/identifiers/base.rb +64 -0
  26. data/lib/pubid/amca/identifiers/interpretation.rb +51 -0
  27. data/lib/pubid/amca/identifiers/publication.rb +47 -0
  28. data/lib/pubid/amca/identifiers/standard.rb +22 -0
  29. data/lib/pubid/amca/identifiers.rb +12 -0
  30. data/lib/pubid/amca/parser.rb +153 -0
  31. data/lib/pubid/amca/scheme.rb +16 -0
  32. data/lib/pubid/amca/single_identifier.rb +33 -0
  33. data/lib/pubid/amca/urn_generator.rb +50 -0
  34. data/lib/pubid/amca.rb +26 -0
  35. data/lib/pubid/ansi/builder.rb +52 -0
  36. data/lib/pubid/ansi/identifier.rb +55 -0
  37. data/lib/pubid/ansi/identifiers/american_national_standard.rb +12 -0
  38. data/lib/pubid/ansi/identifiers/standard.rb +16 -0
  39. data/lib/pubid/ansi/identifiers.rb +11 -0
  40. data/lib/pubid/ansi/parser.rb +91 -0
  41. data/lib/pubid/ansi/scheme.rb +15 -0
  42. data/lib/pubid/ansi/single_identifier.rb +45 -0
  43. data/lib/pubid/ansi/urn_generator.rb +76 -0
  44. data/lib/pubid/ansi.rb +27 -0
  45. data/lib/pubid/api/builder.rb +85 -0
  46. data/lib/pubid/api/components/code.rb +9 -0
  47. data/lib/pubid/api/identifier.rb +68 -0
  48. data/lib/pubid/api/identifiers/base.rb +24 -0
  49. data/lib/pubid/api/identifiers/bulletin.rb +15 -0
  50. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +15 -0
  51. data/lib/pubid/api/identifiers/mpms.rb +44 -0
  52. data/lib/pubid/api/identifiers/publication.rb +15 -0
  53. data/lib/pubid/api/identifiers/recommended_practice.rb +15 -0
  54. data/lib/pubid/api/identifiers/specification.rb +15 -0
  55. data/lib/pubid/api/identifiers/standard.rb +15 -0
  56. data/lib/pubid/api/identifiers/technical_report.rb +15 -0
  57. data/lib/pubid/api/identifiers/typeless_standard.rb +27 -0
  58. data/lib/pubid/api/parser.rb +140 -0
  59. data/lib/pubid/api/scheme.rb +66 -0
  60. data/lib/pubid/api/single_identifier.rb +46 -0
  61. data/lib/pubid/api/urn_generator.rb +41 -0
  62. data/lib/pubid/api.rb +17 -0
  63. data/lib/pubid/ashrae/builder.rb +498 -0
  64. data/lib/pubid/ashrae/identifier.rb +57 -0
  65. data/lib/pubid/ashrae/identifiers/addenda_package.rb +46 -0
  66. data/lib/pubid/ashrae/identifiers/addendum.rb +55 -0
  67. data/lib/pubid/ashrae/identifiers/base.rb +23 -0
  68. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +51 -0
  69. data/lib/pubid/ashrae/identifiers/errata.rb +40 -0
  70. data/lib/pubid/ashrae/identifiers/guideline.rb +38 -0
  71. data/lib/pubid/ashrae/identifiers/interpretation.rb +39 -0
  72. data/lib/pubid/ashrae/identifiers/standard.rb +38 -0
  73. data/lib/pubid/ashrae/identifiers.rb +16 -0
  74. data/lib/pubid/ashrae/parser.rb +724 -0
  75. data/lib/pubid/ashrae/scheme.rb +53 -0
  76. data/lib/pubid/ashrae/single_identifier.rb +23 -0
  77. data/lib/pubid/ashrae/supplement_identifier.rb +23 -0
  78. data/lib/pubid/ashrae/urn_generator.rb +59 -0
  79. data/lib/pubid/ashrae.rb +21 -0
  80. data/lib/pubid/asme/builder.rb +153 -0
  81. data/lib/pubid/asme/components/code.rb +18 -0
  82. data/lib/pubid/asme/identifier.rb +61 -0
  83. data/lib/pubid/asme/identifiers/base.rb +70 -0
  84. data/lib/pubid/asme/identifiers/standard.rb +12 -0
  85. data/lib/pubid/asme/identifiers.rb +10 -0
  86. data/lib/pubid/asme/parser.rb +308 -0
  87. data/lib/pubid/asme/scheme.rb +37 -0
  88. data/lib/pubid/asme/single_identifier.rb +29 -0
  89. data/lib/pubid/asme/urn_generator.rb +133 -0
  90. data/lib/pubid/asme.rb +21 -0
  91. data/lib/pubid/astm/builder.rb +159 -0
  92. data/lib/pubid/astm/components/code.rb +33 -0
  93. data/lib/pubid/astm/identifier.rb +92 -0
  94. data/lib/pubid/astm/identifiers/adjunct.rb +21 -0
  95. data/lib/pubid/astm/identifiers/base.rb +13 -0
  96. data/lib/pubid/astm/identifiers/data_series.rb +25 -0
  97. data/lib/pubid/astm/identifiers/iso_dual_published.rb +74 -0
  98. data/lib/pubid/astm/identifiers/manual.rb +40 -0
  99. data/lib/pubid/astm/identifiers/monograph.rb +25 -0
  100. data/lib/pubid/astm/identifiers/research_report.rb +18 -0
  101. data/lib/pubid/astm/identifiers/standard.rb +52 -0
  102. data/lib/pubid/astm/identifiers/technical_report.rb +23 -0
  103. data/lib/pubid/astm/identifiers/work_in_progress.rb +21 -0
  104. data/lib/pubid/astm/parser.rb +244 -0
  105. data/lib/pubid/astm/scheme.rb +55 -0
  106. data/lib/pubid/astm/single_identifier.rb +25 -0
  107. data/lib/pubid/astm/urn_generator.rb +99 -0
  108. data/lib/pubid/astm.rb +38 -0
  109. data/lib/pubid/bsi/builder.rb +1483 -0
  110. data/lib/pubid/bsi/components/code.rb +11 -0
  111. data/lib/pubid/bsi/components/date.rb +11 -0
  112. data/lib/pubid/bsi/components/publisher.rb +11 -0
  113. data/lib/pubid/bsi/components/type.rb +11 -0
  114. data/lib/pubid/bsi/identifier.rb +87 -0
  115. data/lib/pubid/bsi/identifiers/addendum_document.rb +64 -0
  116. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +95 -0
  117. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +82 -0
  118. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +118 -0
  119. data/lib/pubid/bsi/identifiers/amendment.rb +40 -0
  120. data/lib/pubid/bsi/identifiers/base.rb +11 -0
  121. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +27 -0
  122. data/lib/pubid/bsi/identifiers/british_standard.rb +33 -0
  123. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +114 -0
  124. data/lib/pubid/bsi/identifiers/committee_document.rb +51 -0
  125. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +152 -0
  126. data/lib/pubid/bsi/identifiers/corrigendum.rb +28 -0
  127. data/lib/pubid/bsi/identifiers/detailed_specification.rb +69 -0
  128. data/lib/pubid/bsi/identifiers/disc.rb +56 -0
  129. data/lib/pubid/bsi/identifiers/draft_document.rb +71 -0
  130. data/lib/pubid/bsi/identifiers/electronic_book.rb +52 -0
  131. data/lib/pubid/bsi/identifiers/expert_commentary.rb +47 -0
  132. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +82 -0
  133. data/lib/pubid/bsi/identifiers/flex.rb +61 -0
  134. data/lib/pubid/bsi/identifiers/handbook.rb +39 -0
  135. data/lib/pubid/bsi/identifiers/index.rb +62 -0
  136. data/lib/pubid/bsi/identifiers/method.rb +76 -0
  137. data/lib/pubid/bsi/identifiers/national_annex.rb +73 -0
  138. data/lib/pubid/bsi/identifiers/practice_guide.rb +27 -0
  139. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +79 -0
  140. data/lib/pubid/bsi/identifiers/published_document.rb +79 -0
  141. data/lib/pubid/bsi/identifiers/section.rb +62 -0
  142. data/lib/pubid/bsi/identifiers/set.rb +46 -0
  143. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +40 -0
  144. data/lib/pubid/bsi/identifiers/supplement_document.rb +51 -0
  145. data/lib/pubid/bsi/identifiers/supplementary_index.rb +81 -0
  146. data/lib/pubid/bsi/identifiers/technical_specification.rb +79 -0
  147. data/lib/pubid/bsi/identifiers/test_method.rb +67 -0
  148. data/lib/pubid/bsi/identifiers/value_added_publication.rb +52 -0
  149. data/lib/pubid/bsi/identifiers.rb +52 -0
  150. data/lib/pubid/bsi/model.rb +196 -0
  151. data/lib/pubid/bsi/parser.rb +659 -0
  152. data/lib/pubid/bsi/scheme.rb +243 -0
  153. data/lib/pubid/bsi/single_identifier.rb +129 -0
  154. data/lib/pubid/bsi/urn_generator.rb +84 -0
  155. data/lib/pubid/bsi.rb +32 -0
  156. data/lib/pubid/builder/base.rb +138 -0
  157. data/lib/pubid/bundled_identifier.rb +126 -0
  158. data/lib/pubid/ccsds/builder.rb +56 -0
  159. data/lib/pubid/ccsds/identifier.rb +84 -0
  160. data/lib/pubid/ccsds/identifiers/base.rb +89 -0
  161. data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +70 -0
  162. data/lib/pubid/ccsds/identifiers/corrigendum.rb +39 -0
  163. data/lib/pubid/ccsds/identifiers.rb +10 -0
  164. data/lib/pubid/ccsds/parser.rb +71 -0
  165. data/lib/pubid/ccsds/scheme.rb +57 -0
  166. data/lib/pubid/ccsds/single_identifier.rb +77 -0
  167. data/lib/pubid/ccsds/supplement_identifier.rb +33 -0
  168. data/lib/pubid/ccsds/urn_generator.rb +115 -0
  169. data/lib/pubid/ccsds.rb +21 -0
  170. data/lib/pubid/cen_cenelec/builder.rb +330 -0
  171. data/lib/pubid/cen_cenelec/identifier.rb +52 -0
  172. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +40 -0
  173. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +29 -0
  174. data/lib/pubid/cen_cenelec/identifiers/base.rb +75 -0
  175. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +28 -0
  176. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +27 -0
  177. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +28 -0
  178. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +61 -0
  179. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +35 -0
  180. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +41 -0
  181. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +37 -0
  182. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +28 -0
  183. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +22 -0
  184. data/lib/pubid/cen_cenelec/identifiers/guide.rb +27 -0
  185. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +27 -0
  186. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +27 -0
  187. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +35 -0
  188. data/lib/pubid/cen_cenelec/identifiers.rb +32 -0
  189. data/lib/pubid/cen_cenelec/parser.rb +144 -0
  190. data/lib/pubid/cen_cenelec/scheme.rb +164 -0
  191. data/lib/pubid/cen_cenelec/single_identifier.rb +130 -0
  192. data/lib/pubid/cen_cenelec/supplement_identifier.rb +48 -0
  193. data/lib/pubid/cen_cenelec/urn_generator.rb +129 -0
  194. data/lib/pubid/cen_cenelec.rb +21 -0
  195. data/lib/pubid/cie/builder.rb +399 -0
  196. data/lib/pubid/cie/components/code.rb +72 -0
  197. data/lib/pubid/cie/components/language.rb +58 -0
  198. data/lib/pubid/cie/identifier.rb +71 -0
  199. data/lib/pubid/cie/identifiers/bundle.rb +20 -0
  200. data/lib/pubid/cie/identifiers/conference.rb +32 -0
  201. data/lib/pubid/cie/identifiers/corrigendum.rb +40 -0
  202. data/lib/pubid/cie/identifiers/dual_published.rb +41 -0
  203. data/lib/pubid/cie/identifiers/identical.rb +64 -0
  204. data/lib/pubid/cie/identifiers/joint_published.rb +52 -0
  205. data/lib/pubid/cie/identifiers/standard.rb +58 -0
  206. data/lib/pubid/cie/identifiers/supplement.rb +45 -0
  207. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +20 -0
  208. data/lib/pubid/cie/identifiers.rb +17 -0
  209. data/lib/pubid/cie/parser.rb +347 -0
  210. data/lib/pubid/cie/scheme.rb +64 -0
  211. data/lib/pubid/cie/single_identifier.rb +30 -0
  212. data/lib/pubid/cie/supplement_identifier.rb +26 -0
  213. data/lib/pubid/cie/urn_generator.rb +123 -0
  214. data/lib/pubid/cie.rb +28 -0
  215. data/lib/pubid/components/code.rb +33 -0
  216. data/lib/pubid/components/date.rb +49 -0
  217. data/lib/pubid/components/edition.rb +32 -0
  218. data/lib/pubid/components/factory.rb +50 -0
  219. data/lib/pubid/components/language.rb +37 -0
  220. data/lib/pubid/components/locality.rb +10 -0
  221. data/lib/pubid/components/publisher.rb +36 -0
  222. data/lib/pubid/components/stage.rb +54 -0
  223. data/lib/pubid/components/type.rb +58 -0
  224. data/lib/pubid/components/typed_stage.rb +59 -0
  225. data/lib/pubid/components.rb +16 -0
  226. data/lib/pubid/core/pattern_doc_generator.rb +272 -0
  227. data/lib/pubid/core/update_codes.rb +77 -0
  228. data/lib/pubid/core.rb +8 -0
  229. data/lib/pubid/csa/builder.rb +671 -0
  230. data/lib/pubid/csa/components/code.rb +9 -0
  231. data/lib/pubid/csa/components.rb +9 -0
  232. data/lib/pubid/csa/composite_identifier.rb +27 -0
  233. data/lib/pubid/csa/identifier.rb +513 -0
  234. data/lib/pubid/csa/identifiers/base.rb +133 -0
  235. data/lib/pubid/csa/identifiers/bundled.rb +125 -0
  236. data/lib/pubid/csa/identifiers/canadian_adopted.rb +82 -0
  237. data/lib/pubid/csa/identifiers/cec.rb +129 -0
  238. data/lib/pubid/csa/identifiers/combined.rb +130 -0
  239. data/lib/pubid/csa/identifiers/csa_adopted.rb +78 -0
  240. data/lib/pubid/csa/identifiers/package.rb +65 -0
  241. data/lib/pubid/csa/identifiers/series.rb +127 -0
  242. data/lib/pubid/csa/identifiers/standard.rb +10 -0
  243. data/lib/pubid/csa/identifiers.rb +17 -0
  244. data/lib/pubid/csa/parser.rb +445 -0
  245. data/lib/pubid/csa/scheme.rb +44 -0
  246. data/lib/pubid/csa/single_identifier.rb +30 -0
  247. data/lib/pubid/csa/urn_generator.rb +80 -0
  248. data/lib/pubid/csa/wrapper_identifier.rb +31 -0
  249. data/lib/pubid/csa.rb +25 -0
  250. data/lib/pubid/etsi/builder.rb +133 -0
  251. data/lib/pubid/etsi/components/code.rb +42 -0
  252. data/lib/pubid/etsi/components/version.rb +37 -0
  253. data/lib/pubid/etsi/components.rb +10 -0
  254. data/lib/pubid/etsi/identifier.rb +57 -0
  255. data/lib/pubid/etsi/identifiers/amendment.rb +15 -0
  256. data/lib/pubid/etsi/identifiers/base.rb +38 -0
  257. data/lib/pubid/etsi/identifiers/corrigendum.rb +15 -0
  258. data/lib/pubid/etsi/identifiers/etsi_standard.rb +19 -0
  259. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +91 -0
  260. data/lib/pubid/etsi/identifiers.rb +14 -0
  261. data/lib/pubid/etsi/parser.rb +133 -0
  262. data/lib/pubid/etsi/scheme.rb +42 -0
  263. data/lib/pubid/etsi/urn_generator.rb +76 -0
  264. data/lib/pubid/etsi.rb +21 -0
  265. data/lib/pubid/export/auditor.rb +89 -0
  266. data/lib/pubid/export/data_class_exporter.rb +59 -0
  267. data/lib/pubid/export/exporter.rb +74 -0
  268. data/lib/pubid/export/flavor_exporter.rb +402 -0
  269. data/lib/pubid/export/ieee_exporter.rb +78 -0
  270. data/lib/pubid/export/itu_exporter.rb +66 -0
  271. data/lib/pubid/export/nist_exporter.rb +64 -0
  272. data/lib/pubid/export/registry_exporter.rb +90 -0
  273. data/lib/pubid/export/result.rb +97 -0
  274. data/lib/pubid/export/scheme_exporter.rb +70 -0
  275. data/lib/pubid/export.rb +18 -0
  276. data/lib/pubid/format_detector.rb +16 -0
  277. data/lib/pubid/format_registry.rb +42 -0
  278. data/lib/pubid/identifier.rb +242 -0
  279. data/lib/pubid/identifier_metadata.rb +148 -0
  280. data/lib/pubid/identifier_registry.rb +198 -0
  281. data/lib/pubid/idf/builder.rb +82 -0
  282. data/lib/pubid/idf/identifier.rb +129 -0
  283. data/lib/pubid/idf/identifiers/amendment.rb +27 -0
  284. data/lib/pubid/idf/identifiers/corrigendum.rb +27 -0
  285. data/lib/pubid/idf/identifiers/international_standard.rb +123 -0
  286. data/lib/pubid/idf/identifiers/reviewed_method.rb +100 -0
  287. data/lib/pubid/idf/identifiers.rb +13 -0
  288. data/lib/pubid/idf/parser.rb +143 -0
  289. data/lib/pubid/idf/scheme.rb +61 -0
  290. data/lib/pubid/idf/single_identifier.rb +19 -0
  291. data/lib/pubid/idf/supplement_identifier.rb +43 -0
  292. data/lib/pubid/idf/urn_generator.rb +84 -0
  293. data/lib/pubid/idf.rb +25 -0
  294. data/lib/pubid/iec/builder.rb +458 -0
  295. data/lib/pubid/iec/components/code.rb +60 -0
  296. data/lib/pubid/iec/components/consolidated_amendment.rb +59 -0
  297. data/lib/pubid/iec/components/publisher.rb +36 -0
  298. data/lib/pubid/iec/components/sheet.rb +32 -0
  299. data/lib/pubid/iec/components/trf_info.rb +38 -0
  300. data/lib/pubid/iec/components/vap_suffix.rb +41 -0
  301. data/lib/pubid/iec/identifier.rb +256 -0
  302. data/lib/pubid/iec/identifiers/amendment.rb +94 -0
  303. data/lib/pubid/iec/identifiers/base.rb +82 -0
  304. data/lib/pubid/iec/identifiers/component_specification.rb +39 -0
  305. data/lib/pubid/iec/identifiers/conformity_assessment.rb +39 -0
  306. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +82 -0
  307. data/lib/pubid/iec/identifiers/corrigendum.rb +94 -0
  308. data/lib/pubid/iec/identifiers/fragment_identifier.rb +137 -0
  309. data/lib/pubid/iec/identifiers/guide.rb +104 -0
  310. data/lib/pubid/iec/identifiers/international_standard.rb +147 -0
  311. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +104 -0
  312. data/lib/pubid/iec/identifiers/operational_document.rb +39 -0
  313. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +101 -0
  314. data/lib/pubid/iec/identifiers/sheet_identifier.rb +62 -0
  315. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +40 -0
  316. data/lib/pubid/iec/identifiers/systems_reference_document.rb +40 -0
  317. data/lib/pubid/iec/identifiers/technical_report.rb +132 -0
  318. data/lib/pubid/iec/identifiers/technical_specification.rb +132 -0
  319. data/lib/pubid/iec/identifiers/technology_report.rb +39 -0
  320. data/lib/pubid/iec/identifiers/test_report_form.rb +78 -0
  321. data/lib/pubid/iec/identifiers/vap_identifier.rb +73 -0
  322. data/lib/pubid/iec/identifiers/white_paper.rb +39 -0
  323. data/lib/pubid/iec/identifiers/working_document.rb +96 -0
  324. data/lib/pubid/iec/parser.rb +417 -0
  325. data/lib/pubid/iec/rendering_style.rb +113 -0
  326. data/lib/pubid/iec/scheme.rb +71 -0
  327. data/lib/pubid/iec/single_identifier.rb +80 -0
  328. data/lib/pubid/iec/supplement_identifier.rb +161 -0
  329. data/lib/pubid/iec/urn_generator.rb +79 -0
  330. data/lib/pubid/iec/urn_parser.rb +90 -0
  331. data/lib/pubid/iec.rb +85 -0
  332. data/lib/pubid/ieee/aiee/builder.rb +71 -0
  333. data/lib/pubid/ieee/aiee/identifier.rb +105 -0
  334. data/lib/pubid/ieee/aiee/parser.rb +130 -0
  335. data/lib/pubid/ieee/aiee.rb +11 -0
  336. data/lib/pubid/ieee/builder.rb +1237 -0
  337. data/lib/pubid/ieee/components/code.rb +102 -0
  338. data/lib/pubid/ieee/components/draft.rb +93 -0
  339. data/lib/pubid/ieee/components/relationship.rb +157 -0
  340. data/lib/pubid/ieee/components/typed_stage.rb +100 -0
  341. data/lib/pubid/ieee/identifier.rb +54 -0
  342. data/lib/pubid/ieee/identifiers/adopted_standard.rb +33 -0
  343. data/lib/pubid/ieee/identifiers/base.rb +591 -0
  344. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +35 -0
  345. data/lib/pubid/ieee/identifiers/corrigendum.rb +37 -0
  346. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +51 -0
  347. data/lib/pubid/ieee/identifiers/dual_identifier.rb +18 -0
  348. data/lib/pubid/ieee/identifiers/dual_published.rb +28 -0
  349. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +27 -0
  350. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +34 -0
  351. data/lib/pubid/ieee/identifiers/joint_development.rb +172 -0
  352. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +51 -0
  353. data/lib/pubid/ieee/identifiers/nesc/base.rb +56 -0
  354. data/lib/pubid/ieee/identifiers/nesc/draft.rb +28 -0
  355. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +32 -0
  356. data/lib/pubid/ieee/identifiers/nesc/redline.rb +26 -0
  357. data/lib/pubid/ieee/identifiers/nesc/standard.rb +26 -0
  358. data/lib/pubid/ieee/identifiers/nesc.rb +15 -0
  359. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +20 -0
  360. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +26 -0
  361. data/lib/pubid/ieee/identifiers/redlined_standard.rb +33 -0
  362. data/lib/pubid/ieee/identifiers/si_standard.rb +73 -0
  363. data/lib/pubid/ieee/identifiers/standard.rb +41 -0
  364. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +23 -0
  365. data/lib/pubid/ieee/identifiers.rb +33 -0
  366. data/lib/pubid/ieee/ire/builder.rb +61 -0
  367. data/lib/pubid/ieee/ire/identifier.rb +58 -0
  368. data/lib/pubid/ieee/ire/parser.rb +91 -0
  369. data/lib/pubid/ieee/ire.rb +11 -0
  370. data/lib/pubid/ieee/nesc/builder.rb +101 -0
  371. data/lib/pubid/ieee/nesc/parser.rb +154 -0
  372. data/lib/pubid/ieee/nesc.rb +10 -0
  373. data/lib/pubid/ieee/parser.rb +1226 -0
  374. data/lib/pubid/ieee/scheme.rb +90 -0
  375. data/lib/pubid/ieee/typed_stages.rb +172 -0
  376. data/lib/pubid/ieee/urn_generator.rb +188 -0
  377. data/lib/pubid/ieee.rb +32 -0
  378. data/lib/pubid/ieee_debug.rb +31 -0
  379. data/lib/pubid/iho/builder.rb +37 -0
  380. data/lib/pubid/iho/identifier.rb +61 -0
  381. data/lib/pubid/iho/identifiers/base.rb +41 -0
  382. data/lib/pubid/iho/identifiers/bibliographic.rb +16 -0
  383. data/lib/pubid/iho/identifiers/circular_letter.rb +15 -0
  384. data/lib/pubid/iho/identifiers/miscellaneous.rb +16 -0
  385. data/lib/pubid/iho/identifiers/publication.rb +15 -0
  386. data/lib/pubid/iho/identifiers/standard.rb +15 -0
  387. data/lib/pubid/iho/identifiers.rb +14 -0
  388. data/lib/pubid/iho/parser.rb +68 -0
  389. data/lib/pubid/iho/scheme.rb +29 -0
  390. data/lib/pubid/iho/urn_generator.rb +29 -0
  391. data/lib/pubid/iho.rb +21 -0
  392. data/lib/pubid/iso/builder.rb +309 -0
  393. data/lib/pubid/iso/bundled_identifier.rb +85 -0
  394. data/lib/pubid/iso/combined_identifier.rb +22 -0
  395. data/lib/pubid/iso/components/code.rb +36 -0
  396. data/lib/pubid/iso/components/publisher.rb +60 -0
  397. data/lib/pubid/iso/components.rb +12 -0
  398. data/lib/pubid/iso/format_resolver.rb +45 -0
  399. data/lib/pubid/iso/identifier.rb +330 -0
  400. data/lib/pubid/iso/identifiers/addendum.rb +104 -0
  401. data/lib/pubid/iso/identifiers/amendment.rb +128 -0
  402. data/lib/pubid/iso/identifiers/base.rb +115 -0
  403. data/lib/pubid/iso/identifiers/corrigendum.rb +108 -0
  404. data/lib/pubid/iso/identifiers/data.rb +76 -0
  405. data/lib/pubid/iso/identifiers/directives.rb +59 -0
  406. data/lib/pubid/iso/identifiers/directives_supplement.rb +119 -0
  407. data/lib/pubid/iso/identifiers/extract.rb +30 -0
  408. data/lib/pubid/iso/identifiers/guide.rb +100 -0
  409. data/lib/pubid/iso/identifiers/international_standard.rb +168 -0
  410. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +94 -0
  411. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +89 -0
  412. data/lib/pubid/iso/identifiers/pas.rb +93 -0
  413. data/lib/pubid/iso/identifiers/recommendation.rb +45 -0
  414. data/lib/pubid/iso/identifiers/supplement.rb +87 -0
  415. data/lib/pubid/iso/identifiers/tc_document.rb +108 -0
  416. data/lib/pubid/iso/identifiers/technical_report.rb +103 -0
  417. data/lib/pubid/iso/identifiers/technical_specification.rb +102 -0
  418. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +95 -0
  419. data/lib/pubid/iso/identifiers.rb +33 -0
  420. data/lib/pubid/iso/parser.rb +512 -0
  421. data/lib/pubid/iso/rendering_style.rb +120 -0
  422. data/lib/pubid/iso/scheme.rb +193 -0
  423. data/lib/pubid/iso/single_identifier.rb +64 -0
  424. data/lib/pubid/iso/supplement_identifier.rb +27 -0
  425. data/lib/pubid/iso/urn_generator.rb +426 -0
  426. data/lib/pubid/iso/urn_parser.rb +437 -0
  427. data/lib/pubid/iso/utilities.rb +86 -0
  428. data/lib/pubid/iso.rb +50 -0
  429. data/lib/pubid/itu/builder.rb +171 -0
  430. data/lib/pubid/itu/components/code.rb +39 -0
  431. data/lib/pubid/itu/components/sector.rb +35 -0
  432. data/lib/pubid/itu/components/series.rb +29 -0
  433. data/lib/pubid/itu/i18n.rb +9 -0
  434. data/lib/pubid/itu/i18n.yaml +30 -0
  435. data/lib/pubid/itu/identifier.rb +118 -0
  436. data/lib/pubid/itu/identifiers/amendment.rb +43 -0
  437. data/lib/pubid/itu/identifiers/annex.rb +74 -0
  438. data/lib/pubid/itu/identifiers/base.rb +154 -0
  439. data/lib/pubid/itu/identifiers/combined_identifier.rb +47 -0
  440. data/lib/pubid/itu/identifiers/corrigendum.rb +44 -0
  441. data/lib/pubid/itu/identifiers/recommendation.rb +16 -0
  442. data/lib/pubid/itu/identifiers/special_publication.rb +31 -0
  443. data/lib/pubid/itu/identifiers/supplement.rb +46 -0
  444. data/lib/pubid/itu/identifiers.rb +16 -0
  445. data/lib/pubid/itu/model.rb +111 -0
  446. data/lib/pubid/itu/parser.rb +225 -0
  447. data/lib/pubid/itu/scheme.rb +174 -0
  448. data/lib/pubid/itu/urn_generator.rb +105 -0
  449. data/lib/pubid/itu.rb +22 -0
  450. data/lib/pubid/jcgm/builder.rb +88 -0
  451. data/lib/pubid/jcgm/components/publisher.rb +20 -0
  452. data/lib/pubid/jcgm/components.rb +9 -0
  453. data/lib/pubid/jcgm/identifier.rb +54 -0
  454. data/lib/pubid/jcgm/identifiers/amendment.rb +35 -0
  455. data/lib/pubid/jcgm/identifiers/guide.rb +21 -0
  456. data/lib/pubid/jcgm/identifiers/gum_guide.rb +51 -0
  457. data/lib/pubid/jcgm/identifiers.rb +11 -0
  458. data/lib/pubid/jcgm/parser.rb +84 -0
  459. data/lib/pubid/jcgm/scheme.rb +60 -0
  460. data/lib/pubid/jcgm/single_identifier.rb +48 -0
  461. data/lib/pubid/jcgm/supplement_identifier.rb +16 -0
  462. data/lib/pubid/jcgm/urn_generator.rb +110 -0
  463. data/lib/pubid/jcgm.rb +31 -0
  464. data/lib/pubid/jis/builder.rb +124 -0
  465. data/lib/pubid/jis/components/code.rb +59 -0
  466. data/lib/pubid/jis/components.rb +9 -0
  467. data/lib/pubid/jis/identifier.rb +61 -0
  468. data/lib/pubid/jis/identifiers/amendment.rb +16 -0
  469. data/lib/pubid/jis/identifiers/base.rb +72 -0
  470. data/lib/pubid/jis/identifiers/explanation.rb +22 -0
  471. data/lib/pubid/jis/identifiers/japanese_industrial_standard.rb +16 -0
  472. data/lib/pubid/jis/identifiers/standard.rb +27 -0
  473. data/lib/pubid/jis/identifiers/technical_report.rb +31 -0
  474. data/lib/pubid/jis/identifiers/technical_specification.rb +31 -0
  475. data/lib/pubid/jis/identifiers.rb +17 -0
  476. data/lib/pubid/jis/parser.rb +109 -0
  477. data/lib/pubid/jis/scheme.rb +49 -0
  478. data/lib/pubid/jis/single_identifier.rb +37 -0
  479. data/lib/pubid/jis/supplement_identifier.rb +47 -0
  480. data/lib/pubid/jis/urn_generator.rb +25 -0
  481. data/lib/pubid/jis.rb +23 -0
  482. data/lib/pubid/lutaml/no_store_registration.rb +30 -0
  483. data/lib/pubid/nist/builder.rb +2269 -0
  484. data/lib/pubid/nist/components/code.rb +38 -0
  485. data/lib/pubid/nist/components/edition.rb +134 -0
  486. data/lib/pubid/nist/components/issue_number.rb +28 -0
  487. data/lib/pubid/nist/components/part.rb +77 -0
  488. data/lib/pubid/nist/components/publisher.rb +24 -0
  489. data/lib/pubid/nist/components/stage.rb +53 -0
  490. data/lib/pubid/nist/components/supplement.rb +188 -0
  491. data/lib/pubid/nist/components/translation.rb +42 -0
  492. data/lib/pubid/nist/components/update.rb +103 -0
  493. data/lib/pubid/nist/components/version.rb +35 -0
  494. data/lib/pubid/nist/components/volume.rb +32 -0
  495. data/lib/pubid/nist/components.rb +19 -0
  496. data/lib/pubid/nist/configuration.rb +77 -0
  497. data/lib/pubid/nist/identifier.rb +62 -0
  498. data/lib/pubid/nist/identifiers/base.rb +578 -0
  499. data/lib/pubid/nist/identifiers/circular.rb +68 -0
  500. data/lib/pubid/nist/identifiers/circular_supplement.rb +50 -0
  501. data/lib/pubid/nist/identifiers/commercial_standard.rb +41 -0
  502. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +56 -0
  503. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +56 -0
  504. data/lib/pubid/nist/identifiers/crpl_report.rb +132 -0
  505. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +104 -0
  506. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +35 -0
  507. data/lib/pubid/nist/identifiers/handbook.rb +50 -0
  508. data/lib/pubid/nist/identifiers/internal_report.rb +56 -0
  509. data/lib/pubid/nist/identifiers/letter_circular.rb +45 -0
  510. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +65 -0
  511. data/lib/pubid/nist/identifiers/monograph.rb +69 -0
  512. data/lib/pubid/nist/identifiers/ncstar.rb +41 -0
  513. data/lib/pubid/nist/identifiers/nsrds.rb +41 -0
  514. data/lib/pubid/nist/identifiers/owmwp.rb +35 -0
  515. data/lib/pubid/nist/identifiers/report.rb +67 -0
  516. data/lib/pubid/nist/identifiers/special_publication.rb +36 -0
  517. data/lib/pubid/nist/identifiers/technical_note.rb +90 -0
  518. data/lib/pubid/nist/identifiers.rb +33 -0
  519. data/lib/pubid/nist/parser.rb +1117 -0
  520. data/lib/pubid/nist/scheme.rb +199 -0
  521. data/lib/pubid/nist/supplement_identifier.rb +67 -0
  522. data/lib/pubid/nist/urn_generator.rb +133 -0
  523. data/lib/pubid/nist.rb +37 -0
  524. data/lib/pubid/oiml/builder.rb +189 -0
  525. data/lib/pubid/oiml/components/code.rb +20 -0
  526. data/lib/pubid/oiml/components.rb +9 -0
  527. data/lib/pubid/oiml/identifier.rb +61 -0
  528. data/lib/pubid/oiml/identifiers/amendment.rb +13 -0
  529. data/lib/pubid/oiml/identifiers/annex.rb +62 -0
  530. data/lib/pubid/oiml/identifiers/base.rb +36 -0
  531. data/lib/pubid/oiml/identifiers/basic_publication.rb +13 -0
  532. data/lib/pubid/oiml/identifiers/document.rb +13 -0
  533. data/lib/pubid/oiml/identifiers/expert_report.rb +13 -0
  534. data/lib/pubid/oiml/identifiers/guide.rb +13 -0
  535. data/lib/pubid/oiml/identifiers/recommendation.rb +13 -0
  536. data/lib/pubid/oiml/identifiers/seminar_report.rb +13 -0
  537. data/lib/pubid/oiml/identifiers/vocabulary.rb +13 -0
  538. data/lib/pubid/oiml/identifiers.rb +18 -0
  539. data/lib/pubid/oiml/parser.rb +173 -0
  540. data/lib/pubid/oiml/scheme.rb +46 -0
  541. data/lib/pubid/oiml/single_identifier.rb +90 -0
  542. data/lib/pubid/oiml/supplement_identifier.rb +43 -0
  543. data/lib/pubid/oiml/urn_generator.rb +64 -0
  544. data/lib/pubid/oiml.rb +26 -0
  545. data/lib/pubid/parser/common_parse_methods.rb +13 -0
  546. data/lib/pubid/parser/common_parse_rules.rb +56 -0
  547. data/lib/pubid/parser.rb +8 -0
  548. data/lib/pubid/parsers/base.rb +11 -0
  549. data/lib/pubid/parsers/mr_string.rb +93 -0
  550. data/lib/pubid/plateau/builder.rb +50 -0
  551. data/lib/pubid/plateau/identifier.rb +57 -0
  552. data/lib/pubid/plateau/identifiers/annex.rb +16 -0
  553. data/lib/pubid/plateau/identifiers/base.rb +51 -0
  554. data/lib/pubid/plateau/identifiers/handbook.rb +34 -0
  555. data/lib/pubid/plateau/identifiers/technical_report.rb +20 -0
  556. data/lib/pubid/plateau/identifiers.rb +12 -0
  557. data/lib/pubid/plateau/parser.rb +63 -0
  558. data/lib/pubid/plateau/scheme.rb +45 -0
  559. data/lib/pubid/plateau/supplement_identifier.rb +72 -0
  560. data/lib/pubid/plateau/urn_generator.rb +29 -0
  561. data/lib/pubid/plateau.rb +26 -0
  562. data/lib/pubid/renderers/base.rb +53 -0
  563. data/lib/pubid/renderers/directives_renderer.rb +61 -0
  564. data/lib/pubid/renderers/guide_renderer.rb +24 -0
  565. data/lib/pubid/renderers/human_readable.rb +70 -0
  566. data/lib/pubid/renderers/iwa_renderer.rb +20 -0
  567. data/lib/pubid/renderers/mr_string.rb +16 -0
  568. data/lib/pubid/renderers/supplement_renderer.rb +36 -0
  569. data/lib/pubid/renderers/urn.rb +11 -0
  570. data/lib/pubid/renderers.rb +14 -0
  571. data/lib/pubid/rendering/base.rb +73 -0
  572. data/lib/pubid/rendering/common.rb +211 -0
  573. data/lib/pubid/rendering/context.rb +159 -0
  574. data/lib/pubid/rendering/date.rb +27 -0
  575. data/lib/pubid/rendering/format.rb +25 -0
  576. data/lib/pubid/rendering/language.rb +21 -0
  577. data/lib/pubid/rendering/numbering.rb +24 -0
  578. data/lib/pubid/rendering/publisher.rb +25 -0
  579. data/lib/pubid/rendering/stage.rb +38 -0
  580. data/lib/pubid/rendering/supplement.rb +46 -0
  581. data/lib/pubid/rendering.rb +16 -0
  582. data/lib/pubid/sae/builder.rb +32 -0
  583. data/lib/pubid/sae/components/code.rb +9 -0
  584. data/lib/pubid/sae/components/date.rb +19 -0
  585. data/lib/pubid/sae/components/type.rb +19 -0
  586. data/lib/pubid/sae/components.rb +11 -0
  587. data/lib/pubid/sae/identifier.rb +37 -0
  588. data/lib/pubid/sae/identifiers/base.rb +42 -0
  589. data/lib/pubid/sae/identifiers.rb +9 -0
  590. data/lib/pubid/sae/parser.rb +55 -0
  591. data/lib/pubid/sae/scheme.rb +47 -0
  592. data/lib/pubid/sae/urn_generator.rb +38 -0
  593. data/lib/pubid/sae.rb +19 -0
  594. data/lib/pubid/scheme.rb +219 -0
  595. data/lib/pubid/urn_generator/base.rb +110 -0
  596. data/lib/pubid/utils/string_normalizer.rb +196 -0
  597. data/lib/pubid/utils.rb +7 -0
  598. data/lib/pubid/version.rb +3 -1
  599. data/lib/pubid.rb +137 -13
  600. data/lib/tasks/docs.rake +37 -0
  601. data/lib/tasks/export.rake +38 -0
  602. data/lib/tasks/website-data.json +7488 -0
  603. metadata +616 -171
  604. data/lib/pubid/registry.rb +0 -30
@@ -0,0 +1,659 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Bsi
7
+ class Parser < Parslet::Parser
8
+ rule(:digit) { match["0-9"] }
9
+ rule(:digits) { digit.repeat(1) }
10
+ rule(:space) { str(" ") }
11
+ rule(:dash) { str("-") }
12
+ rule(:slash) { str("/") }
13
+ rule(:plus) { str("+") }
14
+ rule(:colon) { str(":") }
15
+
16
+ # BSI publisher
17
+ rule(:bs) { str("BS") | str("BSI") }
18
+
19
+ # Specialized prefixes - Multi-letter BEFORE single-letter (longest match first)
20
+ rule(:multi_letter_prefix) do
21
+ # Flex type prefixes for supplement/addendum documents (5-character first)
22
+ str("E9111") |
23
+ # CECC (4-character)
24
+ str("CECC") |
25
+ # 5-character prefixes
26
+ str("CISPR") |
27
+ # 4-character prefixes
28
+ str("2HC") | str("2HR") | str("2SP") | str("2TA") |
29
+ str("3HR") | str("3TA") |
30
+ # 3-character prefixes
31
+ str("2A") | str("2B") | str("2C") | str("2F") | str("2G") |
32
+ str("2L") | str("2M") | str("2S") |
33
+ str("3B") | str("3F") | str("3G") | str("3J") | str("3L") | str("3S") |
34
+ str("4F") | str("4L") | str("4S") |
35
+ str("5S") | str("7S") |
36
+ # 2-character prefixes
37
+ str("SP")
38
+ end
39
+
40
+ rule(:single_letter_prefix) do
41
+ # Two-letter prefixes BEFORE single-letter
42
+ str("AU") | str("HC") | str("MA") | str("PL") | str("QC") | str("TA") |
43
+ # Single-letter prefixes
44
+ str("A") | str("B") | str("C") | str("F") | str("G") |
45
+ str("L") | str("M") | str("S") | str("X")
46
+ end
47
+
48
+ rule(:specialized_prefix) do
49
+ (multi_letter_prefix | single_letter_prefix).as(:prefix)
50
+ end
51
+
52
+ # Flex documents (BSI Flex or just Flex) - BSI is already normalized to BS
53
+ rule(:flex) { str("BSI Flex") | str("BS Flex") | str("Flex") }
54
+
55
+ # Types for native BSI standards
56
+ rule(:dd) { str("DD") }
57
+ rule(:pd) { str("PD") }
58
+ rule(:pas) { str("PAS") }
59
+ rule(:na) { str("NA") }
60
+ rule(:ts) { str("TS") }
61
+ rule(:handbook) { str("Handbook") | str("HB") }
62
+ rule(:pp) { str("PP") }
63
+ rule(:bip) { str("BIP") }
64
+ rule(:ep_type) { str("EP") | str("ep") }
65
+
66
+ # Index suffix - handles three formats:
67
+ # 1. Colon format: BS 5000:Index:1981
68
+ # 2. Space format: BS 185 Index:1964
69
+ # 3. Issue format: BS 5000 Index Issue 4:1980
70
+ rule(:index_suffix) do
71
+ # Issue format: " Index Issue N" (must be before colon format to match correctly)
72
+ (space >> str("Index") >> space >> str("Issue") >> space >> digits.as(:issue_number)) |
73
+ # Colon format: ":Index"
74
+ (colon.as(:colon_sep) >> str("Index")) |
75
+ # Space format: " Index" (year rule includes the colon)
76
+ (space >> str("Index"))
77
+ end
78
+
79
+ # Supplementary Index suffix - handles one format:
80
+ # Space format: " Supplementary Index" (year rule includes the colon)
81
+ rule(:supplementary_index_suffix) do
82
+ space >> str("Supplementary Index")
83
+ end
84
+
85
+ # Explanatory Supplement suffix - handles one format:
86
+ # Colon format: ":Explanatory Supplement" (year rule includes the second colon)
87
+ rule(:explanatory_supplement_suffix) do
88
+ colon >> str("Explanatory Supplement")
89
+ end
90
+
91
+ # Method suffix - handles three formats:
92
+ # 1. Basic (singular): BS 2782-1:Method 131B:1983
93
+ # 2. Range (plural): BS 2782-4:Methods 451F to 451J:1978
94
+ # 3. And (plural): BS 2782-8:Methods 823A and 823B:1978
95
+ rule(:method_suffix) do
96
+ # Range format (plural): ":Methods X to Y" (must be first to match the "to" keyword)
97
+ (colon >> str("Methods") >> space >> method_code.as(:method_code) >> space >> str("to") >> space >> method_code.as(:method_to)) |
98
+ # And format (plural): ":Methods X and Y"
99
+ (colon >> str("Methods") >> space >> method_code.as(:method_code) >> space >> str("and") >> space >> method_code.as(:method_and)) |
100
+ # Basic format (singular): ":Method X"
101
+ (colon >> str("Method") >> space >> method_code.as(:method_code))
102
+ end
103
+
104
+ # Method code - alphanumeric like "131B", "451F", "823A", "1006"
105
+ rule(:method_code) { match["0-9A-Z"].repeat(1) }
106
+
107
+ # Test Method suffix - format: ":TEST:TESTID"
108
+ # Examples: BS 1006:B01C:LFS1:1982
109
+ rule(:test_method_suffix) do
110
+ colon >> match["0-9A-Z"].repeat(1).as(:test_series) >> colon >> match["0-9A-Z"].repeat(1).as(:test_id)
111
+ end
112
+
113
+ # Set separator - plus sign with optional spaces
114
+ # Handles: " + ", "+", " +", "+ "
115
+ rule(:set_separator) { space.maybe >> str("+") >> space.maybe }
116
+
117
+ # Set pattern - capture identifiers separated by +
118
+ # We'll parse each part separately in the builder
119
+ # Use a different approach to avoid key collision
120
+ rule(:set_item) do
121
+ # Wrap the item in a unique key to avoid merging
122
+ (bs.as(:publisher) >> space >>
123
+ (adopted_org_prefix.as(:adopted_org) >> space).maybe >>
124
+ number >> parts.maybe >>
125
+ year.maybe).as(:set_item)
126
+ end
127
+
128
+ # Parse a sequence of set items separated by +
129
+ rule(:set_items) do
130
+ # First item
131
+ set_item >> (set_separator >> set_item).repeat(1)
132
+ end
133
+
134
+ rule(:set_identifier) do
135
+ # Use as() on the whole sequence to capture the set structure
136
+ set_items.as(:set)
137
+ end
138
+
139
+ # Section suffix - handles two formats:
140
+ # 1. Colon format (DD): "DD 51:Section 0:1977"
141
+ # 2. Space format (BS): "BS 3224 Section B2:1970"
142
+ rule(:section_suffix) do
143
+ # Colon format: ":Section N" (DD format)
144
+ (colon.as(:colon_sep) >> str("Section") >> space >> section_id.as(:section_id)) |
145
+ # Space format: " Section N" (BS format)
146
+ (space >> str("Section") >> space >> section_id.as(:section_id))
147
+ end
148
+
149
+ # Section ID - can be numeric (0-7) or alphanumeric (B2, C1, D1, etc.)
150
+ rule(:section_id) { match["0-9A-Za-z"].repeat(1) }
151
+
152
+ # Detailed Specification suffix - N or C notation
153
+ # Formats: "BS 9074 N002:1974", "BS 9210 N0009-1:1978", "BS 9300 C155-168:1971"
154
+ # N notation: N<number> or N<number>-<part>
155
+ # C notation: C<start>-<end> (range)
156
+ rule(:detailed_spec_suffix) do
157
+ space >> (
158
+ # C notation with range: C155-168
159
+ (str("C") >> match["0-9"].repeat(1,
160
+ 3) >> dash >> match["0-9"].repeat(1,
161
+ 3)).as(:spec_code) |
162
+ # N notation with optional part: N002 or N0009-1
163
+ (str("N") >> match["0-9"].repeat(1,
164
+ 4) >> (dash >> match["0-9"].repeat(1)).maybe).as(:spec_code)
165
+ )
166
+ end
167
+
168
+ # Committee Document identifier
169
+ # Format: "YY/NNNNNNNN DC" (2-digit year, 8-digit number, DC suffix)
170
+ rule(:committee_document) do
171
+ (digit.repeat(2,
172
+ 2).as(:year) >> slash >> match["0-9"].repeat(8).as(:document_number) >> space >> str("DC")).as(:committee_document)
173
+ end
174
+
175
+ # Standalone Amendment identifier
176
+ # Formats: "AMD 11015", "(AMD 10971)", "AMD Corrigendum 14716"
177
+ rule(:standalone_amendment) do
178
+ # Parenthesized format: "(AMD 10971)" or "(AMD Corrigendum 14716)"
179
+ (str("(") >> str("AMD") >> space >> str("Corrigendum").as(:corrigendum) >> space >> digits.as(:amendment_number) >> str(")")).as(:parenthesized_amd) |
180
+ (str("(") >> str("AMD") >> space >> digits.as(:amendment_number) >> str(")")).as(:parenthesized_amd) |
181
+ # Regular format with corrigendum: "AMD Corrigendum 14716"
182
+ (str("AMD") >> space >> str("Corrigendum").as(:corrigendum) >> space >> digits.as(:amendment_number)).as(:standalone_amendment) |
183
+ # Basic format: "AMD 11015"
184
+ (str("AMD") >> space >> digits.as(:amendment_number)).as(:standalone_amendment)
185
+ end
186
+
187
+ # DISC identifier - "DISC PD <number>[-<part>]:<year>"
188
+ rule(:disc_prefix) { str("DISC PD ") }
189
+
190
+ # Stage prefixes
191
+ rule(:draft) { str("Draft BS") | str("DBS") }
192
+
193
+ # Adopted organizations - order matters!
194
+ rule(:en) { str("EN") }
195
+ rule(:iso) { str("ISO") }
196
+ rule(:iec) { str("IEC") }
197
+ rule(:cispr) { str("CISPR") }
198
+ rule(:cen) { str("CEN") }
199
+ rule(:clc) { str("CLC") }
200
+
201
+ # National Annex prefix (special case: "NA to BS..." or "NA+A1:2012 to BS...")
202
+ rule(:na_with_supplements) do
203
+ str("NA") >> supplement.repeat(1).as(:na_supplements) >> space >> str("to ")
204
+ end
205
+
206
+ rule(:na_simple) do
207
+ str("NA to ")
208
+ end
209
+
210
+ rule(:na_prefix) do
211
+ (na_with_supplements | na_simple).as(:na_prefix)
212
+ end
213
+
214
+ # Publisher/Type - longer patterns first
215
+ rule(:publisher_or_type) do
216
+ (na_prefix >>
217
+ (draft.as(:stage) |
218
+ dd.as(:type) |
219
+ pd.as(:type) |
220
+ bs.as(:publisher))) |
221
+ flex.as(:flex_type) |
222
+ handbook.as(:type) |
223
+ bip.as(:type) |
224
+ ts.as(:type) |
225
+ ep_type.as(:type) |
226
+ draft.as(:stage) |
227
+ dd.as(:type) |
228
+ pd.as(:type) |
229
+ pas.as(:type) |
230
+ pp.as(:type) |
231
+ na.as(:type) |
232
+ (bs.as(:publisher) >> space >> specialized_prefix) |
233
+ bs.as(:publisher)
234
+ end
235
+
236
+ # Number (with optional bracket notation for iterations like 1000[9])
237
+ # Allow alphanumeric for codes like E9111
238
+ rule(:number) { match["0-9A-Z"].repeat(1).as(:number) }
239
+
240
+ # Bracket notation for iterations (e.g., 1000[9])
241
+ rule(:bracket_iteration) do
242
+ str("[") >> match["0-9"].repeat(1).as(:iteration) >> str("]")
243
+ end
244
+
245
+ # Part with subpart (multi-level like 1-2)
246
+ # Must match before general :part rule
247
+ rule(:part_with_subpart) do
248
+ dash >> digits.as(:part) >> dash >> digits.as(:subpart)
249
+ end
250
+
251
+ # Part (can be multi-level like 1-2 or 2.3 with dots, or with letters like F3, or ampersand like 3A & B)
252
+ rule(:part) { dash >> match["0-9A-Za-z.& "].repeat(1).as(:part) }
253
+ rule(:parts) { (part_with_subpart | part).repeat(0).as(:parts) }
254
+
255
+ # Part with optional letter suffix edition for aerospace standards (e.g., "200-1a" or "50-1.1.1a")
256
+ # Must match before the regular part rule
257
+ rule(:part_with_letter_edition) do
258
+ # Part number (digits, dots) followed by single letter edition
259
+ (dash >> match["0-9."].repeat(1).as(:part) >> letter_edition.as(:letter_edition)) |
260
+ # Just part number (no edition)
261
+ (dash >> match["0-9."].repeat(1).as(:part))
262
+ end
263
+
264
+ # Number with optional letter suffix edition for aerospace standards (e.g., "145e" or "159G")
265
+ rule(:number_with_letter_edition) do
266
+ (match["0-9"].repeat(1).as(:number) >> letter_edition.as(:letter_edition)) |
267
+ match["0-9"].repeat(1).as(:number)
268
+ end
269
+
270
+ # Space-separated alphanumeric part (for bundled patterns like "9113 N001")
271
+ rule(:space_separated_part) do
272
+ space >> (match["A-Z"].repeat(1) >> match["0-9"].repeat(1)).as(:part)
273
+ end
274
+
275
+ # Iteration (for formats like BS 1000[9])
276
+ rule(:iteration) { bracket_iteration.repeat(0).as(:iteration) }
277
+
278
+ # Year (3 or 4 digits - some old standards have 3-digit years like :197)
279
+ rule(:year) { colon >> digit.repeat(3, 4).as(:year) }
280
+
281
+ # Base year (year in the base identifier, used when there's a supplement/addendum)
282
+ rule(:base_year) { colon >> digit.repeat(4, 4).as(:base_year) }
283
+
284
+ # Month (optional, like :2020-01)
285
+ rule(:month) { dash >> digit.repeat(2, 2).as(:month) }
286
+
287
+ # Edition (v1.0, v2.0, etc.) for Flex - lowercase v
288
+ rule(:flex_edition) do
289
+ space >> str("v") >> match["0-9."].repeat(1).as(:edition)
290
+ end
291
+
292
+ # Edition for IEC/ISO standards (ED2, ED3, etc.) - space before ED, uppercase
293
+ rule(:edition) { space >> str("ED") >> digits.as(:edition) }
294
+
295
+ # Letter suffix edition for aerospace/specialized standards (e.g., BS AU 145e:2018)
296
+ # Single letter (a-z or A-Z) that comes immediately after number or part
297
+ rule(:letter_edition) { match["a-zA-Z"].as(:letter_edition) }
298
+
299
+ # Amendment (+A1:2008 or /A2:2019 or /Amd 1:2020 or +A1:15 for short year)
300
+ rule(:amendment) do
301
+ ((plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
302
+ str("A") >> digits.as(:amd_number) >>
303
+ colon >> digit.repeat(2, 4).as(:amd_year)) |
304
+ ((plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
305
+ str("Amd") >> space >> digits.as(:amd_number) >>
306
+ colon >> digit.repeat(4, 4).as(:amd_year))
307
+ end
308
+
309
+ # Corrigendum (+AC:2009 or +AC1:2008 or /AC1:2005 or +C1:2018 or +C1 without year)
310
+ rule(:corrigendum) do
311
+ ((plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
312
+ str("AC") >> digits.maybe.as(:cor_number) >>
313
+ (colon >> digit.repeat(2, 4).as(:cor_year)).maybe) |
314
+ ((plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
315
+ str("C") >> digits.as(:cor_number) >>
316
+ (colon >> digit.repeat(2, 4).as(:cor_year)).maybe)
317
+ end
318
+
319
+ # AMD suffix without year - "AMD5", "AMD AA", "AMD11"
320
+ # Used after number/year on BS identifiers and adopted EN identifiers
321
+ rule(:amd_suffix) do
322
+ space >> str("AMD") >> space.maybe >>
323
+ (match["0-9"].repeat(1).as(:amd_number) | match["A-Z"].repeat(1).as(:amd_letter))
324
+ end
325
+
326
+ # AMD verbose form - "Amd 1 (09/15)" or "Amendment 2:August 2013"
327
+ rule(:amd_verbose) do
328
+ space >> (str("Amd") | str("Amendment")).as(:amd_verbose_type) >> space >>
329
+ match["0-9"].repeat(1).as(:amd_number) >>
330
+ (space >> str("(") >> match["0-9/"].repeat(1).as(:amd_date) >> str(")")).maybe >>
331
+ (colon >> match["A-Za-z"].repeat(1).as(:amd_month) >> space >> digit.repeat(
332
+ 4, 4
333
+ ).as(:amd_year)).maybe
334
+ end
335
+
336
+ # Supplements Document (not amendment/corrigendum supplements, but standalone supplement documents)
337
+ # Forward format: "BS NUMBER:Supplement No. N:YEAR" or "BS NUMBER Supplement N:YEAR"
338
+ # Also handles flex types: "BS CECC 50000:Supplement" or "BS M 31:Supplement"
339
+ # Reverse format: "Supplement No. N (YEAR) to BS NUMBER:YEAR"
340
+ rule(:supplement_document_forward) do
341
+ # With multi-letter flex type prefix (CECC, E9111, etc.)
342
+ (bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
343
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >> str("No.").as(:supp_no_prefix) >> space >>
344
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
345
+ 4).as(:supplement_year)
346
+ ).as(:supplement_document) |
347
+ (bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
348
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >>
349
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
350
+ 4).as(:supplement_year)
351
+ ).as(:supplement_document) |
352
+ # With single-letter flex type prefix (M, etc.)
353
+ (bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
354
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >> str("No.").as(:supp_no_prefix) >> space >>
355
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
356
+ 4).as(:supplement_year)
357
+ ).as(:supplement_document) |
358
+ (bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
359
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >>
360
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
361
+ 4).as(:supplement_year)
362
+ ).as(:supplement_document) |
363
+ # Without flex type prefix - with "No." prefix
364
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
365
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >> str("No.").as(:supp_no_prefix) >> space >>
366
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
367
+ 4).as(:supplement_year)
368
+ ).as(:supplement_document) |
369
+ # Without "No." prefix
370
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
371
+ (colon | space).as(:supp_sep) >> str("Supplement") >> space >>
372
+ digits.as(:supplement_number) >> colon >> digit.repeat(4,
373
+ 4).as(:supplement_year)
374
+ ).as(:supplement_document)
375
+ end
376
+
377
+ rule(:supplement_document_reverse) do
378
+ # With "No." prefix
379
+ (str("Supplement") >> space >> str("No.").as(:supp_no_prefix) >> space >>
380
+ digits.as(:supplement_number) >> space >> str("(") >> digit.repeat(4,
381
+ 4).as(:supplement_year) >>
382
+ str(")") >> space >> str("to ") >> bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
383
+ colon >> digit.repeat(4, 4).as(:base_year)
384
+ ).as(:supplement_document) |
385
+ # Without "No." prefix
386
+ (str("Supplement") >> space >>
387
+ digits.as(:supplement_number) >> space >> str("(") >> digit.repeat(4,
388
+ 4).as(:supplement_year) >>
389
+ str(")") >> space >> str("to ") >> bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
390
+ colon >> digit.repeat(4, 4).as(:base_year)
391
+ ).as(:supplement_document)
392
+ end
393
+
394
+ # Addendum Document
395
+ # Format: "BS NUMBER:Addendum No. N:YEAR" or "BS NUMBER Addendum N:YEAR"
396
+ # Also: "BS NUMBER:YEAR:Addendum No. N:YEAR" or "BS NUMBER:YEARAddendum No. N:YEAR" (space before Addendum)
397
+ # Also handles flex types: "BS CECC 90000:Addendum"
398
+ rule(:addendum_document) do
399
+ # With multi-letter flex type prefix (CECC, E9111, etc.)
400
+ (bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
401
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
402
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
403
+ 4).as(:addendum_year)
404
+ ).as(:addendum_document) |
405
+ (bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
406
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >>
407
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
408
+ 4).as(:addendum_year)
409
+ ).as(:addendum_document) |
410
+ # With single-letter flex type prefix (M, etc.)
411
+ (bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
412
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
413
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
414
+ 4).as(:addendum_year)
415
+ ).as(:addendum_document) |
416
+ (bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
417
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >>
418
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
419
+ 4).as(:addendum_year)
420
+ ).as(:addendum_document) |
421
+ # With year before Addendum and SPACE separator: "BS NUMBER:YEAR Addendum No. N:YEAR"
422
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
423
+ colon >> digit.repeat(4,
424
+ 4).as(:base_year) >> space.as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
425
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
426
+ 4).as(:addendum_year)
427
+ ).as(:addendum_document) |
428
+ # With year before Addendum and COLON separator: "BS NUMBER:YEAR:Addendum No. N:YEAR"
429
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
430
+ colon >> digit.repeat(4,
431
+ 4).as(:base_year) >> colon.as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
432
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
433
+ 4).as(:addendum_year)
434
+ ).as(:addendum_document) |
435
+ # Without flex type prefix - with "No." prefix
436
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
437
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
438
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
439
+ 4).as(:addendum_year)
440
+ ).as(:addendum_document) |
441
+ # Without "No." prefix
442
+ (bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
443
+ (colon | space).as(:add_sep) >> str("Addendum") >> space >>
444
+ digits.as(:addendum_number) >> colon >> digit.repeat(4,
445
+ 4).as(:addendum_year)
446
+ ).as(:addendum_document)
447
+ end
448
+
449
+ # Bundled Identifiers - Collections of standards published together
450
+ # Separators for bundles
451
+ rule(:bundle_sep_and) { space >> str("and") >> space }
452
+ rule(:bundle_sep_to) do
453
+ space >> (str("TO") | str("to")).as(:to_case) >> space
454
+ end
455
+ rule(:bundle_sep_ampersand) { space >> str("&") >> space }
456
+ rule(:bundle_sep_semicolon) { str(";") >> space }
457
+ rule(:bundle_sep_comma) { str(",") }
458
+
459
+ rule(:bundle_separator) do
460
+ bundle_sep_and.as(:sep_and) |
461
+ bundle_sep_to.as(:sep_to) |
462
+ bundle_sep_ampersand.as(:sep_ampersand) |
463
+ bundle_sep_semicolon.as(:sep_semicolon) |
464
+ bundle_sep_comma.as(:sep_comma)
465
+ end
466
+
467
+ # Parts/Sections bundle like "BS 4048:Parts 1 and 2:1966"
468
+ rule(:parts_bundle) do
469
+ (str("Parts") | str("Sections")).as(:bundle_type) >> space >>
470
+ match["0-9"].repeat(1).as(:part1) >>
471
+ bundle_sep_and >>
472
+ match["0-9."].repeat(1).as(:part2)
473
+ end
474
+
475
+ # Single identifier for bundling (without year in some cases)
476
+ # Enhanced to handle space-separated alphanumeric like "9113 N001"
477
+ # IMPORTANT: Order from most specific to least specific
478
+ rule(:bundle_item) do
479
+ # With full BS prefix and multi-letter specialized prefix (for "to" ranges like "BS 2SP 68 to BS 2SP 71")
480
+ (bs.as(:publisher) >> space >> multi_letter_prefix.as(:prefix) >> space >> number >> parts).as(:bundle_item) |
481
+ # With full BS prefix and single-letter specialized prefix
482
+ (bs.as(:publisher) >> space >> single_letter_prefix.as(:prefix) >> space >> number >> parts).as(:bundle_item) |
483
+ # With full BS prefix, number, and space-separated alphanumeric part
484
+ (bs.as(:publisher) >> space >> number >> space_separated_part).as(:bundle_item) |
485
+ # With full BS prefix only
486
+ (bs.as(:publisher) >> space >> number >> parts).as(:bundle_item) |
487
+ # Without BS prefix but with multi-letter prefix (continuing same type)
488
+ (multi_letter_prefix.as(:prefix) >> space >> number >> parts).as(:bundle_item) |
489
+ # Without BS prefix but with single-letter prefix
490
+ (single_letter_prefix.as(:prefix) >> space >> number >> parts).as(:bundle_item) |
491
+ # Number with space-separated alphanumeric part (BEFORE simple number+parts)
492
+ (number >> space_separated_part).as(:bundle_item) |
493
+ # Space-separated alphanumeric parts like "N001" (standalone, for abbreviated forms)
494
+ (match["A-Z"].repeat(1) >> match["0-9"].repeat(1)).as(:bundle_item) |
495
+ # Just number and parts (minimal form - LAST to avoid consuming space-separated)
496
+ (number >> parts).as(:bundle_item)
497
+ end
498
+
499
+ # Bundled identifier patterns
500
+ rule(:bundled_identifier) do
501
+ # Parts/Sections format: "BS NUMBER:Parts/Sections N and N:YEAR"
502
+ (publisher_or_type >> space >> number >> colon >> parts_bundle >> year).as(:bundled_parts) |
503
+ # List format with multiple separators: "BS SP 13; 14; 15 and 16:1949"
504
+ (publisher_or_type >> space >> bundle_item >>
505
+ (bundle_separator >> bundle_item).repeat(1) >>
506
+ year.maybe).as(:bundled_list)
507
+ end
508
+
509
+ # Supplements
510
+ rule(:supplement) do
511
+ (amendment | corrigendum | amd_suffix | amd_verbose).as(:supplement)
512
+ end
513
+ rule(:supplements) { supplement.repeat(0).as(:supplements) }
514
+
515
+ # Expert Commentary suffix - three formats:
516
+ # 1. "Expert Commentary" (full form)
517
+ # 2. "ExComm" (abbreviated form)
518
+ # 3. "ExComm (Fire)" (with optional topic suffix)
519
+ rule(:expert_commentary) do
520
+ space >> (
521
+ str("Expert Commentary").as(:expert_commentary_full) |
522
+ (str("ExComm") >> (space >> str("(") >> match["A-Za-z"].repeat(1).as(:expert_commentary_topic) >> str(")")).maybe).as(:expert_commentary)
523
+ )
524
+ end
525
+
526
+ # Tracked Changes suffix
527
+ rule(:tracked_changes) do
528
+ space >> dash >> space >> str("TC").as(:tracked_changes)
529
+ end
530
+
531
+ # PDF suffix
532
+ rule(:pdf_suffix) { space >> str("PDF").as(:pdf) }
533
+
534
+ # Translation (captures language name from various formats)
535
+ rule(:translation) do
536
+ (space >> str("(") >>
537
+ (
538
+ match["A-Za-z"].repeat(1).as(:translation_lang) >>
539
+ (space >> (str("Translation") | str("version"))).maybe
540
+ ) >>
541
+ str(")")) |
542
+ # All-caps format: " SPANISH TRANSLATION" (supplements already parsed)
543
+ (space >> (str("SPANISH") | str("FRENCH") | str("GERMAN") | str("ITALIAN")).as(:translation_upper) >> space >> str("TRANSLATION"))
544
+ end
545
+
546
+ # Collection number (second number after slash like 2035/2030)
547
+ rule(:collection_number) { slash >> digits.as(:second_number) }
548
+
549
+ # Adopted standard as opaque string
550
+ # Captures: "EN ISO 8601:2019", "EN IEC 62600:2020", "ISO 8601:2019", "IEC 62600:2020", "EN 10077-1:2006"
551
+ # Also CEN types: "CR 13933:2000", "ES 59008:2000", "ENV 41112:1991", "HD 60269-3", "CWA 13620-5:1999"
552
+ # IMPORTANT: Must NOT capture expert_commentary suffixes - let them be captured separately
553
+ rule(:adopted_org_prefix) do
554
+ str("EN") | str("ISO") | str("IEC") | str("CISPR") | str("CEN") | str("CLC") |
555
+ str("CR") | str("ES") | str("ENV") | str("HD") | str("CWA")
556
+ end
557
+
558
+ # Simple adopted string without expert commentary checks (for use in adopted_with_expert_commentary)
559
+ # Use character class that excludes "E" (first letter of "Expert Commentary" and "ExComm")
560
+ # This stops matching before expert commentary suffixes
561
+ rule(:adopted_string_no_expert) do
562
+ adopted_org_prefix >> match("[^E\n]").repeat(1).as(:adopted_string_no_expert)
563
+ end
564
+
565
+ # Match content that stops before expert commentary patterns and AMD suffixes
566
+ rule(:adopted_string_content) do
567
+ (supplement.absent? >> amd_suffix.absent? >> amd_verbose.absent? >> expert_commentary.absent? >> tracked_changes.absent? >> pdf_suffix.absent? >> translation.absent?) >>
568
+ match("[^\n]").repeat(1)
569
+ end
570
+
571
+ rule(:adopted_string) do
572
+ (adopted_org_prefix >> adopted_string_content).as(:adopted_string)
573
+ end
574
+
575
+ # Bare adopted identifier (no BSI prefix) - starts with ISO/IEC/CISPR
576
+ # IMPORTANT: Order in identifier rule handles this - bare_adopted is tried BEFORE publisher_or_type
577
+ # So we don't need to check for expert_commentary here
578
+ rule(:bare_adopted) do
579
+ (bs.absent? >> adopted_org_prefix >>
580
+ (supplement.absent? >> amd_suffix.absent? >> amd_verbose.absent? >> tracked_changes.absent? >> pdf_suffix.absent? >> translation.absent? >> match("[^\n]")).repeat(0)).as(:adopted_string)
581
+ end
582
+
583
+ # Value-Added Publication suffixes (wrapper pattern, not attributes)
584
+ rule(:vapSuffix) do
585
+ (space >> str("PDF").as(:pdf_format)) |
586
+ (space >> str("BOOK").as(:book_format)) |
587
+ (space >> dash >> space >> str("TC").as(:tc_format))
588
+ end
589
+
590
+ # Identifier patterns - try most specific first
591
+ rule(:identifier) do
592
+ # Standalone Amendment - must be first as it starts with "AMD"
593
+ standalone_amendment |
594
+ # Committee Document - must be before bare adopted as it starts with digits
595
+ committee_document |
596
+ # Index identifier - must be before regular identifier
597
+ (bs.as(:publisher) >> space >> number >> index_suffix.as(:index_suffix) >> year).as(:index_identifier) |
598
+ # Supplementary Index identifier - must be before regular identifier
599
+ (bs.as(:publisher) >> space >> number >> supplementary_index_suffix.as(:supplementary_index_suffix) >> year).as(:supplementary_index_identifier) |
600
+ # Explanatory Supplement identifier - must be before regular identifier
601
+ (bs.as(:publisher) >> space >> number >> parts >> explanatory_supplement_suffix.as(:explanatory_supplement_suffix) >> year).as(:explanatory_supplement_identifier) |
602
+ # Method identifier - must be before regular identifier
603
+ (bs.as(:publisher) >> space >> number >> parts >> method_suffix.as(:method_suffix) >> year).as(:method_identifier) |
604
+ # Test Method identifier - BS {number}:{test_series}:{test_id}:{year}
605
+ (bs.as(:publisher) >> space >> number >> test_method_suffix.as(:test_method_suffix) >> year).as(:test_method_identifier) |
606
+ # Section identifier - must be before regular identifier
607
+ (publisher_or_type >> space >> number >> section_suffix.as(:section_suffix) >> year).as(:section_identifier) |
608
+ # Detailed Specification identifier - must be before regular identifier
609
+ (bs.as(:publisher) >> space >> number >> detailed_spec_suffix.as(:detailed_spec_suffix) >> year).as(:detailed_specification) |
610
+ # Aerospace/Specialized identifier with letter suffix edition (e.g., BS AU 145e:2018)
611
+ # Must be before DISC and regular identifiers
612
+ # Supports supplements (+A1:2012, +C1:2020, etc.)
613
+ (bs.as(:publisher) >> space >> (single_letter_prefix | multi_letter_prefix).as(:prefix) >> space >>
614
+ number_with_letter_edition >> part_with_letter_edition.maybe >> iteration.as(:iteration).maybe >>
615
+ year >> supplements).as(:aerospace_identifier) |
616
+ # DISC identifier - "DISC PD <number>[-<part>]:<year>"
617
+ (disc_prefix >> number >> parts.maybe >> year).as(:disc_identifier) |
618
+ # Supplement Document - reverse format (Supplement No. N (YEAR) to BS...)
619
+ supplement_document_reverse.as(:supplement_document) |
620
+ # Supplement Document - forward format (BS NUMBER:Supplement No. N:YEAR)
621
+ supplement_document_forward |
622
+ # Addendum Document (BS NUMBER:Addendum No. N:YEAR)
623
+ addendum_document |
624
+ # Set identifier - multiple identifiers joined by +
625
+ # Must be BEFORE bare_adopted and regular identifier with adopted_string
626
+ set_identifier.as(:set) |
627
+ # Bundled Identifiers (must be before regular identifiers)
628
+ bundled_identifier |
629
+ # Bare adopted identifier (ISO, IEC without BSI prefix) - check BEFORE adopted_string
630
+ bare_adopted.as(:adopted_string) |
631
+ # Flex with v-style edition before date
632
+ (flex.as(:flex_type) >> space >> number >> parts >> flex_edition.maybe >> (year >> month.maybe).maybe >> supplements) |
633
+ # Regular BSI identifier - VAP suffix at the end
634
+ (publisher_or_type >>
635
+ (space >> adopted_string).maybe >>
636
+ (space >> number >> parts >> collection_number.maybe >>
637
+ (year >> month.maybe).maybe >>
638
+ flex_edition.maybe).maybe >>
639
+ supplements.maybe >>
640
+ edition.maybe >>
641
+ expert_commentary.maybe >>
642
+ translation.maybe >>
643
+ vapSuffix.maybe)
644
+ end
645
+
646
+ rule(:root) { identifier }
647
+
648
+ def self.parse(input)
649
+ # Normalize "BSI " to "BS " for consistency, but NOT for "BSI Flex"
650
+ normalized = if input.start_with?("BSI Flex")
651
+ input # Keep as is
652
+ else
653
+ input.gsub(/\bBSI\s+/, "BS ")
654
+ end
655
+ new.parse(normalized)
656
+ end
657
+ end
658
+ end
659
+ end