pubid 2.0.0.pre.alpha.2 → 2.0.0.pre.alpha.3

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 (458) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -39
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -43
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -51
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -39
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifier.rb +0 -46
  55. data/lib/pubid/asme/identifiers/base.rb +0 -60
  56. data/lib/pubid/asme/renderer.rb +66 -0
  57. data/lib/pubid/asme/urn_parser.rb +31 -0
  58. data/lib/pubid/asme.rb +42 -1
  59. data/lib/pubid/astm/components/code.rb +9 -0
  60. data/lib/pubid/{jis → astm}/components.rb +1 -1
  61. data/lib/pubid/astm/identifier.rb +0 -77
  62. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  63. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  64. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  65. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  66. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  67. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  68. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  69. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  70. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  71. data/lib/pubid/astm/identifiers.rb +18 -0
  72. data/lib/pubid/astm/renderer.rb +172 -0
  73. data/lib/pubid/astm/single_identifier.rb +0 -10
  74. data/lib/pubid/astm/urn_parser.rb +30 -0
  75. data/lib/pubid/astm.rb +39 -27
  76. data/lib/pubid/bsi/builder.rb +21 -12
  77. data/lib/pubid/bsi/identifier.rb +8 -62
  78. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  79. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  80. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  81. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  82. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  84. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  87. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  88. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  89. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  90. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  91. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  92. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  93. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  94. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  95. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  96. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  97. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  98. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  99. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  100. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  101. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  102. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  103. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  104. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  105. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  106. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  107. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  108. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  109. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  110. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  111. data/lib/pubid/bsi/identifiers.rb +0 -1
  112. data/lib/pubid/bsi/renderer.rb +1050 -0
  113. data/lib/pubid/bsi/single_identifier.rb +6 -70
  114. data/lib/pubid/bsi/urn_generator.rb +2 -3
  115. data/lib/pubid/bsi/urn_parser.rb +52 -0
  116. data/lib/pubid/bsi.rb +224 -1
  117. data/lib/pubid/builder/base.rb +57 -10
  118. data/lib/pubid/bundled_identifier.rb +0 -1
  119. data/lib/pubid/ccsds/builder.rb +4 -3
  120. data/lib/pubid/ccsds/identifier.rb +63 -66
  121. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  122. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  123. data/lib/pubid/ccsds/parser.rb +4 -2
  124. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  125. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  126. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  127. data/lib/pubid/ccsds.rb +39 -1
  128. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  129. data/lib/pubid/cen_cenelec/identifier.rb +7 -38
  130. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  131. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  132. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  133. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  135. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  136. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  137. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  139. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  140. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  141. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  143. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  145. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  146. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  147. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  148. data/lib/pubid/cen_cenelec.rb +168 -1
  149. data/lib/pubid/cie/components/code.rb +8 -0
  150. data/lib/pubid/cie/identifier.rb +6 -57
  151. data/lib/pubid/cie/urn_parser.rb +28 -0
  152. data/lib/pubid/cie.rb +43 -1
  153. data/lib/pubid/components/adoption.rb +104 -0
  154. data/lib/pubid/components/code.rb +22 -8
  155. data/lib/pubid/components/date.rb +23 -16
  156. data/lib/pubid/components/edition.rb +9 -6
  157. data/lib/pubid/components/iteration.rb +32 -0
  158. data/lib/pubid/components/language.rb +6 -4
  159. data/lib/pubid/components/locality.rb +10 -1
  160. data/lib/pubid/components/publisher.rb +9 -6
  161. data/lib/pubid/components/relationship.rb +151 -0
  162. data/lib/pubid/components/stage.rb +5 -14
  163. data/lib/pubid/components/supplement.rb +184 -0
  164. data/lib/pubid/components/type.rb +5 -15
  165. data/lib/pubid/components/typed_stage.rb +10 -11
  166. data/lib/pubid/components.rb +4 -1
  167. data/lib/pubid/core/update_codes.rb +28 -7
  168. data/lib/pubid/csa/identifier.rb +0 -59
  169. data/lib/pubid/csa/identifiers/base.rb +2 -122
  170. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  171. data/lib/pubid/csa/identifiers/series.rb +2 -102
  172. data/lib/pubid/csa/renderer.rb +292 -0
  173. data/lib/pubid/csa/urn_generator.rb +1 -1
  174. data/lib/pubid/csa/urn_parser.rb +33 -0
  175. data/lib/pubid/csa.rb +42 -1
  176. data/lib/pubid/etsi/components/code.rb +9 -2
  177. data/lib/pubid/etsi/identifier.rb +0 -43
  178. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  179. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  180. data/lib/pubid/etsi/renderer.rb +42 -0
  181. data/lib/pubid/etsi/urn_parser.rb +34 -0
  182. data/lib/pubid/etsi.rb +42 -1
  183. data/lib/pubid/export/exporter.rb +4 -46
  184. data/lib/pubid/export/flavor_exporter.rb +111 -278
  185. data/lib/pubid/export.rb +0 -6
  186. data/lib/pubid/identifier.rb +2 -17
  187. data/lib/pubid/identifier_facade.rb +114 -0
  188. data/lib/pubid/identifier_metadata.rb +1 -1
  189. data/lib/pubid/idf/builder.rb +3 -3
  190. data/lib/pubid/idf/identifier.rb +3 -66
  191. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  192. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  193. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  194. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  195. data/lib/pubid/idf/parser.rb +3 -2
  196. data/lib/pubid/idf/renderer.rb +84 -0
  197. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  198. data/lib/pubid/idf/urn_generator.rb +4 -39
  199. data/lib/pubid/idf/urn_parser.rb +25 -0
  200. data/lib/pubid/idf.rb +51 -1
  201. data/lib/pubid/iec/builder.rb +46 -64
  202. data/lib/pubid/iec/components/code.rb +8 -32
  203. data/lib/pubid/iec/components/publisher.rb +0 -1
  204. data/lib/pubid/iec/components.rb +14 -0
  205. data/lib/pubid/iec/identifier.rb +251 -213
  206. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  207. data/lib/pubid/iec/identifiers/base.rb +8 -32
  208. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  209. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  210. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -26
  211. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  212. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -22
  213. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  214. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  215. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  216. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  217. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  218. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -11
  219. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  220. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  222. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  223. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  224. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  225. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -19
  226. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  227. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  228. data/lib/pubid/iec/identifiers.rb +30 -0
  229. data/lib/pubid/iec/parser.rb +13 -12
  230. data/lib/pubid/iec/renderer.rb +254 -0
  231. data/lib/pubid/iec/single_identifier.rb +6 -12
  232. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  233. data/lib/pubid/iec/urn_generator.rb +3 -3
  234. data/lib/pubid/iec/urn_parser.rb +3 -3
  235. data/lib/pubid/iec.rb +40 -68
  236. data/lib/pubid/ieee/builder.rb +12 -12
  237. data/lib/pubid/ieee/components/code.rb +8 -0
  238. data/lib/pubid/ieee/components/draft.rb +14 -0
  239. data/lib/pubid/ieee/components/relationship.rb +5 -149
  240. data/lib/pubid/ieee/identifier.rb +6 -41
  241. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  242. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  243. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  245. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  246. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  247. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  248. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  249. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  250. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  251. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  256. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  257. data/lib/pubid/ieee/pre_parser.rb +301 -0
  258. data/lib/pubid/ieee/renderer.rb +307 -0
  259. data/lib/pubid/ieee/urn_parser.rb +34 -0
  260. data/lib/pubid/ieee.rb +62 -1
  261. data/lib/pubid/ieee_debug.rb +0 -1
  262. data/lib/pubid/iho/builder.rb +2 -2
  263. data/lib/pubid/iho/identifier.rb +8 -42
  264. data/lib/pubid/iho/identifiers/base.rb +49 -10
  265. data/lib/pubid/iho/parser.rb +3 -3
  266. data/lib/pubid/iho/renderer.rb +30 -0
  267. data/lib/pubid/iho/urn_generator.rb +2 -2
  268. data/lib/pubid/iho/urn_parser.rb +58 -0
  269. data/lib/pubid/iho.rb +50 -1
  270. data/lib/pubid/iso/builder.rb +55 -53
  271. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  272. data/lib/pubid/iso/components/code.rb +7 -19
  273. data/lib/pubid/iso/components/publisher.rb +10 -8
  274. data/lib/pubid/iso/components.rb +2 -4
  275. data/lib/pubid/iso/identifier.rb +218 -252
  276. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  277. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  278. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  279. data/lib/pubid/iso/identifiers/data.rb +0 -1
  280. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  281. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  282. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  283. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  284. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  285. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  286. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  287. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  288. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  289. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  290. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  291. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  292. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  293. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  294. data/lib/pubid/iso/identifiers.rb +0 -1
  295. data/lib/pubid/iso/normalizer.rb +89 -0
  296. data/lib/pubid/iso/parser.rb +22 -4
  297. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  298. data/lib/pubid/iso/urn_generator.rb +66 -182
  299. data/lib/pubid/iso/urn_parser.rb +12 -7
  300. data/lib/pubid/iso.rb +173 -2
  301. data/lib/pubid/itu/builder.rb +0 -12
  302. data/lib/pubid/itu/components/code.rb +8 -0
  303. data/lib/pubid/itu/components.rb +11 -0
  304. data/lib/pubid/itu/identifier.rb +6 -104
  305. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  306. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  307. data/lib/pubid/itu/identifiers/base.rb +0 -6
  308. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  309. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  310. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  311. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  312. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  313. data/lib/pubid/itu/urn_parser.rb +23 -0
  314. data/lib/pubid/itu.rb +42 -1
  315. data/lib/pubid/jcgm/builder.rb +16 -8
  316. data/lib/pubid/jcgm/identifier.rb +0 -43
  317. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  318. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  319. data/lib/pubid/jcgm/renderer.rb +68 -0
  320. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  321. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  322. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  323. data/lib/pubid/jcgm.rb +43 -2
  324. data/lib/pubid/jis/builder.rb +44 -52
  325. data/lib/pubid/jis/identifier.rb +132 -46
  326. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  327. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  328. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  329. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  330. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  331. data/lib/pubid/jis/identifiers.rb +1 -1
  332. data/lib/pubid/jis/parser.rb +31 -5
  333. data/lib/pubid/jis/renderer.rb +69 -0
  334. data/lib/pubid/jis/single_identifier.rb +6 -12
  335. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  336. data/lib/pubid/jis/urn_parser.rb +23 -0
  337. data/lib/pubid/jis.rb +42 -2
  338. data/lib/pubid/nist/builder.rb +63 -1871
  339. data/lib/pubid/nist/caster.rb +1272 -0
  340. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  341. data/lib/pubid/nist/components/code.rb +9 -20
  342. data/lib/pubid/nist/components/supplement.rb +2 -2
  343. data/lib/pubid/nist/components.rb +0 -1
  344. data/lib/pubid/nist/identifier.rb +11 -48
  345. data/lib/pubid/nist/identifiers/base.rb +110 -47
  346. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  347. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  348. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  349. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  350. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  351. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  352. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  353. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  354. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  355. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  356. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  357. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  358. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  359. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  360. data/lib/pubid/nist/identifiers/report.rb +4 -2
  361. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  362. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  363. data/lib/pubid/nist/identifiers.rb +1 -0
  364. data/lib/pubid/nist/parser.rb +62 -452
  365. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  366. data/lib/pubid/nist/preprocessor.rb +416 -0
  367. data/lib/pubid/nist/renderer.rb +43 -0
  368. data/lib/pubid/nist/router.rb +148 -0
  369. data/lib/pubid/nist/series/base.rb +58 -0
  370. data/lib/pubid/nist/series/crpl.rb +13 -0
  371. data/lib/pubid/nist/series/fips.rb +14 -0
  372. data/lib/pubid/nist/series/ir.rb +60 -0
  373. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  374. data/lib/pubid/nist/series/mono.rb +19 -0
  375. data/lib/pubid/nist/series/ncstar.rb +20 -0
  376. data/lib/pubid/nist/series.rb +49 -0
  377. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  378. data/lib/pubid/nist/urn_parser.rb +67 -0
  379. data/lib/pubid/nist.rb +82 -4
  380. data/lib/pubid/oiml/components/code.rb +10 -0
  381. data/lib/pubid/oiml/identifier.rb +0 -50
  382. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  383. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  384. data/lib/pubid/oiml/renderer.rb +161 -0
  385. data/lib/pubid/oiml/single_identifier.rb +6 -45
  386. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  387. data/lib/pubid/oiml/urn_generator.rb +0 -8
  388. data/lib/pubid/oiml/urn_parser.rb +22 -0
  389. data/lib/pubid/oiml.rb +42 -1
  390. data/lib/pubid/plateau/identifier.rb +7 -41
  391. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  392. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  393. data/lib/pubid/plateau/renderer.rb +51 -0
  394. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  395. data/lib/pubid/plateau/urn_parser.rb +43 -0
  396. data/lib/pubid/plateau.rb +43 -1
  397. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  398. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  399. data/lib/pubid/renderers/human_readable.rb +18 -7
  400. data/lib/pubid/rendering/context.rb +28 -19
  401. data/lib/pubid/rendering.rb +0 -3
  402. data/lib/pubid/sae/components/date.rb +8 -0
  403. data/lib/pubid/sae/components/type.rb +5 -1
  404. data/lib/pubid/sae/identifier.rb +0 -23
  405. data/lib/pubid/sae/identifiers/base.rb +2 -16
  406. data/lib/pubid/sae/renderer.rb +36 -0
  407. data/lib/pubid/sae/urn_generator.rb +2 -10
  408. data/lib/pubid/sae/urn_parser.rb +36 -0
  409. data/lib/pubid/sae.rb +42 -1
  410. data/lib/pubid/urn_generator/base.rb +12 -12
  411. data/lib/pubid/urn_parser/base.rb +81 -0
  412. data/lib/pubid/urn_parser/errors.rb +9 -0
  413. data/lib/pubid/urn_parser.rb +14 -0
  414. data/lib/pubid/version.rb +1 -1
  415. data/lib/pubid.rb +29 -7
  416. data/lib/tasks/website-data.json +1940 -1882
  417. metadata +75 -44
  418. data/lib/pubid/amca/scheme.rb +0 -16
  419. data/lib/pubid/ansi/scheme.rb +0 -15
  420. data/lib/pubid/api/scheme.rb +0 -66
  421. data/lib/pubid/ashrae/scheme.rb +0 -53
  422. data/lib/pubid/asme/scheme.rb +0 -37
  423. data/lib/pubid/astm/scheme.rb +0 -55
  424. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  425. data/lib/pubid/bsi/scheme.rb +0 -243
  426. data/lib/pubid/ccsds/scheme.rb +0 -57
  427. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  428. data/lib/pubid/cie/scheme.rb +0 -64
  429. data/lib/pubid/components/factory.rb +0 -50
  430. data/lib/pubid/csa/scheme.rb +0 -44
  431. data/lib/pubid/etsi/scheme.rb +0 -42
  432. data/lib/pubid/export/data_class_exporter.rb +0 -59
  433. data/lib/pubid/export/ieee_exporter.rb +0 -78
  434. data/lib/pubid/export/itu_exporter.rb +0 -66
  435. data/lib/pubid/export/nist_exporter.rb +0 -64
  436. data/lib/pubid/export/registry_exporter.rb +0 -90
  437. data/lib/pubid/export/scheme_exporter.rb +0 -70
  438. data/lib/pubid/identifier_registry.rb +0 -198
  439. data/lib/pubid/idf/scheme.rb +0 -61
  440. data/lib/pubid/iec/scheme.rb +0 -71
  441. data/lib/pubid/ieee/scheme.rb +0 -90
  442. data/lib/pubid/iho/scheme.rb +0 -29
  443. data/lib/pubid/iso/identifiers/base.rb +0 -115
  444. data/lib/pubid/iso/scheme.rb +0 -193
  445. data/lib/pubid/itu/scheme.rb +0 -174
  446. data/lib/pubid/jcgm/scheme.rb +0 -60
  447. data/lib/pubid/jis/components/code.rb +0 -59
  448. data/lib/pubid/jis/identifiers/base.rb +0 -72
  449. data/lib/pubid/jis/scheme.rb +0 -49
  450. data/lib/pubid/nist/components/publisher.rb +0 -24
  451. data/lib/pubid/nist/scheme.rb +0 -199
  452. data/lib/pubid/oiml/scheme.rb +0 -46
  453. data/lib/pubid/plateau/scheme.rb +0 -45
  454. data/lib/pubid/rendering/base.rb +0 -73
  455. data/lib/pubid/rendering/common.rb +0 -211
  456. data/lib/pubid/rendering/format.rb +0 -25
  457. data/lib/pubid/sae/scheme.rb +0 -47
  458. data/lib/pubid/scheme.rb +0 -219
@@ -4,128 +4,8 @@ module Pubid
4
4
  module Csa
5
5
  module Identifiers
6
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
7
+ def to_s(**opts)
8
+ render(format: :human, **opts)
129
9
  end
130
10
  end
131
11
  end
@@ -21,107 +21,8 @@ module Pubid
21
21
  @code ||= Components::Code.new(value: "#{cec_part.value}-#{no_number.value}")
22
22
  end
23
23
 
24
- def to_s
25
- parts = []
26
-
27
- # Publisher prefix (CSA, CAN/CSA-, CAN3-)
28
- prefix = publisher_prefix || "CSA"
29
-
30
- # Determine if we need space after prefix
31
- # CAN/CSA- and CAN3- end with dash, so no space needed
32
- needs_space = !prefix.end_with?("-")
33
-
34
- parts << prefix unless prefix == ""
35
-
36
- # CEC Part (C22.2, C22.3, etc.)
37
- parts << cec_part.value if cec_part
38
-
39
- # NO. notation - this is the key semantic component
40
- parts << "NO."
41
-
42
- # Number after NO.
43
- parts << no_number.value if no_number
44
-
45
- # Determine separator based on prefix ending
46
- result = if prefix == ""
47
- parts.join(" ")
48
- elsif needs_space
49
- parts.join(" ")
50
- elsif parts.length <= 2
51
- # No space after dash-ending prefix (CAN/CSA-, CAN3-)
52
- # Join first two parts directly, rest with spaces
53
- parts.join
54
- else
55
- parts[0] + parts[1..].join(" ")
56
- end
57
-
58
- # Year with proper format (colon or dash)
59
- if year
60
- # Use dash if year_format is dash, otherwise colon
61
- separator = year_format == "dash" ? "-" : ":"
62
- year_part = separator
63
-
64
- # Convert 4-digit year back to 2-digit for display
65
- year_str = year.to_s
66
- display_year = if year_str.length == 4 && year_str.start_with?("20")
67
- year_str[2..3]
68
- elsif year_str.length == 4 && year_str.start_with?("19")
69
- year_str[2..3]
70
- else
71
- year_str
72
- end
73
-
74
- # Add prefix if present
75
- year_part += if year_prefix
76
- year_prefix + display_year
77
- elsif french && year_format != "dash"
78
- # Only add F if no prefix already set
79
- "F#{display_year}"
80
- else
81
- display_year
82
- end
83
-
84
- result += year_part
85
- end
86
-
87
- # Reaffirmation - preserve original format and determine spacing
88
- if reaffirmation
89
- # Check if year was originally 2-digit (original_year_4digit flag)
90
- year_was_2digit = !original_year_4digit
91
-
92
- # Check if reaffirmation was originally 4-digit (original_reaffirmation_4digit flag)
93
- reaffirmation_was_4digit = original_reaffirmation_4digit
94
-
95
- # Preserve original reaffirmation format
96
- # If original was 4-digit, keep as 4-digit
97
- # If original was 2-digit, convert from 4-digit storage back to 2-digit
98
- reaffirmation_str = if reaffirmation_was_4digit
99
- # Original was 4-digit, keep as-is
100
- reaffirmation.to_s
101
- elsif reaffirmation.to_s.length == 4 && reaffirmation.to_s.start_with?(
102
- "19", "20"
103
- )
104
- # Original was 2-digit, convert 4-digit storage back to 2-digit
105
- # (R2004) → (R04), (R1994) → (R94)
106
- reaffirmation.to_s[2..3]
107
- else
108
- # Already 2-digit or other format
109
- reaffirmation.to_s
110
- end
111
-
112
- # Determine spacing based on original formats
113
- # Space needed if year is 2-digit and reaffirmation is 4-digit (original format)
114
- # No space if both year and reaffirmation are 2-digit, or both are 4-digit
115
- if year_was_2digit && reaffirmation_was_4digit
116
- # Year was 2-digit, reaffirmation was 4-digit → add space
117
- result += " (R#{reaffirmation_str})"
118
- else
119
- # Both 2-digit, both 4-digit, or other cases → no space
120
- result += "(R#{reaffirmation_str})"
121
- end
122
- end
123
-
124
- result
24
+ def to_s(**opts)
25
+ render(format: :human, **opts)
125
26
  end
126
27
  end
127
28
  end
@@ -18,108 +18,8 @@ module Pubid
18
18
  # Series prefix (MH, RV, etc.) - optional
19
19
  attribute :series_prefix, :string
20
20
 
21
- def to_s
22
- result = publisher_prefix_portion
23
-
24
- # Add code FIRST (before SERIES keyword)
25
- result += code.to_s
26
-
27
- # Add space before series prefix/SERIES keyword
28
- result += " "
29
-
30
- # Add series prefix if present
31
- result += "#{series_prefix} " if series_prefix && !series_prefix.empty?
32
-
33
- # Add SERIES keyword
34
- result += "SERIES"
35
-
36
- # Add year
37
- result += year_portion
38
-
39
- # Add language
40
- result += language_portion
41
-
42
- # Add reaffirmation
43
- result += reaffirmation_portion
44
-
45
- result
46
- end
47
-
48
- private
49
-
50
- def publisher_prefix_portion
51
- prefix = publisher_prefix || "CSA"
52
-
53
- # Handle code_only identifiers (empty string means no prefix)
54
- return "" if prefix == ""
55
-
56
- # Determine if we need space after prefix
57
- # CAN/CSA- and CAN3- end with dash, so no space needed
58
- needs_space = !prefix.end_with?("-")
59
-
60
- needs_space ? "#{prefix} " : prefix
61
- end
62
-
63
- def year_portion
64
- return "" unless year
65
-
66
- # Use dash if year_format is dash, otherwise colon
67
- separator = year_format == "dash" ? "-" : ":"
68
- year_part = separator
69
- year_part += year_prefix if year_prefix # Add M or F prefix
70
- year_part += "F" if french && year_format != "dash" && !year_prefix # Only add F if no prefix
71
-
72
- # Convert 4-digit year back to 2-digit
73
- year_str = year.to_s
74
- year_part += if year_str.length == 4 && year_str.start_with?("20")
75
- year_str[2..3]
76
- else
77
- year_str
78
- end
79
-
80
- year_part
81
- end
82
-
83
- def language_portion
84
- "" # CSA doesn't use language codes in rendering
85
- end
86
-
87
- def reaffirmation_portion
88
- return "" unless reaffirmation
89
-
90
- # Check if year was originally 2-digit (original_year_4digit flag)
91
- year_was_2digit = !original_year_4digit
92
-
93
- # Check if reaffirmation was originally 4-digit (original_reaffirmation_4digit flag)
94
- reaffirmation_was_4digit = original_reaffirmation_4digit
95
-
96
- # Preserve original reaffirmation format
97
- # If original was 4-digit, keep as 4-digit
98
- # If original was 2-digit, convert from 4-digit storage back to 2-digit
99
- reaffirmation_str = if reaffirmation_was_4digit
100
- # Original was 4-digit, keep as-is
101
- reaffirmation.to_s
102
- elsif reaffirmation.to_s.length == 4 && reaffirmation.to_s.start_with?(
103
- "19", "20"
104
- )
105
- # Original was 2-digit, convert 4-digit storage back to 2-digit
106
- # (R2004) → (R04), (R1994) → (R94)
107
- reaffirmation.to_s[2..3]
108
- else
109
- # Already 2-digit or other format
110
- reaffirmation.to_s
111
- end
112
-
113
- # Determine spacing based on original formats
114
- # Space needed if year is 2-digit and reaffirmation is 4-digit (original format)
115
- # No space if both year and reaffirmation are 2-digit, or both are 4-digit
116
- if year_was_2digit && reaffirmation_was_4digit
117
- # Year was 2-digit, reaffirmation was 4-digit → add space
118
- " (R#{reaffirmation_str})"
119
- else
120
- # Both 2-digit, both 4-digit, or other cases → no space
121
- "(R#{reaffirmation_str})"
122
- end
21
+ def to_s(**opts)
22
+ render(format: :human, **opts)
123
23
  end
124
24
  end
125
25
  end
@@ -0,0 +1,292 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Csa
5
+ # Human-readable renderer for CSA identifiers that extend Pubid::Identifier.
6
+ #
7
+ # Produces strings like:
8
+ # "CSA B149.1:20"
9
+ # "CAN/CSA-C22.2 NO. 60601-1-9:15"
10
+ # "CSA C22.2 NO. 286:23"
11
+ # "CSA MH SERIES 3.14:20"
12
+ #
13
+ # The renderer is registered as the +:human+ format in the CSA format
14
+ # registry and invoked via +render(format: :human)+.
15
+ #
16
+ # Note: Some CSA identifier types (Bundled, Combined, CanadianAdopted,
17
+ # CsaAdopted, Package) extend Lutaml::Model::Serializable directly,
18
+ # not Pubid::Identifier, so they keep their own to_s implementations.
19
+ class Renderer < ::Pubid::Renderers::Base
20
+ def render(context: nil, **_opts)
21
+ id = @id
22
+ @context = context
23
+
24
+ case id
25
+ when Identifiers::Series
26
+ render_series(id)
27
+ when Identifiers::Cec
28
+ render_cec(id)
29
+ else
30
+ render_base(id)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # Base rendering: "CSA B149.1:20", "CAN/CSA-C22.2-05"
37
+ def render_base(id)
38
+ prefix = id.publisher_prefix || "CSA"
39
+
40
+ # Handle code_only identifiers (empty string means no prefix)
41
+ if prefix == ""
42
+ # No prefix for code_only identifiers
43
+ parts = []
44
+ else
45
+ # Determine if we need space after prefix
46
+ # CAN/CSA- and CAN3- end with dash, so no space needed
47
+ needs_space = !prefix.end_with?("-")
48
+
49
+ parts = []
50
+ parts << prefix
51
+ end
52
+
53
+ # Code and year together
54
+ code_part = id.code.to_s if id.code
55
+
56
+ # NO. keyword
57
+ if id.no_number
58
+ code_part += " NO. #{id.no_number}"
59
+ end
60
+
61
+ # Series prefix and keyword (before year)
62
+ if id.series_prefix
63
+ code_part += " #{id.series_prefix} SERIES"
64
+ elsif id.series
65
+ # SERIES without prefix
66
+ code_part += " SERIES"
67
+ end
68
+
69
+ parts << code_part if code_part
70
+
71
+ # Year with proper format (colon or dash)
72
+ if id.year
73
+ # Use dash if year_format is dash, otherwise colon
74
+ separator = id.year_format == "dash" ? "-" : ":"
75
+ year_part = separator
76
+ year_part += id.year_prefix if id.year_prefix # Add M or F prefix
77
+ year_part += "F" if id.french && id.year_format != "dash" && !id.year_prefix # Only add F if no prefix
78
+ # Convert 4-digit year back to 2-digit for M/F prefix preservation
79
+ # M1983 → M83, F1983 → F83, 1983 → 83, 20xx → xx
80
+ # However, preserve original 4-digit format if the input was 4-digit (original_year_4digit)
81
+ year_str = id.year.to_s
82
+ year_part += if id.original_year_4digit
83
+ # Preserve 4-digit format (e.g., "M1981" stays "M1981")
84
+ year_str
85
+ elsif id.year_prefix&.match?(/^[MF]$/) && year_str.length == 4 && year_str.start_with?("19")
86
+ # M/F + 4-digit year (1900s) → convert to 2-digit with prefix
87
+ year_str[2..3]
88
+ elsif year_str.length == 4 && year_str.start_with?("20")
89
+ # 2000s → just last 2 digits
90
+ year_str[2..3]
91
+ elsif year_str.length == 4 && year_str.start_with?("19") && !id.original_year_4digit
92
+ # 1900s with no M/F prefix, but original was 2-digit (e.g., CAN3-Z299.0-86)
93
+ # Convert back to 2-digit
94
+ year_str[2..3]
95
+ else
96
+ # Other formats - keep as-is
97
+ year_str
98
+ end
99
+ parts[-1] += year_part
100
+ end
101
+
102
+ result = if prefix == ""
103
+ # No prefix, just join parts
104
+ parts.join(" ")
105
+ elsif !prefix.end_with?("-")
106
+ parts.join(" ")
107
+ elsif parts.length == 2
108
+ # No space after dash-ending prefix - join first two parts directly
109
+ # If there are more parts after code, they should still have spaces
110
+ parts.join
111
+ else
112
+ # More than 2 parts shouldn't happen in current design
113
+ parts.join
114
+ end
115
+
116
+ # Reaffirmation - preserve original format and determine spacing
117
+ if id.reaffirmation && !id.reaffirmation.to_s.empty?
118
+ result += render_reaffirmation(id)
119
+ end
120
+
121
+ # Package (already has leading space from parser)
122
+ if id.package
123
+ result += id.package
124
+ end
125
+
126
+ result
127
+ end
128
+
129
+ # CEC rendering: "CSA C22.2 NO. 286:23"
130
+ def render_cec(id)
131
+ parts = []
132
+
133
+ # Publisher prefix (CSA, CAN/CSA-, CAN3-)
134
+ prefix = id.publisher_prefix || "CSA"
135
+
136
+ # Determine if we need space after prefix
137
+ # CAN/CSA- and CAN3- end with dash, so no space needed
138
+ needs_space = !prefix.end_with?("-")
139
+
140
+ parts << prefix unless prefix == ""
141
+
142
+ # CEC Part (C22.2, C22.3, etc.)
143
+ parts << id.cec_part.render(context: @context) if id.cec_part
144
+
145
+ # NO. notation - this is the key semantic component
146
+ parts << "NO."
147
+
148
+ # Number after NO.
149
+ parts << id.no_number.render(context: @context) if id.no_number
150
+
151
+ # Determine separator based on prefix ending
152
+ result = if prefix == ""
153
+ parts.join(" ")
154
+ elsif needs_space
155
+ parts.join(" ")
156
+ elsif parts.length <= 2
157
+ # No space after dash-ending prefix (CAN/CSA-, CAN3-)
158
+ # Join first two parts directly, rest with spaces
159
+ parts.join
160
+ else
161
+ parts[0] + parts[1..].join(" ")
162
+ end
163
+
164
+ # Year with proper format (colon or dash)
165
+ if id.year
166
+ # Use dash if year_format is dash, otherwise colon
167
+ separator = id.year_format == "dash" ? "-" : ":"
168
+ year_part = separator
169
+
170
+ # Convert 4-digit year back to 2-digit for display
171
+ year_str = id.year.to_s
172
+ display_year = if year_str.length == 4 && year_str.start_with?("20")
173
+ year_str[2..3]
174
+ elsif year_str.length == 4 && year_str.start_with?("19")
175
+ year_str[2..3]
176
+ else
177
+ year_str
178
+ end
179
+
180
+ # Add prefix if present
181
+ year_part += if id.year_prefix
182
+ id.year_prefix + display_year
183
+ elsif id.french && id.year_format != "dash"
184
+ # Only add F if no prefix already set
185
+ "F#{display_year}"
186
+ else
187
+ display_year
188
+ end
189
+
190
+ result += year_part
191
+ end
192
+
193
+ # Reaffirmation
194
+ if id.reaffirmation && !id.reaffirmation.to_s.empty?
195
+ result += render_reaffirmation(id)
196
+ end
197
+
198
+ result
199
+ end
200
+
201
+ # Series rendering: "CSA MH SERIES 3.14:20"
202
+ def render_series(id)
203
+ result = series_publisher_prefix_portion(id)
204
+
205
+ # Add code FIRST (before SERIES keyword)
206
+ result += id.code.to_s
207
+
208
+ # Add space before series prefix/SERIES keyword
209
+ result += " "
210
+
211
+ # Add series prefix if present
212
+ result += "#{id.series_prefix} " if id.series_prefix && !id.series_prefix.empty?
213
+
214
+ # Add SERIES keyword
215
+ result += "SERIES"
216
+
217
+ # Add year
218
+ result += series_year_portion(id)
219
+
220
+ # Add reaffirmation
221
+ result += render_reaffirmation(id) if id.reaffirmation && !id.reaffirmation.to_s.empty?
222
+
223
+ result
224
+ end
225
+
226
+ private
227
+
228
+ # Reaffirmation rendering helper - shared across Base, Cec, and Series
229
+ def render_reaffirmation(id)
230
+ # Check if year was originally 2-digit (original_year_4digit flag)
231
+ year_was_2digit = !id.original_year_4digit
232
+
233
+ # Check if reaffirmation was originally 4-digit (original_reaffirmation_4digit flag)
234
+ reaffirmation_was_4digit = id.original_reaffirmation_4digit
235
+
236
+ # Preserve original reaffirmation format
237
+ reaffirmation_str = if reaffirmation_was_4digit
238
+ # Original was 4-digit, keep as-is
239
+ id.reaffirmation.to_s
240
+ elsif id.reaffirmation.to_s.length == 4 && id.reaffirmation.to_s.start_with?("19", "20")
241
+ # Original was 2-digit, convert 4-digit storage back to 2-digit
242
+ id.reaffirmation.to_s[2..3]
243
+ else
244
+ # Already 2-digit or other format
245
+ id.reaffirmation.to_s
246
+ end
247
+
248
+ # Determine spacing based on original formats
249
+ if year_was_2digit && reaffirmation_was_4digit
250
+ # Year was 2-digit, reaffirmation was 4-digit → add space
251
+ " (R#{reaffirmation_str})"
252
+ else
253
+ # Both 2-digit, both 4-digit, or other cases → no space
254
+ "(R#{reaffirmation_str})"
255
+ end
256
+ end
257
+
258
+ def series_publisher_prefix_portion(id)
259
+ prefix = id.publisher_prefix || "CSA"
260
+
261
+ # Handle code_only identifiers (empty string means no prefix)
262
+ return "" if prefix == ""
263
+
264
+ # Determine if we need space after prefix
265
+ # CAN/CSA- and CAN3- end with dash, so no space needed
266
+ needs_space = !prefix.end_with?("-")
267
+
268
+ needs_space ? "#{prefix} " : prefix
269
+ end
270
+
271
+ def series_year_portion(id)
272
+ return "" unless id.year
273
+
274
+ # Use dash if year_format is dash, otherwise colon
275
+ separator = id.year_format == "dash" ? "-" : ":"
276
+ year_part = separator
277
+ year_part += id.year_prefix if id.year_prefix # Add M or F prefix
278
+ year_part += "F" if id.french && id.year_format != "dash" && !id.year_prefix # Only add F if no prefix
279
+
280
+ # Convert 4-digit year back to 2-digit
281
+ year_str = id.year.to_s
282
+ year_part += if year_str.length == 4 && year_str.start_with?("20")
283
+ year_str[2..3]
284
+ else
285
+ year_str
286
+ end
287
+
288
+ year_part
289
+ end
290
+ end
291
+ end
292
+ end
@@ -12,7 +12,7 @@ module Pubid
12
12
  def urn_number
13
13
  return nil unless identifier.code
14
14
 
15
- identifier.code.value.to_s
15
+ identifier.code.render(context: URN_CONTEXT)
16
16
  end
17
17
 
18
18
  def urn_no_number
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Csa
5
+ # Parses CSA URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:csa:{publisher}:{code}:{year}:format.{format}
9
+ #
10
+ # The trailing `format.X` token records the year-separator style used
11
+ # in the human-readable form (`dash` for `-`, `colon` for `:`).
12
+ #
13
+ # Examples:
14
+ # - urn:csa:csa:Z240.2.1:16:format.dash → CSA Z240.2.1-16
15
+ class UrnParser < Pubid::UrnParser::Base
16
+ YEAR_SEPARATOR = { "dash" => "-", "colon" => ":" }.freeze
17
+
18
+ def parse_urn(urn)
19
+ body = strip_namespace(urn)
20
+ parts = split_parts(body)
21
+
22
+ format_token = parts.find { |p| p.start_with?("format.") }
23
+ separator = YEAR_SEPARATOR.fetch(format_token&.split(".")&.last, "-")
24
+
25
+ payload = parts.reject { |p| p.start_with?("format.") }
26
+ _publisher, code, year = payload
27
+ text = "CSA #{code}"
28
+ text += "#{separator}#{year}" if year
29
+ flavor_parse(text)
30
+ end
31
+ end
32
+ end
33
+ end