pubid 2.0.0.pre.alpha.1 → 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 (463) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +27 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -0
  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 -1
  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 -4
  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 -0
  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/identifiers/base.rb +0 -60
  55. data/lib/pubid/asme/renderer.rb +66 -0
  56. data/lib/pubid/asme/urn_parser.rb +31 -0
  57. data/lib/pubid/asme.rb +42 -1
  58. data/lib/pubid/astm/components/code.rb +9 -0
  59. data/lib/pubid/{jis → astm}/components.rb +1 -1
  60. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  61. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  62. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  63. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  64. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  65. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  66. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  67. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  68. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  69. data/lib/pubid/astm/identifiers.rb +18 -0
  70. data/lib/pubid/astm/renderer.rb +172 -0
  71. data/lib/pubid/astm/single_identifier.rb +0 -10
  72. data/lib/pubid/astm/urn_parser.rb +30 -0
  73. data/lib/pubid/astm.rb +39 -27
  74. data/lib/pubid/bsi/builder.rb +21 -12
  75. data/lib/pubid/bsi/identifier.rb +8 -2
  76. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  77. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  78. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  79. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  80. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  81. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  82. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  83. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  84. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  85. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  87. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  88. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  89. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  90. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  91. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  92. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  93. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  94. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  95. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  96. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  97. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  98. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  99. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  100. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  101. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  102. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  103. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  104. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  105. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  106. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  107. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  108. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  109. data/lib/pubid/bsi/identifiers.rb +0 -1
  110. data/lib/pubid/bsi/renderer.rb +1050 -0
  111. data/lib/pubid/bsi/single_identifier.rb +6 -70
  112. data/lib/pubid/bsi/urn_generator.rb +2 -3
  113. data/lib/pubid/bsi/urn_parser.rb +52 -0
  114. data/lib/pubid/bsi.rb +224 -1
  115. data/lib/pubid/builder/base.rb +57 -10
  116. data/lib/pubid/bundled_identifier.rb +0 -1
  117. data/lib/pubid/ccsds/builder.rb +4 -3
  118. data/lib/pubid/ccsds/identifier.rb +66 -1
  119. data/lib/pubid/ccsds/identifiers/base.rb +11 -50
  120. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  121. data/lib/pubid/ccsds/parser.rb +4 -2
  122. data/lib/pubid/ccsds/single_identifier.rb +4 -1
  123. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  124. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  125. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  126. data/lib/pubid/ccsds.rb +39 -1
  127. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  128. data/lib/pubid/cen_cenelec/identifier.rb +8 -2
  129. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  130. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  131. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  132. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  133. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  135. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  136. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  137. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  138. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  140. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  141. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  143. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  144. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  145. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  146. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  147. data/lib/pubid/cen_cenelec.rb +168 -1
  148. data/lib/pubid/cie/components/code.rb +8 -0
  149. data/lib/pubid/cie/identifier.rb +6 -4
  150. data/lib/pubid/cie/urn_parser.rb +28 -0
  151. data/lib/pubid/cie.rb +43 -1
  152. data/lib/pubid/components/adoption.rb +104 -0
  153. data/lib/pubid/components/code.rb +22 -8
  154. data/lib/pubid/components/date.rb +23 -16
  155. data/lib/pubid/components/edition.rb +9 -6
  156. data/lib/pubid/components/iteration.rb +32 -0
  157. data/lib/pubid/components/language.rb +6 -4
  158. data/lib/pubid/components/locality.rb +10 -1
  159. data/lib/pubid/components/publisher.rb +9 -6
  160. data/lib/pubid/components/relationship.rb +151 -0
  161. data/lib/pubid/components/stage.rb +5 -14
  162. data/lib/pubid/components/supplement.rb +184 -0
  163. data/lib/pubid/components/type.rb +5 -15
  164. data/lib/pubid/components/typed_stage.rb +11 -8
  165. data/lib/pubid/components.rb +4 -0
  166. data/lib/pubid/core/update_codes.rb +28 -7
  167. data/lib/pubid/csa/identifier.rb +0 -3
  168. data/lib/pubid/csa/identifiers/base.rb +2 -122
  169. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  170. data/lib/pubid/csa/identifiers/series.rb +2 -102
  171. data/lib/pubid/csa/renderer.rb +292 -0
  172. data/lib/pubid/csa/urn_generator.rb +1 -1
  173. data/lib/pubid/csa/urn_parser.rb +33 -0
  174. data/lib/pubid/csa.rb +42 -1
  175. data/lib/pubid/etsi/components/code.rb +9 -2
  176. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  177. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  178. data/lib/pubid/etsi/renderer.rb +42 -0
  179. data/lib/pubid/etsi/urn_parser.rb +34 -0
  180. data/lib/pubid/etsi.rb +42 -1
  181. data/lib/pubid/export/exporter.rb +4 -46
  182. data/lib/pubid/export/flavor_exporter.rb +111 -278
  183. data/lib/pubid/export.rb +0 -6
  184. data/lib/pubid/identifier.rb +10 -18
  185. data/lib/pubid/identifier_facade.rb +114 -0
  186. data/lib/pubid/identifier_metadata.rb +1 -1
  187. data/lib/pubid/idf/builder.rb +3 -3
  188. data/lib/pubid/idf/identifier.rb +3 -6
  189. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  190. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  191. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  192. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  193. data/lib/pubid/idf/parser.rb +3 -2
  194. data/lib/pubid/idf/renderer.rb +84 -0
  195. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  196. data/lib/pubid/idf/urn_generator.rb +4 -39
  197. data/lib/pubid/idf/urn_parser.rb +25 -0
  198. data/lib/pubid/idf.rb +51 -1
  199. data/lib/pubid/iec/builder.rb +48 -65
  200. data/lib/pubid/iec/components/code.rb +9 -32
  201. data/lib/pubid/iec/components/publisher.rb +1 -1
  202. data/lib/pubid/iec/components.rb +14 -0
  203. data/lib/pubid/iec/identifier.rb +276 -3
  204. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  205. data/lib/pubid/iec/identifiers/base.rb +8 -28
  206. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  207. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  208. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -30
  209. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  210. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -26
  211. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  212. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  213. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  214. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  215. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  216. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -15
  217. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  218. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  219. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  220. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  222. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  223. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -23
  224. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  225. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  226. data/lib/pubid/iec/identifiers.rb +30 -0
  227. data/lib/pubid/iec/parser.rb +20 -14
  228. data/lib/pubid/iec/renderer.rb +254 -0
  229. data/lib/pubid/iec/single_identifier.rb +6 -12
  230. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  231. data/lib/pubid/iec/urn_generator.rb +57 -171
  232. data/lib/pubid/iec/urn_parser.rb +53 -252
  233. data/lib/pubid/iec.rb +40 -68
  234. data/lib/pubid/ieee/builder.rb +12 -12
  235. data/lib/pubid/ieee/components/code.rb +8 -0
  236. data/lib/pubid/ieee/components/draft.rb +14 -0
  237. data/lib/pubid/ieee/components/relationship.rb +5 -149
  238. data/lib/pubid/ieee/identifier.rb +6 -0
  239. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  240. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  241. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  242. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  243. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  246. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  247. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  248. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  249. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  250. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  251. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  252. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  253. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  254. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  255. data/lib/pubid/ieee/pre_parser.rb +301 -0
  256. data/lib/pubid/ieee/renderer.rb +307 -0
  257. data/lib/pubid/ieee/urn_parser.rb +34 -0
  258. data/lib/pubid/ieee.rb +62 -1
  259. data/lib/pubid/ieee_debug.rb +0 -1
  260. data/lib/pubid/iho/builder.rb +2 -2
  261. data/lib/pubid/iho/identifier.rb +8 -0
  262. data/lib/pubid/iho/identifiers/base.rb +49 -10
  263. data/lib/pubid/iho/identifiers/bibliographic.rb +0 -4
  264. data/lib/pubid/iho/identifiers/circular_letter.rb +0 -4
  265. data/lib/pubid/iho/identifiers/miscellaneous.rb +0 -4
  266. data/lib/pubid/iho/identifiers/publication.rb +0 -4
  267. data/lib/pubid/iho/identifiers/standard.rb +0 -4
  268. data/lib/pubid/iho/parser.rb +3 -3
  269. data/lib/pubid/iho/renderer.rb +30 -0
  270. data/lib/pubid/iho/urn_generator.rb +3 -3
  271. data/lib/pubid/iho/urn_parser.rb +58 -0
  272. data/lib/pubid/iho.rb +50 -1
  273. data/lib/pubid/iso/builder.rb +59 -53
  274. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  275. data/lib/pubid/iso/components/code.rb +7 -19
  276. data/lib/pubid/iso/components/publisher.rb +10 -8
  277. data/lib/pubid/iso/components.rb +2 -4
  278. data/lib/pubid/iso/identifier.rb +233 -6
  279. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  280. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  281. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  282. data/lib/pubid/iso/identifiers/data.rb +0 -1
  283. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  284. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  285. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  286. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  287. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  288. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  289. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  290. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  291. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  292. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  293. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  294. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  295. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  296. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  297. data/lib/pubid/iso/identifiers.rb +0 -1
  298. data/lib/pubid/iso/normalizer.rb +89 -0
  299. data/lib/pubid/iso/parser.rb +26 -6
  300. data/lib/pubid/iso/single_identifier.rb +6 -3
  301. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  302. data/lib/pubid/iso/urn_generator.rb +74 -176
  303. data/lib/pubid/iso/urn_parser.rb +28 -9
  304. data/lib/pubid/iso.rb +173 -2
  305. data/lib/pubid/itu/builder.rb +0 -12
  306. data/lib/pubid/itu/components/code.rb +8 -0
  307. data/lib/pubid/itu/components.rb +11 -0
  308. data/lib/pubid/itu/identifier.rb +6 -39
  309. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  310. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  311. data/lib/pubid/itu/identifiers/base.rb +0 -6
  312. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  313. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  314. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  315. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  316. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  317. data/lib/pubid/itu/urn_parser.rb +23 -0
  318. data/lib/pubid/itu.rb +42 -1
  319. data/lib/pubid/jcgm/builder.rb +16 -8
  320. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  321. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  322. data/lib/pubid/jcgm/renderer.rb +68 -0
  323. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  324. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  325. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  326. data/lib/pubid/jcgm.rb +43 -2
  327. data/lib/pubid/jis/builder.rb +44 -52
  328. data/lib/pubid/jis/identifier.rb +132 -3
  329. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  330. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  331. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  332. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  333. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  334. data/lib/pubid/jis/identifiers.rb +1 -1
  335. data/lib/pubid/jis/parser.rb +31 -5
  336. data/lib/pubid/jis/renderer.rb +69 -0
  337. data/lib/pubid/jis/single_identifier.rb +6 -12
  338. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  339. data/lib/pubid/jis/urn_parser.rb +23 -0
  340. data/lib/pubid/jis.rb +42 -2
  341. data/lib/pubid/nist/builder.rb +122 -1761
  342. data/lib/pubid/nist/caster.rb +1272 -0
  343. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  344. data/lib/pubid/nist/components/code.rb +9 -20
  345. data/lib/pubid/nist/components/edition.rb +16 -0
  346. data/lib/pubid/nist/components/supplement.rb +88 -21
  347. data/lib/pubid/nist/components.rb +0 -1
  348. data/lib/pubid/nist/identifier.rb +25 -0
  349. data/lib/pubid/nist/identifiers/base.rb +206 -64
  350. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  351. data/lib/pubid/nist/identifiers/circular_supplement.rb +3 -2
  352. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  353. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  354. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  355. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -11
  356. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  357. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +17 -16
  358. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  359. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  360. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  361. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  362. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  363. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  364. data/lib/pubid/nist/identifiers/report.rb +4 -3
  365. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  366. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  367. data/lib/pubid/nist/identifiers.rb +1 -0
  368. data/lib/pubid/nist/parser.rb +67 -424
  369. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  370. data/lib/pubid/nist/preprocessor.rb +416 -0
  371. data/lib/pubid/nist/renderer.rb +43 -0
  372. data/lib/pubid/nist/router.rb +148 -0
  373. data/lib/pubid/nist/series/base.rb +58 -0
  374. data/lib/pubid/nist/series/crpl.rb +13 -0
  375. data/lib/pubid/nist/series/fips.rb +14 -0
  376. data/lib/pubid/nist/series/ir.rb +60 -0
  377. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  378. data/lib/pubid/nist/series/mono.rb +19 -0
  379. data/lib/pubid/nist/series/ncstar.rb +20 -0
  380. data/lib/pubid/nist/series.rb +49 -0
  381. data/lib/pubid/nist/supplement_identifier.rb +11 -25
  382. data/lib/pubid/nist/urn_generator.rb +14 -8
  383. data/lib/pubid/nist/urn_parser.rb +67 -0
  384. data/lib/pubid/nist.rb +83 -4
  385. data/lib/pubid/oiml/components/code.rb +10 -0
  386. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  387. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  388. data/lib/pubid/oiml/renderer.rb +161 -0
  389. data/lib/pubid/oiml/single_identifier.rb +6 -45
  390. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  391. data/lib/pubid/oiml/urn_generator.rb +0 -8
  392. data/lib/pubid/oiml/urn_parser.rb +22 -0
  393. data/lib/pubid/oiml.rb +42 -1
  394. data/lib/pubid/plateau/identifier.rb +23 -0
  395. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  396. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  397. data/lib/pubid/plateau/renderer.rb +51 -0
  398. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  399. data/lib/pubid/plateau/urn_parser.rb +43 -0
  400. data/lib/pubid/plateau.rb +44 -1
  401. data/lib/pubid/renderers/base.rb +34 -0
  402. data/lib/pubid/renderers/directives_renderer.rb +27 -14
  403. data/lib/pubid/renderers/guide_renderer.rb +7 -1
  404. data/lib/pubid/renderers/human_readable.rb +31 -8
  405. data/lib/pubid/renderers/iwa_renderer.rb +5 -1
  406. data/lib/pubid/renderers/supplement_renderer.rb +4 -1
  407. data/lib/pubid/rendering/context.rb +33 -21
  408. data/lib/pubid/rendering.rb +0 -3
  409. data/lib/pubid/sae/components/date.rb +8 -0
  410. data/lib/pubid/sae/components/type.rb +5 -1
  411. data/lib/pubid/sae/identifiers/base.rb +2 -16
  412. data/lib/pubid/sae/renderer.rb +36 -0
  413. data/lib/pubid/sae/urn_generator.rb +2 -10
  414. data/lib/pubid/sae/urn_parser.rb +36 -0
  415. data/lib/pubid/sae.rb +42 -1
  416. data/lib/pubid/urn_generator/base.rb +12 -12
  417. data/lib/pubid/urn_parser/base.rb +81 -0
  418. data/lib/pubid/urn_parser/errors.rb +9 -0
  419. data/lib/pubid/urn_parser.rb +14 -0
  420. data/lib/pubid/version.rb +1 -1
  421. data/lib/pubid.rb +29 -7
  422. data/lib/tasks/website-data.json +1940 -1882
  423. metadata +77 -43
  424. data/lib/pubid/amca/scheme.rb +0 -16
  425. data/lib/pubid/ansi/scheme.rb +0 -15
  426. data/lib/pubid/api/scheme.rb +0 -66
  427. data/lib/pubid/ashrae/scheme.rb +0 -53
  428. data/lib/pubid/asme/scheme.rb +0 -37
  429. data/lib/pubid/astm/scheme.rb +0 -55
  430. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  431. data/lib/pubid/bsi/scheme.rb +0 -243
  432. data/lib/pubid/ccsds/scheme.rb +0 -57
  433. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  434. data/lib/pubid/cie/scheme.rb +0 -64
  435. data/lib/pubid/csa/scheme.rb +0 -44
  436. data/lib/pubid/etsi/scheme.rb +0 -42
  437. data/lib/pubid/export/data_class_exporter.rb +0 -59
  438. data/lib/pubid/export/ieee_exporter.rb +0 -78
  439. data/lib/pubid/export/itu_exporter.rb +0 -66
  440. data/lib/pubid/export/nist_exporter.rb +0 -64
  441. data/lib/pubid/export/registry_exporter.rb +0 -90
  442. data/lib/pubid/export/scheme_exporter.rb +0 -70
  443. data/lib/pubid/identifier_registry.rb +0 -198
  444. data/lib/pubid/idf/scheme.rb +0 -61
  445. data/lib/pubid/iec/scheme.rb +0 -71
  446. data/lib/pubid/ieee/scheme.rb +0 -90
  447. data/lib/pubid/iho/scheme.rb +0 -29
  448. data/lib/pubid/iso/identifiers/base.rb +0 -115
  449. data/lib/pubid/iso/scheme.rb +0 -187
  450. data/lib/pubid/itu/scheme.rb +0 -174
  451. data/lib/pubid/jcgm/scheme.rb +0 -60
  452. data/lib/pubid/jis/components/code.rb +0 -59
  453. data/lib/pubid/jis/identifiers/base.rb +0 -72
  454. data/lib/pubid/jis/scheme.rb +0 -49
  455. data/lib/pubid/nist/components/publisher.rb +0 -24
  456. data/lib/pubid/nist/scheme.rb +0 -199
  457. data/lib/pubid/oiml/scheme.rb +0 -46
  458. data/lib/pubid/plateau/scheme.rb +0 -45
  459. data/lib/pubid/rendering/base.rb +0 -73
  460. data/lib/pubid/rendering/common.rb +0 -211
  461. data/lib/pubid/rendering/format.rb +0 -25
  462. data/lib/pubid/sae/scheme.rb +0 -47
  463. data/lib/pubid/scheme.rb +0 -207
@@ -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
data/lib/pubid/csa.rb CHANGED
@@ -6,9 +6,10 @@ module Pubid
6
6
  autoload :Identifier, "#{__dir__}/csa/identifier"
7
7
  autoload :Identifiers, "#{__dir__}/csa/identifiers"
8
8
  autoload :Parser, "#{__dir__}/csa/parser"
9
- autoload :Scheme, "#{__dir__}/csa/scheme"
9
+ autoload :Renderer, "#{__dir__}/csa/renderer"
10
10
  autoload :SingleIdentifier, "#{__dir__}/csa/single_identifier"
11
11
  autoload :UrnGenerator, "#{__dir__}/csa/urn_generator"
12
+ autoload :UrnParser, "#{__dir__}/csa/urn_parser"
12
13
  autoload :WrapperIdentifier, "#{__dir__}/csa/wrapper_identifier"
13
14
  autoload :CompositeIdentifier, "#{__dir__}/csa/composite_identifier"
14
15
  autoload :Components, "#{__dir__}/csa/components"
@@ -16,6 +17,42 @@ module Pubid
16
17
  def self.parse(identifier_string)
17
18
  Identifier.parse(identifier_string)
18
19
  end
20
+
21
+ # Auto-discover all identifier types from the Identifiers namespace
22
+ # @return [Array<Class>] identifier classes that define a self.type Hash
23
+ def self.identifier_types
24
+ @identifier_types ||= Identifiers.constants
25
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
26
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
27
+ .select { |c| c.type.is_a?(Hash) }
28
+ end
29
+
30
+ # Build typed stage index from identifier types
31
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
32
+ def self.all_typed_stages
33
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
34
+ if klass.const_defined?(:TYPED_STAGES)
35
+ klass.const_get(:TYPED_STAGES)
36
+ else
37
+ []
38
+ end
39
+ end
40
+ end
41
+
42
+ # Lookup: type code -> identifier class
43
+ # @param code [String, Symbol] the type key to find
44
+ # @return [Class, nil] the matching identifier class
45
+ def self.locate_type(code)
46
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
47
+ end
48
+
49
+ # Lookup: abbreviation -> typed stage
50
+ # @param abbr [String, Symbol] the abbreviation to find
51
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
52
+ def self.locate_stage(abbr)
53
+ abbr_str = abbr.to_s.upcase
54
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
55
+ end
19
56
  end
20
57
 
21
58
  # Register this flavor with the Pubid registry
@@ -23,3 +60,7 @@ end
23
60
 
24
61
  # Register Ucsa flavor with the registry
25
62
  Pubid::Registry.register(:csa, Pubid::Csa)
63
+
64
+ # Per-flavor format registry: inherits global formats, overrides :human
65
+ Pubid::Csa::SingleIdentifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
66
+ Pubid::Csa::SingleIdentifier.format_registry.register(:human, renderer: Pubid::Csa::Renderer)
@@ -10,9 +10,12 @@ module Pubid
10
10
  # Simple: 012, 123, 456
11
11
  # GSM: GSM 02.01, 02.01
12
12
  # Complex: ABC 123, ABC-DEF 123
13
+ #
14
+ # Stays independent of Pubid::Components::Code because ETSI uses
15
+ # +minor+ (a flavor-specific sub-number) plus +parts+.
13
16
  class Code < Lutaml::Model::Serializable
14
- attribute :number, :string # Main number (can contain dots, letters, etc.)
15
- attribute :minor, :string # Optional minor part
17
+ attribute :number, :string # Main number
18
+ attribute :minor, :string # Optional minor part
16
19
  attribute :parts, :string, collection: true # Parts array
17
20
 
18
21
  def initialize(number:, minor: nil, parts: nil)
@@ -29,6 +32,10 @@ module Pubid
29
32
  result
30
33
  end
31
34
 
35
+ def render(context: nil)
36
+ to_s
37
+ end
38
+
32
39
  def ==(other)
33
40
  return false unless other.is_a?(Code)
34
41
 
@@ -18,10 +18,7 @@ module Pubid
18
18
  end
19
19
 
20
20
  def to_s
21
- result = "#{publisher} #{type} #{code}"
22
- result += " #{version} (#{date.year}-#{date.month.to_s.rjust(2,
23
- '0')})"
24
- result
21
+ render(format: :human)
25
22
  end
26
23
 
27
24
  def ==(other)
@@ -25,16 +25,9 @@ module Pubid
25
25
  base.date
26
26
  end
27
27
 
28
- # Render as: ETSI TYPE CODE/SUPPLEMENTS VERSION (DATE)
29
- # When multiple supplements are present, they appear in order: /A1/C1
28
+ # Render via renderer
30
29
  def to_s
31
- supplement_notations = collect_supplement_notations(self, [])
32
- # Get the actual base ETSI standard (not supplements)
33
- actual_base = find_actual_base(base)
34
- code_with_supplements = "#{actual_base.code}#{supplement_notations.join}"
35
- "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements} #{actual_base.version} (#{actual_base.date.year}-#{actual_base.date.month.to_s.rjust(
36
- 2, '0'
37
- )})"
30
+ render(format: :human)
38
31
  end
39
32
 
40
33
  # Recursively collect supplement notations from the supplement chain
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Etsi
5
+ # Human-readable renderer for ETSI identifiers.
6
+ #
7
+ # Produces strings like:
8
+ # "ETSI EN 301 419 V1.1.1 (2020-01)"
9
+ # "ETSI TS 102 606-1/A1 V1.1.1 (2021-06)"
10
+ # "ETSI GS NFV 002 ed.1 (2013-10)"
11
+ #
12
+ # The renderer is registered as the `:human` format in the ETSI format
13
+ # registry and invoked via `render(format: :human)`.
14
+ class Renderer < ::Pubid::Renderers::Base
15
+ def render(context: nil, **opts)
16
+ id = @id
17
+
18
+ case id
19
+ when Identifiers::SupplementIdentifier
20
+ render_supplement(id)
21
+ else
22
+ render_base(id)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def render_base(id)
29
+ result = "#{id.publisher} #{id.type} #{id.code}"
30
+ result += " #{id.version} (#{id.date.render})"
31
+ result
32
+ end
33
+
34
+ def render_supplement(id)
35
+ supplement_notations = id.collect_supplement_notations(id, [])
36
+ actual_base = id.find_actual_base(id.base)
37
+ code_with_supplements = "#{actual_base.code}#{supplement_notations.join}"
38
+ "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements} #{actual_base.version} (#{actual_base.date.render})"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Etsi
5
+ # Parses ETSI URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:etsi:{type}:{code}:{version}:{date}[:{supplement_notation}:{number}]
9
+ #
10
+ # type is the lowercase type abbreviation (en, ets, ts, tr, gs, sr).
11
+ # code is the identifier code with internal whitespace preserved.
12
+ # version is the lowercase Vx.y.z form.
13
+ # date is YYYY or YYYY-MM.
14
+ #
15
+ # Examples:
16
+ # - urn:etsi:en:300 100:v1.1.1:1998-04 → ETSI EN 300 100 V1.1.1 (1998-04)
17
+ class UrnParser < Pubid::UrnParser::Base
18
+ def parse_urn(urn)
19
+ body = strip_namespace(urn)
20
+ parts = split_parts(body)
21
+
22
+ type_token = parts.fetch(0).upcase
23
+ code = parts.fetch(1)
24
+ version = parts[2]
25
+ date = parts[3]
26
+
27
+ text = "ETSI #{type_token} #{code}"
28
+ text += " #{version.upcase}" if version
29
+ text += " (#{date})" if date
30
+ flavor_parse(text)
31
+ end
32
+ end
33
+ end
34
+ end