pubid 1.15.19 → 2.0.0.pre.alpha.1

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 (601) 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 +87 -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 +18 -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 +13 -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 +21 -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 +18 -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 +15 -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 +15 -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 +27 -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 +16 -0
  160. data/lib/pubid/ccsds/identifiers/base.rb +78 -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 +74 -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 +15 -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 +18 -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/language.rb +37 -0
  219. data/lib/pubid/components/locality.rb +10 -0
  220. data/lib/pubid/components/publisher.rb +36 -0
  221. data/lib/pubid/components/stage.rb +54 -0
  222. data/lib/pubid/components/type.rb +58 -0
  223. data/lib/pubid/components/typed_stage.rb +55 -0
  224. data/lib/pubid/components.rb +15 -0
  225. data/lib/pubid/core/pattern_doc_generator.rb +272 -0
  226. data/lib/pubid/core/update_codes.rb +77 -0
  227. data/lib/pubid/core.rb +8 -0
  228. data/lib/pubid/csa/builder.rb +671 -0
  229. data/lib/pubid/csa/components/code.rb +9 -0
  230. data/lib/pubid/csa/components.rb +9 -0
  231. data/lib/pubid/csa/composite_identifier.rb +27 -0
  232. data/lib/pubid/csa/identifier.rb +457 -0
  233. data/lib/pubid/csa/identifiers/base.rb +133 -0
  234. data/lib/pubid/csa/identifiers/bundled.rb +125 -0
  235. data/lib/pubid/csa/identifiers/canadian_adopted.rb +82 -0
  236. data/lib/pubid/csa/identifiers/cec.rb +129 -0
  237. data/lib/pubid/csa/identifiers/combined.rb +130 -0
  238. data/lib/pubid/csa/identifiers/csa_adopted.rb +78 -0
  239. data/lib/pubid/csa/identifiers/package.rb +65 -0
  240. data/lib/pubid/csa/identifiers/series.rb +127 -0
  241. data/lib/pubid/csa/identifiers/standard.rb +10 -0
  242. data/lib/pubid/csa/identifiers.rb +17 -0
  243. data/lib/pubid/csa/parser.rb +445 -0
  244. data/lib/pubid/csa/scheme.rb +44 -0
  245. data/lib/pubid/csa/single_identifier.rb +30 -0
  246. data/lib/pubid/csa/urn_generator.rb +80 -0
  247. data/lib/pubid/csa/wrapper_identifier.rb +31 -0
  248. data/lib/pubid/csa.rb +25 -0
  249. data/lib/pubid/etsi/builder.rb +133 -0
  250. data/lib/pubid/etsi/components/code.rb +42 -0
  251. data/lib/pubid/etsi/components/version.rb +37 -0
  252. data/lib/pubid/etsi/components.rb +10 -0
  253. data/lib/pubid/etsi/identifier.rb +14 -0
  254. data/lib/pubid/etsi/identifiers/amendment.rb +15 -0
  255. data/lib/pubid/etsi/identifiers/base.rb +38 -0
  256. data/lib/pubid/etsi/identifiers/corrigendum.rb +15 -0
  257. data/lib/pubid/etsi/identifiers/etsi_standard.rb +19 -0
  258. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +91 -0
  259. data/lib/pubid/etsi/identifiers.rb +14 -0
  260. data/lib/pubid/etsi/parser.rb +133 -0
  261. data/lib/pubid/etsi/scheme.rb +42 -0
  262. data/lib/pubid/etsi/urn_generator.rb +76 -0
  263. data/lib/pubid/etsi.rb +21 -0
  264. data/lib/pubid/export/auditor.rb +89 -0
  265. data/lib/pubid/export/data_class_exporter.rb +59 -0
  266. data/lib/pubid/export/exporter.rb +74 -0
  267. data/lib/pubid/export/flavor_exporter.rb +402 -0
  268. data/lib/pubid/export/ieee_exporter.rb +78 -0
  269. data/lib/pubid/export/itu_exporter.rb +66 -0
  270. data/lib/pubid/export/nist_exporter.rb +64 -0
  271. data/lib/pubid/export/registry_exporter.rb +90 -0
  272. data/lib/pubid/export/result.rb +97 -0
  273. data/lib/pubid/export/scheme_exporter.rb +70 -0
  274. data/lib/pubid/export.rb +18 -0
  275. data/lib/pubid/format_detector.rb +16 -0
  276. data/lib/pubid/format_registry.rb +42 -0
  277. data/lib/pubid/identifier.rb +235 -0
  278. data/lib/pubid/identifier_metadata.rb +148 -0
  279. data/lib/pubid/identifier_registry.rb +198 -0
  280. data/lib/pubid/idf/builder.rb +82 -0
  281. data/lib/pubid/idf/identifier.rb +69 -0
  282. data/lib/pubid/idf/identifiers/amendment.rb +27 -0
  283. data/lib/pubid/idf/identifiers/corrigendum.rb +27 -0
  284. data/lib/pubid/idf/identifiers/international_standard.rb +123 -0
  285. data/lib/pubid/idf/identifiers/reviewed_method.rb +100 -0
  286. data/lib/pubid/idf/identifiers.rb +13 -0
  287. data/lib/pubid/idf/parser.rb +143 -0
  288. data/lib/pubid/idf/scheme.rb +61 -0
  289. data/lib/pubid/idf/single_identifier.rb +19 -0
  290. data/lib/pubid/idf/supplement_identifier.rb +43 -0
  291. data/lib/pubid/idf/urn_generator.rb +84 -0
  292. data/lib/pubid/idf.rb +25 -0
  293. data/lib/pubid/iec/builder.rb +457 -0
  294. data/lib/pubid/iec/components/code.rb +59 -0
  295. data/lib/pubid/iec/components/consolidated_amendment.rb +59 -0
  296. data/lib/pubid/iec/components/publisher.rb +35 -0
  297. data/lib/pubid/iec/components/sheet.rb +32 -0
  298. data/lib/pubid/iec/components/trf_info.rb +38 -0
  299. data/lib/pubid/iec/components/vap_suffix.rb +41 -0
  300. data/lib/pubid/iec/identifier.rb +21 -0
  301. data/lib/pubid/iec/identifiers/amendment.rb +94 -0
  302. data/lib/pubid/iec/identifiers/base.rb +78 -0
  303. data/lib/pubid/iec/identifiers/component_specification.rb +39 -0
  304. data/lib/pubid/iec/identifiers/conformity_assessment.rb +39 -0
  305. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +86 -0
  306. data/lib/pubid/iec/identifiers/corrigendum.rb +94 -0
  307. data/lib/pubid/iec/identifiers/fragment_identifier.rb +141 -0
  308. data/lib/pubid/iec/identifiers/guide.rb +104 -0
  309. data/lib/pubid/iec/identifiers/international_standard.rb +147 -0
  310. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +104 -0
  311. data/lib/pubid/iec/identifiers/operational_document.rb +39 -0
  312. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +101 -0
  313. data/lib/pubid/iec/identifiers/sheet_identifier.rb +66 -0
  314. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +40 -0
  315. data/lib/pubid/iec/identifiers/systems_reference_document.rb +40 -0
  316. data/lib/pubid/iec/identifiers/technical_report.rb +132 -0
  317. data/lib/pubid/iec/identifiers/technical_specification.rb +132 -0
  318. data/lib/pubid/iec/identifiers/technology_report.rb +39 -0
  319. data/lib/pubid/iec/identifiers/test_report_form.rb +78 -0
  320. data/lib/pubid/iec/identifiers/vap_identifier.rb +77 -0
  321. data/lib/pubid/iec/identifiers/white_paper.rb +39 -0
  322. data/lib/pubid/iec/identifiers/working_document.rb +96 -0
  323. data/lib/pubid/iec/parser.rb +412 -0
  324. data/lib/pubid/iec/rendering_style.rb +113 -0
  325. data/lib/pubid/iec/scheme.rb +71 -0
  326. data/lib/pubid/iec/single_identifier.rb +80 -0
  327. data/lib/pubid/iec/supplement_identifier.rb +161 -0
  328. data/lib/pubid/iec/urn_generator.rb +193 -0
  329. data/lib/pubid/iec/urn_parser.rb +289 -0
  330. data/lib/pubid/iec.rb +85 -0
  331. data/lib/pubid/ieee/aiee/builder.rb +71 -0
  332. data/lib/pubid/ieee/aiee/identifier.rb +105 -0
  333. data/lib/pubid/ieee/aiee/parser.rb +130 -0
  334. data/lib/pubid/ieee/aiee.rb +11 -0
  335. data/lib/pubid/ieee/builder.rb +1237 -0
  336. data/lib/pubid/ieee/components/code.rb +102 -0
  337. data/lib/pubid/ieee/components/draft.rb +93 -0
  338. data/lib/pubid/ieee/components/relationship.rb +157 -0
  339. data/lib/pubid/ieee/components/typed_stage.rb +100 -0
  340. data/lib/pubid/ieee/identifier.rb +13 -0
  341. data/lib/pubid/ieee/identifiers/adopted_standard.rb +33 -0
  342. data/lib/pubid/ieee/identifiers/base.rb +591 -0
  343. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +35 -0
  344. data/lib/pubid/ieee/identifiers/corrigendum.rb +37 -0
  345. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +51 -0
  346. data/lib/pubid/ieee/identifiers/dual_identifier.rb +18 -0
  347. data/lib/pubid/ieee/identifiers/dual_published.rb +28 -0
  348. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +27 -0
  349. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +34 -0
  350. data/lib/pubid/ieee/identifiers/joint_development.rb +172 -0
  351. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +51 -0
  352. data/lib/pubid/ieee/identifiers/nesc/base.rb +56 -0
  353. data/lib/pubid/ieee/identifiers/nesc/draft.rb +28 -0
  354. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +32 -0
  355. data/lib/pubid/ieee/identifiers/nesc/redline.rb +26 -0
  356. data/lib/pubid/ieee/identifiers/nesc/standard.rb +26 -0
  357. data/lib/pubid/ieee/identifiers/nesc.rb +15 -0
  358. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +20 -0
  359. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +26 -0
  360. data/lib/pubid/ieee/identifiers/redlined_standard.rb +33 -0
  361. data/lib/pubid/ieee/identifiers/si_standard.rb +73 -0
  362. data/lib/pubid/ieee/identifiers/standard.rb +41 -0
  363. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +23 -0
  364. data/lib/pubid/ieee/identifiers.rb +33 -0
  365. data/lib/pubid/ieee/ire/builder.rb +61 -0
  366. data/lib/pubid/ieee/ire/identifier.rb +58 -0
  367. data/lib/pubid/ieee/ire/parser.rb +91 -0
  368. data/lib/pubid/ieee/ire.rb +11 -0
  369. data/lib/pubid/ieee/nesc/builder.rb +101 -0
  370. data/lib/pubid/ieee/nesc/parser.rb +154 -0
  371. data/lib/pubid/ieee/nesc.rb +10 -0
  372. data/lib/pubid/ieee/parser.rb +1226 -0
  373. data/lib/pubid/ieee/scheme.rb +90 -0
  374. data/lib/pubid/ieee/typed_stages.rb +172 -0
  375. data/lib/pubid/ieee/urn_generator.rb +188 -0
  376. data/lib/pubid/ieee.rb +32 -0
  377. data/lib/pubid/ieee_debug.rb +31 -0
  378. data/lib/pubid/iho/builder.rb +37 -0
  379. data/lib/pubid/iho/identifier.rb +19 -0
  380. data/lib/pubid/iho/identifiers/base.rb +41 -0
  381. data/lib/pubid/iho/identifiers/bibliographic.rb +20 -0
  382. data/lib/pubid/iho/identifiers/circular_letter.rb +19 -0
  383. data/lib/pubid/iho/identifiers/miscellaneous.rb +20 -0
  384. data/lib/pubid/iho/identifiers/publication.rb +19 -0
  385. data/lib/pubid/iho/identifiers/standard.rb +19 -0
  386. data/lib/pubid/iho/identifiers.rb +14 -0
  387. data/lib/pubid/iho/parser.rb +68 -0
  388. data/lib/pubid/iho/scheme.rb +29 -0
  389. data/lib/pubid/iho/urn_generator.rb +29 -0
  390. data/lib/pubid/iho.rb +21 -0
  391. data/lib/pubid/iso/builder.rb +305 -0
  392. data/lib/pubid/iso/bundled_identifier.rb +85 -0
  393. data/lib/pubid/iso/combined_identifier.rb +22 -0
  394. data/lib/pubid/iso/components/code.rb +36 -0
  395. data/lib/pubid/iso/components/publisher.rb +60 -0
  396. data/lib/pubid/iso/components.rb +12 -0
  397. data/lib/pubid/iso/format_resolver.rb +45 -0
  398. data/lib/pubid/iso/identifier.rb +69 -0
  399. data/lib/pubid/iso/identifiers/addendum.rb +104 -0
  400. data/lib/pubid/iso/identifiers/amendment.rb +128 -0
  401. data/lib/pubid/iso/identifiers/base.rb +115 -0
  402. data/lib/pubid/iso/identifiers/corrigendum.rb +108 -0
  403. data/lib/pubid/iso/identifiers/data.rb +76 -0
  404. data/lib/pubid/iso/identifiers/directives.rb +59 -0
  405. data/lib/pubid/iso/identifiers/directives_supplement.rb +119 -0
  406. data/lib/pubid/iso/identifiers/extract.rb +30 -0
  407. data/lib/pubid/iso/identifiers/guide.rb +100 -0
  408. data/lib/pubid/iso/identifiers/international_standard.rb +168 -0
  409. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +94 -0
  410. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +89 -0
  411. data/lib/pubid/iso/identifiers/pas.rb +93 -0
  412. data/lib/pubid/iso/identifiers/recommendation.rb +45 -0
  413. data/lib/pubid/iso/identifiers/supplement.rb +87 -0
  414. data/lib/pubid/iso/identifiers/tc_document.rb +108 -0
  415. data/lib/pubid/iso/identifiers/technical_report.rb +103 -0
  416. data/lib/pubid/iso/identifiers/technical_specification.rb +102 -0
  417. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +95 -0
  418. data/lib/pubid/iso/identifiers.rb +33 -0
  419. data/lib/pubid/iso/parser.rb +510 -0
  420. data/lib/pubid/iso/rendering_style.rb +120 -0
  421. data/lib/pubid/iso/scheme.rb +187 -0
  422. data/lib/pubid/iso/single_identifier.rb +61 -0
  423. data/lib/pubid/iso/supplement_identifier.rb +27 -0
  424. data/lib/pubid/iso/urn_generator.rb +412 -0
  425. data/lib/pubid/iso/urn_parser.rb +423 -0
  426. data/lib/pubid/iso/utilities.rb +86 -0
  427. data/lib/pubid/iso.rb +50 -0
  428. data/lib/pubid/itu/builder.rb +171 -0
  429. data/lib/pubid/itu/components/code.rb +39 -0
  430. data/lib/pubid/itu/components/sector.rb +35 -0
  431. data/lib/pubid/itu/components/series.rb +29 -0
  432. data/lib/pubid/itu/i18n.rb +9 -0
  433. data/lib/pubid/itu/i18n.yaml +30 -0
  434. data/lib/pubid/itu/identifier.rb +53 -0
  435. data/lib/pubid/itu/identifiers/amendment.rb +43 -0
  436. data/lib/pubid/itu/identifiers/annex.rb +74 -0
  437. data/lib/pubid/itu/identifiers/base.rb +154 -0
  438. data/lib/pubid/itu/identifiers/combined_identifier.rb +47 -0
  439. data/lib/pubid/itu/identifiers/corrigendum.rb +44 -0
  440. data/lib/pubid/itu/identifiers/recommendation.rb +16 -0
  441. data/lib/pubid/itu/identifiers/special_publication.rb +31 -0
  442. data/lib/pubid/itu/identifiers/supplement.rb +46 -0
  443. data/lib/pubid/itu/identifiers.rb +16 -0
  444. data/lib/pubid/itu/model.rb +111 -0
  445. data/lib/pubid/itu/parser.rb +225 -0
  446. data/lib/pubid/itu/scheme.rb +174 -0
  447. data/lib/pubid/itu/urn_generator.rb +105 -0
  448. data/lib/pubid/itu.rb +22 -0
  449. data/lib/pubid/jcgm/builder.rb +88 -0
  450. data/lib/pubid/jcgm/components/publisher.rb +20 -0
  451. data/lib/pubid/jcgm/components.rb +9 -0
  452. data/lib/pubid/jcgm/identifier.rb +11 -0
  453. data/lib/pubid/jcgm/identifiers/amendment.rb +35 -0
  454. data/lib/pubid/jcgm/identifiers/guide.rb +21 -0
  455. data/lib/pubid/jcgm/identifiers/gum_guide.rb +51 -0
  456. data/lib/pubid/jcgm/identifiers.rb +11 -0
  457. data/lib/pubid/jcgm/parser.rb +84 -0
  458. data/lib/pubid/jcgm/scheme.rb +60 -0
  459. data/lib/pubid/jcgm/single_identifier.rb +48 -0
  460. data/lib/pubid/jcgm/supplement_identifier.rb +16 -0
  461. data/lib/pubid/jcgm/urn_generator.rb +110 -0
  462. data/lib/pubid/jcgm.rb +31 -0
  463. data/lib/pubid/jis/builder.rb +124 -0
  464. data/lib/pubid/jis/components/code.rb +59 -0
  465. data/lib/pubid/jis/components.rb +9 -0
  466. data/lib/pubid/jis/identifier.rb +18 -0
  467. data/lib/pubid/jis/identifiers/amendment.rb +16 -0
  468. data/lib/pubid/jis/identifiers/base.rb +72 -0
  469. data/lib/pubid/jis/identifiers/explanation.rb +22 -0
  470. data/lib/pubid/jis/identifiers/japanese_industrial_standard.rb +16 -0
  471. data/lib/pubid/jis/identifiers/standard.rb +27 -0
  472. data/lib/pubid/jis/identifiers/technical_report.rb +31 -0
  473. data/lib/pubid/jis/identifiers/technical_specification.rb +31 -0
  474. data/lib/pubid/jis/identifiers.rb +17 -0
  475. data/lib/pubid/jis/parser.rb +109 -0
  476. data/lib/pubid/jis/scheme.rb +49 -0
  477. data/lib/pubid/jis/single_identifier.rb +37 -0
  478. data/lib/pubid/jis/supplement_identifier.rb +47 -0
  479. data/lib/pubid/jis/urn_generator.rb +25 -0
  480. data/lib/pubid/jis.rb +23 -0
  481. data/lib/pubid/lutaml/no_store_registration.rb +30 -0
  482. data/lib/pubid/nist/builder.rb +2100 -0
  483. data/lib/pubid/nist/components/code.rb +38 -0
  484. data/lib/pubid/nist/components/edition.rb +118 -0
  485. data/lib/pubid/nist/components/issue_number.rb +28 -0
  486. data/lib/pubid/nist/components/part.rb +77 -0
  487. data/lib/pubid/nist/components/publisher.rb +24 -0
  488. data/lib/pubid/nist/components/stage.rb +53 -0
  489. data/lib/pubid/nist/components/supplement.rb +121 -0
  490. data/lib/pubid/nist/components/translation.rb +42 -0
  491. data/lib/pubid/nist/components/update.rb +103 -0
  492. data/lib/pubid/nist/components/version.rb +35 -0
  493. data/lib/pubid/nist/components/volume.rb +32 -0
  494. data/lib/pubid/nist/components.rb +19 -0
  495. data/lib/pubid/nist/configuration.rb +77 -0
  496. data/lib/pubid/nist/identifiers/base.rb +499 -0
  497. data/lib/pubid/nist/identifiers/circular.rb +68 -0
  498. data/lib/pubid/nist/identifiers/circular_supplement.rb +50 -0
  499. data/lib/pubid/nist/identifiers/commercial_standard.rb +41 -0
  500. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +56 -0
  501. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +56 -0
  502. data/lib/pubid/nist/identifiers/crpl_report.rb +135 -0
  503. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +94 -0
  504. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +35 -0
  505. data/lib/pubid/nist/identifiers/handbook.rb +50 -0
  506. data/lib/pubid/nist/identifiers/internal_report.rb +56 -0
  507. data/lib/pubid/nist/identifiers/letter_circular.rb +45 -0
  508. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +65 -0
  509. data/lib/pubid/nist/identifiers/monograph.rb +69 -0
  510. data/lib/pubid/nist/identifiers/ncstar.rb +41 -0
  511. data/lib/pubid/nist/identifiers/nsrds.rb +41 -0
  512. data/lib/pubid/nist/identifiers/owmwp.rb +35 -0
  513. data/lib/pubid/nist/identifiers/report.rb +68 -0
  514. data/lib/pubid/nist/identifiers/special_publication.rb +36 -0
  515. data/lib/pubid/nist/identifiers/technical_note.rb +90 -0
  516. data/lib/pubid/nist/identifiers.rb +33 -0
  517. data/lib/pubid/nist/parser.rb +1084 -0
  518. data/lib/pubid/nist/scheme.rb +199 -0
  519. data/lib/pubid/nist/supplement_identifier.rb +83 -0
  520. data/lib/pubid/nist/urn_generator.rb +127 -0
  521. data/lib/pubid/nist.rb +36 -0
  522. data/lib/pubid/oiml/builder.rb +189 -0
  523. data/lib/pubid/oiml/components/code.rb +20 -0
  524. data/lib/pubid/oiml/components.rb +9 -0
  525. data/lib/pubid/oiml/identifier.rb +11 -0
  526. data/lib/pubid/oiml/identifiers/amendment.rb +13 -0
  527. data/lib/pubid/oiml/identifiers/annex.rb +62 -0
  528. data/lib/pubid/oiml/identifiers/base.rb +36 -0
  529. data/lib/pubid/oiml/identifiers/basic_publication.rb +13 -0
  530. data/lib/pubid/oiml/identifiers/document.rb +13 -0
  531. data/lib/pubid/oiml/identifiers/expert_report.rb +13 -0
  532. data/lib/pubid/oiml/identifiers/guide.rb +13 -0
  533. data/lib/pubid/oiml/identifiers/recommendation.rb +13 -0
  534. data/lib/pubid/oiml/identifiers/seminar_report.rb +13 -0
  535. data/lib/pubid/oiml/identifiers/vocabulary.rb +13 -0
  536. data/lib/pubid/oiml/identifiers.rb +18 -0
  537. data/lib/pubid/oiml/parser.rb +173 -0
  538. data/lib/pubid/oiml/scheme.rb +46 -0
  539. data/lib/pubid/oiml/single_identifier.rb +90 -0
  540. data/lib/pubid/oiml/supplement_identifier.rb +43 -0
  541. data/lib/pubid/oiml/urn_generator.rb +64 -0
  542. data/lib/pubid/oiml.rb +26 -0
  543. data/lib/pubid/parser/common_parse_methods.rb +13 -0
  544. data/lib/pubid/parser/common_parse_rules.rb +56 -0
  545. data/lib/pubid/parser.rb +8 -0
  546. data/lib/pubid/parsers/base.rb +11 -0
  547. data/lib/pubid/parsers/mr_string.rb +93 -0
  548. data/lib/pubid/plateau/builder.rb +50 -0
  549. data/lib/pubid/plateau/identifiers/annex.rb +16 -0
  550. data/lib/pubid/plateau/identifiers/base.rb +51 -0
  551. data/lib/pubid/plateau/identifiers/handbook.rb +34 -0
  552. data/lib/pubid/plateau/identifiers/technical_report.rb +20 -0
  553. data/lib/pubid/plateau/identifiers.rb +12 -0
  554. data/lib/pubid/plateau/parser.rb +63 -0
  555. data/lib/pubid/plateau/scheme.rb +45 -0
  556. data/lib/pubid/plateau/supplement_identifier.rb +72 -0
  557. data/lib/pubid/plateau/urn_generator.rb +29 -0
  558. data/lib/pubid/plateau.rb +25 -0
  559. data/lib/pubid/renderers/base.rb +19 -0
  560. data/lib/pubid/renderers/directives_renderer.rb +62 -0
  561. data/lib/pubid/renderers/guide_renderer.rb +20 -0
  562. data/lib/pubid/renderers/human_readable.rb +58 -0
  563. data/lib/pubid/renderers/iwa_renderer.rb +16 -0
  564. data/lib/pubid/renderers/mr_string.rb +16 -0
  565. data/lib/pubid/renderers/supplement_renderer.rb +33 -0
  566. data/lib/pubid/renderers/urn.rb +11 -0
  567. data/lib/pubid/renderers.rb +14 -0
  568. data/lib/pubid/rendering/base.rb +73 -0
  569. data/lib/pubid/rendering/common.rb +211 -0
  570. data/lib/pubid/rendering/context.rb +156 -0
  571. data/lib/pubid/rendering/date.rb +27 -0
  572. data/lib/pubid/rendering/format.rb +25 -0
  573. data/lib/pubid/rendering/language.rb +21 -0
  574. data/lib/pubid/rendering/numbering.rb +24 -0
  575. data/lib/pubid/rendering/publisher.rb +25 -0
  576. data/lib/pubid/rendering/stage.rb +38 -0
  577. data/lib/pubid/rendering/supplement.rb +46 -0
  578. data/lib/pubid/rendering.rb +16 -0
  579. data/lib/pubid/sae/builder.rb +32 -0
  580. data/lib/pubid/sae/components/code.rb +9 -0
  581. data/lib/pubid/sae/components/date.rb +19 -0
  582. data/lib/pubid/sae/components/type.rb +19 -0
  583. data/lib/pubid/sae/components.rb +11 -0
  584. data/lib/pubid/sae/identifier.rb +14 -0
  585. data/lib/pubid/sae/identifiers/base.rb +42 -0
  586. data/lib/pubid/sae/identifiers.rb +9 -0
  587. data/lib/pubid/sae/parser.rb +55 -0
  588. data/lib/pubid/sae/scheme.rb +47 -0
  589. data/lib/pubid/sae/urn_generator.rb +38 -0
  590. data/lib/pubid/sae.rb +19 -0
  591. data/lib/pubid/scheme.rb +207 -0
  592. data/lib/pubid/urn_generator/base.rb +110 -0
  593. data/lib/pubid/utils/string_normalizer.rb +196 -0
  594. data/lib/pubid/utils.rb +7 -0
  595. data/lib/pubid/version.rb +3 -1
  596. data/lib/pubid.rb +137 -13
  597. data/lib/tasks/docs.rake +37 -0
  598. data/lib/tasks/export.rake +38 -0
  599. data/lib/tasks/website-data.json +7488 -0
  600. metadata +613 -171
  601. data/lib/pubid/registry.rb +0 -30
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Pubid
6
+ module Csa
7
+ # CompositeIdentifier is the base class for identifiers that contain
8
+ # collections of other identifiers or package materials.
9
+ #
10
+ # Examples:
11
+ # - PackageIdentifier: Base + package materials
12
+ # - Future: BundleIdentifier refactor to use composite
13
+ #
14
+ # This follows the Composite pattern where an identifier can contain
15
+ # other identifiers or additional metadata as a collection.
16
+ class CompositeIdentifier < Lutaml::Model::Serializable
17
+ # The primary/base identifier
18
+ # Use attr_accessor since it can be any identifier object
19
+ attr_accessor :base_identifier
20
+
21
+ # Subclasses MUST implement to_s to define how they render
22
+ def to_s
23
+ raise NotImplementedError, "Subclasses must implement to_s method"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,457 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Csa
5
+ class Identifier
6
+ def self.parse(input)
7
+ # Filter out comments
8
+ return nil if input.start_with?("#")
9
+
10
+ # Filter out non-standards
11
+ return nil if input.match?(/^CSA (Communities|Group|Learning|OnDemand|Update)/)
12
+
13
+ # Preprocessing: normalize CEI to IEC (French name)
14
+ input = input.gsub("CEI/IEC", "IEC").gsub(/\bCEI\b/, "IEC")
15
+
16
+ # Detect CAN/ wrapper (Canadian adoption)
17
+ if input.start_with?("CAN/")
18
+ # Check if this is actually a bundled/combined identifier with + or /
19
+ # that should NOT be wrapped in CanadianAdopted
20
+ wrapped_input = input.sub(/^CAN\//, "")
21
+
22
+ # Check for bundled (+) or combined (/ or ,) patterns that should remain as-is
23
+ # These should be parsed normally, with publisher prefix applied to each part
24
+ # Patterns to detect:
25
+ # 1. Bundled: + separator (e.g., "CSA B127.1:99 + B127.2:99")
26
+ # 2. Combined with space: / separator with space before CSA- (e.g., "CSA A23.1:24/CSA A23.2:24")
27
+ # 3. Combined with CAN/CSA-: / separator with CSA- appearing multiple times (e.g., "CSA-B138.1-17/CSA-B138.2-17")
28
+ if wrapped_input.include?("+") ||
29
+ (wrapped_input.include?("/") && wrapped_input.match?(/\s+CSA-/)) ||
30
+ (wrapped_input.include?("/") && wrapped_input.scan("CSA-").length > 1)
31
+ # This is a bundled or combined identifier - parse normally and add prefix
32
+ # Normalize CSA- to CSA (with space) for parsing
33
+ normalized = wrapped_input.sub(/^CSA-/, "CSA ")
34
+ normalized = normalized.gsub("CAN/CSA-", "CSA ").gsub("CAN3-",
35
+ "CSA ")
36
+ normalized = normalized.gsub(/\s+/, " ").strip
37
+
38
+ # Parse normally (will create Bundled or Combined identifier)
39
+ tree = Parser.new.parse(normalized)
40
+ result = Builder.new.build(tree)
41
+
42
+ # Apply CAN/CSA- prefix to the appropriate parts
43
+ if result
44
+ set_publisher_prefix(result, "CAN/CSA-")
45
+
46
+ # Handle reaffirmation if present
47
+ if (wrapped_input =~ /\(R(\d{4})\)/) && result.class.attributes.key?(:reaffirmation)
48
+ result.reaffirmation = $1
49
+ end
50
+ end
51
+
52
+ return result
53
+ end
54
+
55
+ # This is a standard single identifier wrapped in CanadianAdopted
56
+ # Remove CAN/ prefix (already done above)
57
+
58
+ # Extract reaffirmation FIRST (before any other processing)
59
+ reaffirm_year = nil
60
+ reaffirmation_was_4digit = false # Track original format
61
+ if wrapped_input =~ /\(R(\d{2,4})\)/
62
+ reaffirm_year = $1
63
+ reaffirmation_was_4digit = ($1.length == 4) # Track if original was 4-digit
64
+ # Convert 2-digit year to 4-digit if needed
65
+ if reaffirm_year.length == 2
66
+ year_int = reaffirm_year.to_i
67
+ reaffirm_year = year_int < 50 ? "20#{reaffirm_year}" : "19#{reaffirm_year}"
68
+ end
69
+ wrapped_input = wrapped_input.sub(/\s*\(R\d{2,4}\)/, "")
70
+ end
71
+
72
+ # Detect and preserve original format (CSA- vs CSA)
73
+ # Also track that this is a CAN/CSA- identifier (not just CSA-)
74
+ original_prefix = if wrapped_input.start_with?("CSA-")
75
+ "CSA-"
76
+ elsif wrapped_input.start_with?("CSA ")
77
+ "CSA"
78
+ end
79
+ is_can_csa = true # Track that this has the CAN/ wrapper
80
+
81
+ # Normalize CSA- to CSA (with space) for parsing
82
+ wrapped_input = wrapped_input.sub(/^CSA-/, "CSA ")
83
+
84
+ # Parse the wrapped identifier recursively
85
+ wrapped_identifier = parse(wrapped_input)
86
+ return nil unless wrapped_identifier
87
+
88
+ # NOTE: Series identifiers should be wrapped in CanadianAdopted when
89
+ # they have CAN/CSA- prefix. The Series will handle rendering correctly.
90
+ # Do NOT return Series directly - always wrap in CanadianAdopted.
91
+
92
+ # Set publisher prefix on wrapped identifier
93
+ # For Series identifiers with CAN/ wrapper, use full "CAN/CSA-" prefix
94
+ # For other identifiers, use the detected original_prefix ("CSA-" or "CSA")
95
+ if wrapped_identifier.class.attributes.key?(:publisher_prefix)
96
+ if is_can_csa && wrapped_identifier.is_a?(Identifiers::Series)
97
+ # Series gets full "CAN/CSA-" prefix for proper rendering
98
+ wrapped_identifier.publisher_prefix = "CAN/CSA-"
99
+ elsif original_prefix
100
+ # For Combined identifiers, set on first identifier
101
+ if wrapped_identifier.is_a?(Identifiers::Combined) && wrapped_identifier.first
102
+ wrapped_identifier.first.publisher_prefix = original_prefix if wrapped_identifier.first.class.attributes.key?(:publisher_prefix)
103
+ else
104
+ # For non-Combined identifiers, set directly
105
+ wrapped_identifier.publisher_prefix = original_prefix
106
+ end
107
+ end
108
+ end
109
+
110
+ # Set reaffirmation on wrapped_identifier if it has the attribute
111
+ if wrapped_identifier.class.attributes.key?(:reaffirmation) && reaffirm_year
112
+ wrapped_identifier.reaffirmation = reaffirm_year
113
+ if wrapped_identifier.class.attributes.key?(:original_reaffirmation_4digit)
114
+ wrapped_identifier.original_reaffirmation_4digit = reaffirmation_was_4digit
115
+ end
116
+ end
117
+
118
+ # Create CanadianAdoptedIdentifier wrapper
119
+ result = Identifiers::CanadianAdopted.new
120
+ result.wrapped_identifier = wrapped_identifier
121
+ result.reaffirmation = reaffirm_year if reaffirm_year
122
+
123
+ return result
124
+ end
125
+
126
+ # Detect CAN3- wrapper (historical Canadian adoption)
127
+ if input.start_with?("CAN3-")
128
+ # This is a historical Canadian adoption - parse as wrapper
129
+ # Remove CAN3- prefix
130
+ wrapped_input = input.sub(/^CAN3-/, "CSA ")
131
+
132
+ # Detect year format before normalization (CAN3- standards use dash format)
133
+ # Format: CAN3-Z299.0-86 (uses dash, not colon)
134
+ has_dash_year = wrapped_input.match?(/-\d{2}\b/) # Match -86, -05, etc. (2-digit years)
135
+
136
+ # Extract reaffirmation FIRST (before any other processing)
137
+ reaffirm_year = nil
138
+ reaffirmation_was_4digit = false # Track original format
139
+ if wrapped_input =~ /\(R(\d{2,4})\)/
140
+ reaffirm_year = $1
141
+ reaffirmation_was_4digit = ($1.length == 4) # Track if original was 4-digit
142
+ # Convert 2-digit year to 4-digit if needed
143
+ if reaffirm_year.length == 2
144
+ year_int = reaffirm_year.to_i
145
+ reaffirm_year = year_int < 50 ? "20#{reaffirm_year}" : "19#{reaffirm_year}"
146
+ end
147
+ wrapped_input = wrapped_input.sub(/\s*\(R\d{2,4}\)/, "")
148
+ end
149
+
150
+ # Parse the wrapped identifier recursively
151
+ wrapped_identifier = parse(wrapped_input)
152
+ return nil unless wrapped_identifier
153
+
154
+ # Set year_format for dash format identifiers (preserve original 2-digit year)
155
+ if has_dash_year && wrapped_identifier.class.attributes.key?(:year_format)
156
+ wrapped_identifier.year_format = "dash"
157
+ # Mark original year as 2-digit so renderer converts back (1986 → 86)
158
+ if wrapped_identifier.class.attributes.key?(:original_year_4digit)
159
+ wrapped_identifier.original_year_4digit = false
160
+ end
161
+ end
162
+
163
+ # Check if this is a Series identifier - return it directly with CAN3- prefix
164
+ # Series identifiers are complete identifier types and handle the prefix themselves
165
+ # They don't need to be wrapped in CanadianAdopted
166
+ if wrapped_identifier.is_a?(Identifiers::Series)
167
+ wrapped_identifier.publisher_prefix = "CAN3-"
168
+ wrapped_identifier.reaffirmation = reaffirm_year if reaffirm_year
169
+ wrapped_identifier.original_reaffirmation_4digit = reaffirmation_was_4digit
170
+ return wrapped_identifier
171
+ end
172
+
173
+ # Set CAN3- as publisher prefix on wrapped identifier
174
+ if wrapped_identifier.class.attributes.key?(:publisher_prefix)
175
+ wrapped_identifier.publisher_prefix = "CAN3-"
176
+ end
177
+
178
+ # Set reaffirmation on wrapped_identifier if it has the attribute
179
+ if wrapped_identifier.class.attributes.key?(:reaffirmation) && reaffirm_year
180
+ wrapped_identifier.reaffirmation = reaffirm_year
181
+ if wrapped_identifier.class.attributes.key?(:original_reaffirmation_4digit)
182
+ wrapped_identifier.original_reaffirmation_4digit = reaffirmation_was_4digit
183
+ end
184
+ end
185
+
186
+ # Create CanadianAdoptedIdentifier wrapper
187
+ result = Identifiers::CanadianAdopted.new
188
+ result.wrapped_identifier = wrapped_identifier
189
+ result.reaffirmation = reaffirm_year if reaffirm_year
190
+
191
+ return result
192
+ end
193
+
194
+ # Detect CSA adoption of international standards
195
+ # Examples: CSA ISO/IEC TR 12785-3:15, CSA CISPR 16-1-1:18, CSA IEC 60601-1:08
196
+ # CSA CEI/IEC 61000-4-28-01 (bilingual)
197
+ if input.match?(/^CSA (ISO\/IEC|CEI\/IEC|CISPR|IEC|CEI|ISO)\s/)
198
+ # This is CSA adoption of international standard
199
+ # Extract the wrapped standard portion
200
+ wrapped_input = input.sub(/^CSA\s+/, "")
201
+
202
+ # Extract reaffirmation FIRST (before parsing)
203
+ reaffirm_year = nil
204
+ if wrapped_input =~ /\(R(\d{2,4})\)/
205
+ reaffirm_year = $1
206
+ # Convert 2-digit year to 4-digit if needed
207
+ if reaffirm_year.length == 2
208
+ year_int = reaffirm_year.to_i
209
+ reaffirm_year = year_int < 50 ? "20#{reaffirm_year}" : "19#{reaffirm_year}"
210
+ end
211
+ wrapped_input = wrapped_input.sub(/\s*\(R\d{2,4}\)/, "")
212
+ end
213
+
214
+ # Convert 2-digit years to 4-digit for external parser
215
+ # :15 → :2015, :04 → :2004
216
+ if wrapped_input =~ /:(\d{2})\b/
217
+ short_year_str = $1 # Keep as string "04", "15", etc.
218
+ short_year_int = short_year_str.to_i
219
+ # Determine century: 00-49 → 2000s, 50-99 → 1900s
220
+ full_year = short_year_int < 50 ? "20#{short_year_str}" : "19#{short_year_str}"
221
+ wrapped_input = wrapped_input.sub(/:#{short_year_str}\b/,
222
+ ":#{full_year}")
223
+ end
224
+
225
+ # Convert CSA amendment format to ISO/IEC format
226
+ # /A1:22 → /Amd 1:2022, /A1-22 → /Amd 1-2022
227
+ # Also handle 2-digit and 4-digit amendment years (convert to 4-digit)
228
+ # Note: In gsub blocks with string regex, we must use $1, $2, $3
229
+ # because the block receives a String, not MatchData
230
+ wrapped_input = wrapped_input.gsub(%r{/A(\d+)([:/-])(\d{2,4})\b}) do
231
+ amendment_num = $1
232
+ separator = $2
233
+ amend_year_str = $3
234
+ amend_year_int = amend_year_str.to_i
235
+ # Convert 2-digit year to 4-digit if needed
236
+ if amend_year_str.length == 2
237
+ amend_full_year = amend_year_int < 50 ? "20#{amend_year_str}" : "19#{amend_year_str}"
238
+ else
239
+ amend_full_year = amend_year_str
240
+ end
241
+ "/Amd #{amendment_num}#{separator}#{amend_full_year}"
242
+ end
243
+
244
+ # Parse with appropriate flavor parser
245
+ wrapped_identifier = parse_external_standard(wrapped_input)
246
+ return nil unless wrapped_identifier
247
+
248
+ # Create CsaAdoptedIdentifier wrapper
249
+ result = Identifiers::CsaAdopted.new
250
+ result.wrapped_identifier = wrapped_identifier
251
+ result.reaffirmation = reaffirm_year if reaffirm_year
252
+
253
+ return result
254
+ end
255
+
256
+ # Detect package identifiers
257
+ # Examples: CSA Z662:23 PACKAGE INCLUDES: +1 (PDF & ESA)
258
+ # CSA B149.1:25 Code, Handbook & Training Package (materials BEFORE keyword)
259
+ # CSA B149.1:20 PACKAGE (PDF + PRINT) (no materials)
260
+ # CSA B108:23 PACKAGE (no trailing space)
261
+ if input.match?(/\sPACKAGE\b/i)
262
+ # Handle two formats:
263
+ # 1. {base} PACKAGE {materials} - materials after keyword
264
+ # 2. {base} {materials} PACKAGE - materials before keyword
265
+
266
+ # Check if materials come after PACKAGE keyword
267
+ # Match: "CSA Z662:23 PACKAGE INCLUDES: +1" or "CSA B149.1:20 PACKAGE (PDF + PRINT)"
268
+ case input
269
+ when /\sPACKAGE\s+[A-Z]/i
270
+ # Format: {base} PACKAGE {materials}
271
+ # Extract materials after PACKAGE keyword
272
+ base_input, package_materials = input.split(/\s+PACKAGE\s+/i, 2)
273
+ base_input = base_input.strip
274
+ package_materials = package_materials ? package_materials.strip : ""
275
+ materials_after = true
276
+ when /:(\d{2,4})(\s+[^P]+)\s+PACKAGE/i
277
+ # Format: {base} PACKAGE or {base} {materials} PACKAGE
278
+ # Examples: "C22.1-15 PACKAGE" (no materials), "CSA B149.1:25 Code, Handbook & Training Package"
279
+
280
+ # Check if there's a year followed by materials before PACKAGE
281
+ # Must check this BEFORE the generic "{base} PACKAGE" pattern
282
+ $1
283
+ $2
284
+
285
+ # Check if this is a combined identifier (has comma with CSA after it)
286
+ # Pattern: ", CSA" or ", CAN" which indicates combined identifier
287
+ if input.match?(/,\s+CSA/)
288
+ # For combined identifiers, we need to extract everything before "& Training Package"
289
+ # The base is the combined identifier, materials is just "& Training Package"
290
+ combined_match = input.match(/^(.+?)(\s+&[^P]+)\s+PACKAGE$/i)
291
+ if combined_match
292
+ base_input = combined_match[1].strip
293
+ package_materials = "#{combined_match[2].strip} Package" # Keep "& Training Package"
294
+ else
295
+ # Fallback to year-based extraction
296
+ year_match = input.match(/:\d{2,4}/)
297
+ if year_match
298
+ base_input = input[0..(year_match.end(0) - 1)]
299
+ materials_input = input[year_match.end(0)..].strip
300
+ package_materials = materials_input
301
+ end
302
+ end
303
+ else
304
+ # Standard single identifier with materials before PACKAGE
305
+ year_match = input.match(/:\d{2,4}/)
306
+ if year_match
307
+ base_input = input[0..(year_match.end(0) - 1)]
308
+ # Materials is everything between base and PACKAGE - keep the "Package" suffix for correct capitalization
309
+ materials_input = input[year_match.end(0)..].strip
310
+ package_materials = materials_input # Keep full materials including "Package" suffix
311
+ base_input = base_input.strip
312
+ end
313
+ end
314
+ materials_after = false
315
+ # Format: {base} {materials} PACKAGE - "CSA B149.1:25 Code, Handbook & Training Package"
316
+ # OR: Combined identifier with package: "CSA B149.1:25, CSA B149.2:25 & Training Package"
317
+ when /^(.+?)\s+PACKAGE\s*$/i
318
+ # Format: {base} PACKAGE (no materials) - "C22.1-15 PACKAGE"
319
+ # Treat PACKAGE as the package description
320
+ base_input = input.sub(/\s+PACKAGE\s*$/i, "").strip
321
+ package_materials = "" # No additional materials
322
+ materials_after = true
323
+ else
324
+ # Fallback: try parsing incrementally
325
+ tokens = input.split(/\s+/)
326
+ base_input = ""
327
+ tokens.each do |token|
328
+ break if token.match?(/^PACKAGE$/i)
329
+
330
+ test_input = base_input.empty? ? token : "#{base_input} #{token}"
331
+ parsed = parse(test_input)
332
+ if parsed
333
+ base_input = test_input
334
+ else
335
+ break
336
+ end
337
+ end
338
+
339
+ # Extract materials as everything between base and PACKAGE
340
+ if base_input && base_input.length < input.length
341
+ materials_input = input[base_input.length..].strip
342
+ package_materials = materials_input.sub(/\s+PACKAGE\s*$/i,
343
+ "").strip
344
+ materials_after = !package_materials.empty?
345
+ end
346
+ end
347
+
348
+ # Parse base identifier recursively
349
+ base_identifier = base_input ? parse(base_input) : nil
350
+ return nil unless base_identifier
351
+
352
+ # Create PackageIdentifier
353
+ result = Identifiers::Package.new
354
+ result.base_identifier = base_identifier
355
+ # Set materials if present
356
+ if package_materials && !package_materials.empty?
357
+ result.package_materials = package_materials
358
+ end
359
+ result.package_keyword = "PACKAGE"
360
+ # Set materials_after_keyword flag based on which format we detected
361
+ result.materials_after_keyword = materials_after
362
+
363
+ return result
364
+ end
365
+
366
+ # Legacy handling for CAN/CSA- and CAN3- (will be migrated to proper classes later)
367
+ # Detect original publisher prefix before normalization
368
+ publisher_prefix = if input.start_with?("CAN/CSA-")
369
+ "CAN/CSA-"
370
+ elsif input.start_with?("CAN3-")
371
+ "CAN3-"
372
+ elsif input.start_with?("CSA ")
373
+ "CSA"
374
+ end
375
+
376
+ # Detect year format before normalization
377
+ # CAN/CSA- standards use dash format: CAN/CSA-C22.2-05
378
+ # Modern CSA standards use colon format: CSA B149:20
379
+ has_dash_year = input.match?(/-\d{2}\b/)
380
+
381
+ # Normalize CAN/CSA- and CAN3- to CSA (global replacement for combined identifiers)
382
+ normalized = input.gsub("CAN/CSA-", "CSA ")
383
+ # Normalize CAN3- to CSA (historical prefix)
384
+ normalized = normalized.gsub("CAN3-", "CSA ")
385
+
386
+ tree = Parser.new.parse(normalized)
387
+ result = Builder.new.build(tree)
388
+
389
+ # Set publisher prefix if detected
390
+ if result && publisher_prefix
391
+ set_publisher_prefix(result, publisher_prefix)
392
+ end
393
+
394
+ # Set year format if detected as dash and not already set
395
+ if result && has_dash_year && result.year_format.nil?
396
+ result.year_format = "dash"
397
+ end
398
+
399
+ result
400
+ rescue Parslet::ParseFailed => e
401
+ raise e
402
+ end
403
+
404
+ def self.set_publisher_prefix(obj, prefix)
405
+ # Set on main object if it has the attribute
406
+ if obj.class.attributes.key?(:publisher_prefix)
407
+ obj.publisher_prefix = prefix
408
+ end
409
+
410
+ # Set on combined identifier parts
411
+ if obj.is_a?(Identifiers::Combined)
412
+ if obj.first&.class&.attributes&.key?(:publisher_prefix)
413
+ obj.first.publisher_prefix = prefix
414
+ end
415
+ if obj.second && obj.second.class.attributes.key?(:has_publisher) && obj.second.has_publisher && obj.second.class.attributes.key?(:publisher_prefix)
416
+ obj.second.publisher_prefix = prefix
417
+ end
418
+ if obj.third && obj.third.class.attributes.key?(:has_publisher) && obj.third.has_publisher && obj.third.class.attributes.key?(:publisher_prefix)
419
+ obj.third.publisher_prefix = prefix
420
+ end
421
+ end
422
+
423
+ # Set on bundled identifier base
424
+ if obj.is_a?(Identifiers::Bundled) && obj.base
425
+ set_publisher_prefix(obj.base, prefix)
426
+ end
427
+ end
428
+
429
+ def self.parse_external_standard(input)
430
+ # Ensure full Pubid is loaded (handles Scheme and all flavors)
431
+ require_relative "../../pubid" unless defined?(Pubid::Iso) && defined?(Pubid::Iec)
432
+
433
+ # Try ISO/IEC first (most common)
434
+ if input.match?(/^(ISO\/IEC|ISO|IEC|CEI|CEI\/IEC)\s/)
435
+ begin
436
+ # Normalize CEI/IEC to IEC for parsing (CEI is French for IEC)
437
+ normalized_input = input.sub(/^CEI\/IEC/, "IEC")
438
+ return Pubid::Iso.parse(normalized_input)
439
+ rescue StandardError
440
+ return nil
441
+ end
442
+ end
443
+
444
+ # Try CISPR (uses IEC parser)
445
+ if input.match?(/^CISPR\s/)
446
+ begin
447
+ return Pubid::Iec.parse(input)
448
+ rescue StandardError
449
+ return nil
450
+ end
451
+ end
452
+
453
+ nil
454
+ end
455
+ end
456
+ end
457
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Csa
5
+ module Identifiers
6
+ class Base < SingleIdentifier
7
+ def to_s
8
+ prefix = publisher_prefix || "CSA"
9
+
10
+ # Handle code_only identifiers (empty string means no prefix)
11
+ if prefix == ""
12
+ # No prefix for code_only identifiers
13
+ parts = []
14
+ else
15
+ # Determine if we need space after prefix
16
+ # CAN/CSA- and CAN3- end with dash, so no space needed
17
+ needs_space = !prefix.end_with?("-")
18
+
19
+ parts = []
20
+ parts << prefix
21
+ end
22
+
23
+ # Code and year together
24
+ code_part = code.to_s if code
25
+
26
+ # NO. keyword
27
+ if no_number
28
+ code_part += " NO. #{no_number}"
29
+ end
30
+
31
+ # Series prefix and keyword (before year)
32
+ if series_prefix
33
+ code_part += " #{series_prefix} SERIES"
34
+ elsif series
35
+ # SERIES without prefix
36
+ code_part += " SERIES"
37
+ end
38
+
39
+ parts << code_part if code_part
40
+
41
+ # Year with proper format (colon or dash)
42
+ if year
43
+ # Use dash if year_format is dash, otherwise colon
44
+ separator = year_format == "dash" ? "-" : ":"
45
+ year_part = separator
46
+ year_part += year_prefix if year_prefix # Add M or F prefix
47
+ year_part += "F" if french && year_format != "dash" && !year_prefix # Only add F if no prefix
48
+ # Convert 4-digit year back to 2-digit for M/F prefix preservation
49
+ # M1983 → M83, F1983 → F83, 1983 → 83, 20xx → xx
50
+ # However, preserve original 4-digit format if the input was 4-digit (original_year_4digit)
51
+ year_str = year.to_s
52
+ year_part += if original_year_4digit
53
+ # Preserve 4-digit format (e.g., "M1981" stays "M1981")
54
+ year_str
55
+ elsif year_prefix&.match?(/^[MF]$/) && year_str.length == 4 && year_str.start_with?("19")
56
+ # M/F + 4-digit year (1900s) → convert to 2-digit with prefix
57
+ year_str[2..3]
58
+ elsif year_str.length == 4 && year_str.start_with?("20")
59
+ # 2000s → just last 2 digits
60
+ year_str[2..3]
61
+ elsif year_str.length == 4 && year_str.start_with?("19") && !original_year_4digit
62
+ # 1900s with no M/F prefix, but original was 2-digit (e.g., CAN3-Z299.0-86)
63
+ # Convert back to 2-digit
64
+ year_str[2..3]
65
+ else
66
+ # Other formats - keep as-is
67
+ year_str
68
+ end
69
+ parts[-1] += year_part
70
+ end
71
+
72
+ result = if prefix == ""
73
+ # No prefix, just join parts
74
+ parts.join(" ")
75
+ elsif needs_space
76
+ parts.join(" ")
77
+ elsif parts.length == 2
78
+ # No space after dash-ending prefix - join first two parts directly
79
+ # If there are more parts after code, they should still have spaces
80
+ parts.join
81
+ else
82
+ # More than 2 parts shouldn't happen in current design
83
+ parts.join
84
+ end
85
+
86
+ # Reaffirmation - preserve original format and determine spacing
87
+ if reaffirmation
88
+ # Check if year was originally 2-digit (original_year_4digit flag)
89
+ year_was_2digit = !original_year_4digit
90
+
91
+ # Check if reaffirmation was originally 4-digit (original_reaffirmation_4digit flag)
92
+ reaffirmation_was_4digit = original_reaffirmation_4digit
93
+
94
+ # Preserve original reaffirmation format
95
+ # If original was 4-digit, keep as 4-digit
96
+ # If original was 2-digit, convert from 4-digit storage back to 2-digit
97
+ reaffirmation_str = if reaffirmation_was_4digit
98
+ # Original was 4-digit, keep as-is
99
+ reaffirmation.to_s
100
+ elsif reaffirmation.to_s.length == 4 && reaffirmation.to_s.start_with?(
101
+ "19", "20"
102
+ )
103
+ # Original was 2-digit, convert 4-digit storage back to 2-digit
104
+ # (R2004) → (R04), (R1994) → (R94)
105
+ reaffirmation.to_s[2..3]
106
+ else
107
+ # Already 2-digit or other format
108
+ reaffirmation.to_s
109
+ end
110
+
111
+ # Determine spacing based on original formats
112
+ # Space needed if year is 2-digit and reaffirmation is 4-digit (original format)
113
+ # No space if both year and reaffirmation are 2-digit, or both are 4-digit
114
+ if year_was_2digit && reaffirmation_was_4digit
115
+ # Year was 2-digit, reaffirmation was 4-digit → add space
116
+ result += " (R#{reaffirmation_str})"
117
+ else
118
+ # Both 2-digit, both 4-digit, or other cases → no space
119
+ result += "(R#{reaffirmation_str})"
120
+ end
121
+ end
122
+
123
+ # Package (already has leading space from parser)
124
+ if package
125
+ result += package
126
+ end
127
+
128
+ result
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end