pubid 2.0.0.pre.alpha.2 → 2.0.0.pre.alpha.4

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 (473) 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 +4 -55
  6. data/lib/pubid/amca/identifiers/base.rb +58 -47
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -21
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -17
  9. data/lib/pubid/amca/identifiers/standard.rb +0 -4
  10. data/lib/pubid/amca/renderer.rb +82 -0
  11. data/lib/pubid/amca/single_identifier.rb +0 -23
  12. data/lib/pubid/amca/urn_generator.rb +2 -1
  13. data/lib/pubid/amca/urn_parser.rb +28 -0
  14. data/lib/pubid/amca.rb +42 -1
  15. data/lib/pubid/ansi/builder.rb +5 -3
  16. data/lib/pubid/ansi/identifier.rb +1 -43
  17. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  18. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  19. data/lib/pubid/ansi/renderer.rb +53 -0
  20. data/lib/pubid/ansi/single_identifier.rb +2 -31
  21. data/lib/pubid/ansi/urn_generator.rb +3 -38
  22. data/lib/pubid/ansi/urn_parser.rb +23 -0
  23. data/lib/pubid/ansi.rb +38 -3
  24. data/lib/pubid/api/builder.rb +33 -74
  25. data/lib/pubid/api/identifier.rb +5 -52
  26. data/lib/pubid/api/identifiers/base.rb +2 -14
  27. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  28. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  29. data/lib/pubid/api/identifiers/mpms.rb +0 -20
  30. data/lib/pubid/api/identifiers/publication.rb +0 -2
  31. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  32. data/lib/pubid/api/identifiers/specification.rb +0 -2
  33. data/lib/pubid/api/identifiers/standard.rb +0 -2
  34. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  35. data/lib/pubid/api/identifiers/typeless_standard.rb +0 -16
  36. data/lib/pubid/api/identifiers.rb +18 -0
  37. data/lib/pubid/api/renderer.rb +89 -0
  38. data/lib/pubid/api/single_identifier.rb +5 -20
  39. data/lib/pubid/api/urn_generator.rb +0 -18
  40. data/lib/pubid/api/urn_parser.rb +35 -0
  41. data/lib/pubid/api.rb +51 -5
  42. data/lib/pubid/ashrae/builder.rb +3 -3
  43. data/lib/pubid/ashrae/identifier.rb +7 -55
  44. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  45. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  46. data/lib/pubid/ashrae/identifiers/base.rb +29 -15
  47. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  48. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  49. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  50. data/lib/pubid/ashrae/parser.rb +4 -0
  51. data/lib/pubid/ashrae/renderer.rb +117 -0
  52. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  53. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  54. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  55. data/lib/pubid/ashrae.rb +46 -1
  56. data/lib/pubid/asme/components/code.rb +10 -2
  57. data/lib/pubid/asme/identifier.rb +0 -46
  58. data/lib/pubid/asme/identifiers/base.rb +0 -60
  59. data/lib/pubid/asme/renderer.rb +66 -0
  60. data/lib/pubid/asme/single_identifier.rb +3 -1
  61. data/lib/pubid/asme/urn_parser.rb +31 -0
  62. data/lib/pubid/asme.rb +42 -1
  63. data/lib/pubid/astm/components/code.rb +9 -0
  64. data/lib/pubid/{jis → astm}/components.rb +1 -1
  65. data/lib/pubid/astm/identifier.rb +0 -77
  66. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  67. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  68. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  69. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  70. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  71. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  72. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  73. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  74. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  75. data/lib/pubid/astm/identifiers.rb +18 -0
  76. data/lib/pubid/astm/renderer.rb +172 -0
  77. data/lib/pubid/astm/single_identifier.rb +3 -11
  78. data/lib/pubid/astm/urn_parser.rb +30 -0
  79. data/lib/pubid/astm.rb +39 -27
  80. data/lib/pubid/bsi/builder.rb +21 -12
  81. data/lib/pubid/bsi/identifier.rb +5 -85
  82. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -36
  83. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +8 -48
  84. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +8 -39
  85. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +2 -55
  86. data/lib/pubid/bsi/identifiers/amendment.rb +2 -22
  87. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -6
  88. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  89. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -87
  90. data/lib/pubid/bsi/identifiers/committee_document.rb +0 -16
  91. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -87
  92. data/lib/pubid/bsi/identifiers/corrigendum.rb +2 -10
  93. data/lib/pubid/bsi/identifiers/detailed_specification.rb +0 -36
  94. data/lib/pubid/bsi/identifiers/disc.rb +0 -29
  95. data/lib/pubid/bsi/identifiers/draft_document.rb +2 -46
  96. data/lib/pubid/bsi/identifiers/electronic_book.rb +2 -38
  97. data/lib/pubid/bsi/identifiers/expert_commentary.rb +2 -18
  98. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +0 -47
  99. data/lib/pubid/bsi/identifiers/flex.rb +0 -35
  100. data/lib/pubid/bsi/identifiers/handbook.rb +1 -15
  101. data/lib/pubid/bsi/identifiers/index.rb +0 -32
  102. data/lib/pubid/bsi/identifiers/method.rb +0 -41
  103. data/lib/pubid/bsi/identifiers/national_annex.rb +4 -29
  104. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -6
  105. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +2 -54
  106. data/lib/pubid/bsi/identifiers/published_document.rb +2 -54
  107. data/lib/pubid/bsi/identifiers/section.rb +0 -30
  108. data/lib/pubid/bsi/identifiers/set.rb +3 -20
  109. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +0 -9
  110. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -24
  111. data/lib/pubid/bsi/identifiers/supplementary_index.rb +0 -46
  112. data/lib/pubid/bsi/identifiers/technical_specification.rb +2 -47
  113. data/lib/pubid/bsi/identifiers/test_method.rb +0 -32
  114. data/lib/pubid/bsi/identifiers/value_added_publication.rb +2 -17
  115. data/lib/pubid/bsi/identifiers.rb +0 -1
  116. data/lib/pubid/bsi/renderer.rb +1050 -0
  117. data/lib/pubid/bsi/single_identifier.rb +33 -78
  118. data/lib/pubid/bsi/urn_generator.rb +2 -3
  119. data/lib/pubid/bsi/urn_parser.rb +52 -0
  120. data/lib/pubid/bsi.rb +232 -2
  121. data/lib/pubid/builder/base.rb +57 -10
  122. data/lib/pubid/bundled_identifier.rb +0 -1
  123. data/lib/pubid/ccsds/builder.rb +4 -3
  124. data/lib/pubid/ccsds/identifier.rb +53 -68
  125. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  126. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  127. data/lib/pubid/ccsds/parser.rb +4 -2
  128. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  129. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  130. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  131. data/lib/pubid/ccsds.rb +39 -1
  132. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  133. data/lib/pubid/cen_cenelec/identifier.rb +11 -40
  134. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +9 -4
  135. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +0 -10
  136. data/lib/pubid/cen_cenelec/identifiers/base.rb +2 -45
  137. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +0 -27
  140. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +0 -15
  141. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +2 -8
  143. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +0 -4
  145. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  146. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  147. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  148. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  149. data/lib/pubid/cen_cenelec/single_identifier.rb +9 -90
  150. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  151. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  152. data/lib/pubid/cen_cenelec.rb +172 -1
  153. data/lib/pubid/cie/components/code.rb +8 -0
  154. data/lib/pubid/cie/identifier.rb +10 -57
  155. data/lib/pubid/cie/single_identifier.rb +4 -4
  156. data/lib/pubid/cie/urn_parser.rb +28 -0
  157. data/lib/pubid/cie.rb +47 -1
  158. data/lib/pubid/components/adoption.rb +104 -0
  159. data/lib/pubid/components/code.rb +22 -8
  160. data/lib/pubid/components/date.rb +23 -16
  161. data/lib/pubid/components/edition.rb +9 -6
  162. data/lib/pubid/components/iteration.rb +32 -0
  163. data/lib/pubid/components/language.rb +6 -4
  164. data/lib/pubid/components/locality.rb +10 -1
  165. data/lib/pubid/components/publisher.rb +9 -6
  166. data/lib/pubid/components/relationship.rb +151 -0
  167. data/lib/pubid/components/stage.rb +5 -14
  168. data/lib/pubid/components/supplement.rb +184 -0
  169. data/lib/pubid/components/type.rb +5 -15
  170. data/lib/pubid/components/typed_stage.rb +10 -11
  171. data/lib/pubid/components.rb +4 -1
  172. data/lib/pubid/core/update_codes.rb +28 -7
  173. data/lib/pubid/csa/identifier.rb +9 -59
  174. data/lib/pubid/csa/identifiers/base.rb +0 -123
  175. data/lib/pubid/csa/identifiers/cec.rb +0 -103
  176. data/lib/pubid/csa/identifiers/series.rb +0 -104
  177. data/lib/pubid/csa/renderer.rb +292 -0
  178. data/lib/pubid/csa/single_identifier.rb +1 -1
  179. data/lib/pubid/csa/urn_generator.rb +1 -1
  180. data/lib/pubid/csa/urn_parser.rb +33 -0
  181. data/lib/pubid/csa.rb +46 -1
  182. data/lib/pubid/etsi/components/code.rb +10 -9
  183. data/lib/pubid/etsi/components/version.rb +0 -5
  184. data/lib/pubid/etsi/identifier.rb +4 -55
  185. data/lib/pubid/etsi/identifiers/base.rb +31 -27
  186. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +1 -11
  187. data/lib/pubid/etsi/renderer.rb +42 -0
  188. data/lib/pubid/etsi/urn_parser.rb +34 -0
  189. data/lib/pubid/etsi.rb +44 -1
  190. data/lib/pubid/export/exporter.rb +4 -46
  191. data/lib/pubid/export/flavor_exporter.rb +111 -278
  192. data/lib/pubid/export.rb +0 -6
  193. data/lib/pubid/identifier.rb +92 -18
  194. data/lib/pubid/identifier_metadata.rb +1 -1
  195. data/lib/pubid/idf/builder.rb +3 -3
  196. data/lib/pubid/idf/identifier.rb +7 -66
  197. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  198. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  199. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  200. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  201. data/lib/pubid/idf/parser.rb +3 -2
  202. data/lib/pubid/idf/renderer.rb +84 -0
  203. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  204. data/lib/pubid/idf/urn_generator.rb +4 -39
  205. data/lib/pubid/idf/urn_parser.rb +25 -0
  206. data/lib/pubid/idf.rb +55 -1
  207. data/lib/pubid/iec/builder.rb +46 -64
  208. data/lib/pubid/iec/components/code.rb +8 -32
  209. data/lib/pubid/iec/components/publisher.rb +0 -1
  210. data/lib/pubid/iec/components.rb +14 -0
  211. data/lib/pubid/iec/identifier.rb +251 -213
  212. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  213. data/lib/pubid/iec/identifiers/base.rb +5 -33
  214. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  215. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  216. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +23 -26
  217. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  218. data/lib/pubid/iec/identifiers/fragment_identifier.rb +35 -24
  219. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  220. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  221. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  222. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  223. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  224. data/lib/pubid/iec/identifiers/sheet_identifier.rb +17 -11
  225. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  226. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  227. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  228. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  229. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  230. data/lib/pubid/iec/identifiers/test_report_form.rb +3 -35
  231. data/lib/pubid/iec/identifiers/vap_identifier.rb +24 -21
  232. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  233. data/lib/pubid/iec/identifiers/working_document.rb +2 -50
  234. data/lib/pubid/iec/identifiers.rb +30 -0
  235. data/lib/pubid/iec/parser.rb +13 -12
  236. data/lib/pubid/iec/renderer.rb +254 -0
  237. data/lib/pubid/iec/single_identifier.rb +6 -12
  238. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  239. data/lib/pubid/iec/urn_generator.rb +3 -3
  240. data/lib/pubid/iec/urn_parser.rb +3 -3
  241. data/lib/pubid/iec.rb +43 -67
  242. data/lib/pubid/ieee/builder.rb +12 -12
  243. data/lib/pubid/ieee/components/code.rb +8 -0
  244. data/lib/pubid/ieee/components/draft.rb +14 -0
  245. data/lib/pubid/ieee/components/relationship.rb +5 -149
  246. data/lib/pubid/ieee/identifier.rb +5 -52
  247. data/lib/pubid/ieee/identifiers/adopted_standard.rb +0 -9
  248. data/lib/pubid/ieee/identifiers/base.rb +221 -556
  249. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +0 -10
  250. data/lib/pubid/ieee/identifiers/corrigendum.rb +0 -12
  251. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +0 -10
  252. data/lib/pubid/ieee/identifiers/dual_identifier.rb +0 -4
  253. data/lib/pubid/ieee/identifiers/dual_published.rb +0 -4
  254. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +0 -9
  255. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +0 -10
  256. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  257. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +0 -18
  258. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +0 -6
  259. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  260. data/lib/pubid/ieee/identifiers/redlined_standard.rb +0 -7
  261. data/lib/pubid/ieee/identifiers/si_standard.rb +0 -38
  262. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  263. data/lib/pubid/ieee/pre_parser.rb +301 -0
  264. data/lib/pubid/ieee/renderer.rb +307 -0
  265. data/lib/pubid/ieee/urn_parser.rb +34 -0
  266. data/lib/pubid/ieee.rb +66 -1
  267. data/lib/pubid/ieee_debug.rb +0 -1
  268. data/lib/pubid/iho/builder.rb +2 -2
  269. data/lib/pubid/iho/identifier.rb +7 -59
  270. data/lib/pubid/iho/identifiers/base.rb +64 -31
  271. data/lib/pubid/iho/parser.rb +3 -3
  272. data/lib/pubid/iho/renderer.rb +30 -0
  273. data/lib/pubid/iho/urn_generator.rb +2 -2
  274. data/lib/pubid/iho/urn_parser.rb +58 -0
  275. data/lib/pubid/iho.rb +52 -1
  276. data/lib/pubid/iso/builder.rb +55 -53
  277. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  278. data/lib/pubid/iso/components/code.rb +7 -19
  279. data/lib/pubid/iso/components/publisher.rb +10 -8
  280. data/lib/pubid/iso/components.rb +2 -4
  281. data/lib/pubid/iso/identifier.rb +219 -252
  282. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  283. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  284. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  285. data/lib/pubid/iso/identifiers/data.rb +0 -1
  286. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  287. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  288. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  289. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  290. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  291. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  292. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  293. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  294. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  295. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  296. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  297. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  298. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  299. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  300. data/lib/pubid/iso/identifiers.rb +0 -1
  301. data/lib/pubid/iso/normalizer.rb +89 -0
  302. data/lib/pubid/iso/parser.rb +22 -4
  303. data/lib/pubid/iso/single_identifier.rb +0 -4
  304. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  305. data/lib/pubid/iso/urn_generator.rb +66 -182
  306. data/lib/pubid/iso/urn_parser.rb +12 -7
  307. data/lib/pubid/iso.rb +177 -2
  308. data/lib/pubid/itu/builder.rb +0 -12
  309. data/lib/pubid/itu/components/code.rb +9 -7
  310. data/lib/pubid/itu/components/sector.rb +15 -4
  311. data/lib/pubid/itu/components/series.rb +0 -4
  312. data/lib/pubid/itu/components.rb +11 -0
  313. data/lib/pubid/itu/identifier.rb +4 -116
  314. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  315. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  316. data/lib/pubid/itu/identifiers/base.rb +124 -128
  317. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  318. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  319. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  320. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  322. data/lib/pubid/itu/urn_parser.rb +23 -0
  323. data/lib/pubid/itu.rb +44 -1
  324. data/lib/pubid/jcgm/builder.rb +16 -8
  325. data/lib/pubid/jcgm/identifier.rb +0 -43
  326. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -9
  327. data/lib/pubid/jcgm/identifiers/gum_guide.rb +0 -12
  328. data/lib/pubid/jcgm/renderer.rb +68 -0
  329. data/lib/pubid/jcgm/single_identifier.rb +0 -8
  330. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  331. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  332. data/lib/pubid/jcgm.rb +43 -2
  333. data/lib/pubid/jis/builder.rb +44 -52
  334. data/lib/pubid/jis/identifier.rb +120 -46
  335. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  336. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  337. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  338. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  339. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  340. data/lib/pubid/jis/identifiers.rb +1 -1
  341. data/lib/pubid/jis/parser.rb +31 -5
  342. data/lib/pubid/jis/renderer.rb +69 -0
  343. data/lib/pubid/jis/single_identifier.rb +6 -12
  344. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  345. data/lib/pubid/jis/urn_parser.rb +23 -0
  346. data/lib/pubid/jis.rb +42 -2
  347. data/lib/pubid/nist/builder.rb +63 -1871
  348. data/lib/pubid/nist/caster.rb +1272 -0
  349. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  350. data/lib/pubid/nist/components/code.rb +9 -20
  351. data/lib/pubid/nist/components/supplement.rb +2 -2
  352. data/lib/pubid/nist/components.rb +0 -1
  353. data/lib/pubid/nist/identifier.rb +8 -60
  354. data/lib/pubid/nist/identifiers/base.rb +564 -492
  355. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  356. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  361. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  368. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  369. data/lib/pubid/nist/identifiers/report.rb +4 -2
  370. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  371. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  372. data/lib/pubid/nist/identifiers.rb +1 -0
  373. data/lib/pubid/nist/parser.rb +62 -452
  374. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  375. data/lib/pubid/nist/preprocessor.rb +428 -0
  376. data/lib/pubid/nist/renderer.rb +43 -0
  377. data/lib/pubid/nist/router.rb +148 -0
  378. data/lib/pubid/nist/series/base.rb +58 -0
  379. data/lib/pubid/nist/series/crpl.rb +13 -0
  380. data/lib/pubid/nist/series/fips.rb +14 -0
  381. data/lib/pubid/nist/series/ir.rb +60 -0
  382. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  383. data/lib/pubid/nist/series/mono.rb +19 -0
  384. data/lib/pubid/nist/series/ncstar.rb +20 -0
  385. data/lib/pubid/nist/series.rb +49 -0
  386. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  387. data/lib/pubid/nist/urn_parser.rb +67 -0
  388. data/lib/pubid/nist.rb +86 -4
  389. data/lib/pubid/oiml/builder.rb +21 -3
  390. data/lib/pubid/oiml/components/code.rb +17 -0
  391. data/lib/pubid/oiml/identifier.rb +40 -46
  392. data/lib/pubid/oiml/identifiers/annex.rb +13 -46
  393. data/lib/pubid/oiml/identifiers/errata.rb +15 -0
  394. data/lib/pubid/oiml/identifiers.rb +1 -1
  395. data/lib/pubid/oiml/parser.rb +59 -12
  396. data/lib/pubid/oiml/renderer.rb +171 -0
  397. data/lib/pubid/oiml/single_identifier.rb +61 -42
  398. data/lib/pubid/oiml/supplement_identifier.rb +31 -17
  399. data/lib/pubid/oiml/urn_generator.rb +0 -8
  400. data/lib/pubid/oiml/urn_parser.rb +22 -0
  401. data/lib/pubid/oiml.rb +42 -1
  402. data/lib/pubid/plateau/identifier.rb +4 -55
  403. data/lib/pubid/plateau/identifiers/base.rb +45 -36
  404. data/lib/pubid/plateau/identifiers/handbook.rb +0 -6
  405. data/lib/pubid/plateau/identifiers/technical_report.rb +0 -4
  406. data/lib/pubid/plateau/renderer.rb +51 -0
  407. data/lib/pubid/plateau/supplement_identifier.rb +0 -4
  408. data/lib/pubid/plateau/urn_parser.rb +43 -0
  409. data/lib/pubid/plateau.rb +43 -1
  410. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  411. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  412. data/lib/pubid/renderers/human_readable.rb +18 -7
  413. data/lib/pubid/rendering/context.rb +28 -19
  414. data/lib/pubid/rendering.rb +0 -3
  415. data/lib/pubid/sae/components/date.rb +8 -0
  416. data/lib/pubid/sae/components/type.rb +5 -1
  417. data/lib/pubid/sae/identifier.rb +4 -35
  418. data/lib/pubid/sae/identifiers/base.rb +26 -31
  419. data/lib/pubid/sae/renderer.rb +36 -0
  420. data/lib/pubid/sae/urn_generator.rb +2 -10
  421. data/lib/pubid/sae/urn_parser.rb +36 -0
  422. data/lib/pubid/sae.rb +42 -1
  423. data/lib/pubid/urn_generator/base.rb +12 -12
  424. data/lib/pubid/urn_parser/base.rb +81 -0
  425. data/lib/pubid/urn_parser/errors.rb +9 -0
  426. data/lib/pubid/urn_parser.rb +14 -0
  427. data/lib/pubid/version.rb +1 -1
  428. data/lib/pubid.rb +45 -7
  429. data/lib/tasks/export.rake +6 -5
  430. data/lib/tasks/website-data.json +1940 -1882
  431. metadata +75 -45
  432. data/lib/pubid/amca/scheme.rb +0 -16
  433. data/lib/pubid/ansi/scheme.rb +0 -15
  434. data/lib/pubid/api/scheme.rb +0 -66
  435. data/lib/pubid/ashrae/scheme.rb +0 -53
  436. data/lib/pubid/asme/scheme.rb +0 -37
  437. data/lib/pubid/astm/scheme.rb +0 -55
  438. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  439. data/lib/pubid/bsi/scheme.rb +0 -243
  440. data/lib/pubid/ccsds/scheme.rb +0 -57
  441. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  442. data/lib/pubid/cie/scheme.rb +0 -64
  443. data/lib/pubid/components/factory.rb +0 -50
  444. data/lib/pubid/csa/scheme.rb +0 -44
  445. data/lib/pubid/etsi/scheme.rb +0 -42
  446. data/lib/pubid/export/data_class_exporter.rb +0 -59
  447. data/lib/pubid/export/ieee_exporter.rb +0 -78
  448. data/lib/pubid/export/itu_exporter.rb +0 -66
  449. data/lib/pubid/export/nist_exporter.rb +0 -64
  450. data/lib/pubid/export/registry_exporter.rb +0 -90
  451. data/lib/pubid/export/scheme_exporter.rb +0 -70
  452. data/lib/pubid/identifier_registry.rb +0 -198
  453. data/lib/pubid/idf/scheme.rb +0 -61
  454. data/lib/pubid/iec/scheme.rb +0 -71
  455. data/lib/pubid/ieee/scheme.rb +0 -90
  456. data/lib/pubid/iho/scheme.rb +0 -29
  457. data/lib/pubid/iso/identifiers/base.rb +0 -115
  458. data/lib/pubid/iso/scheme.rb +0 -193
  459. data/lib/pubid/itu/scheme.rb +0 -174
  460. data/lib/pubid/jcgm/scheme.rb +0 -60
  461. data/lib/pubid/jis/components/code.rb +0 -59
  462. data/lib/pubid/jis/identifiers/base.rb +0 -72
  463. data/lib/pubid/jis/scheme.rb +0 -49
  464. data/lib/pubid/nist/components/publisher.rb +0 -24
  465. data/lib/pubid/nist/scheme.rb +0 -199
  466. data/lib/pubid/oiml/identifiers/base.rb +0 -36
  467. data/lib/pubid/oiml/scheme.rb +0 -46
  468. data/lib/pubid/plateau/scheme.rb +0 -45
  469. data/lib/pubid/rendering/base.rb +0 -73
  470. data/lib/pubid/rendering/common.rb +0 -211
  471. data/lib/pubid/rendering/format.rb +0 -25
  472. data/lib/pubid/sae/scheme.rb +0 -47
  473. data/lib/pubid/scheme.rb +0 -219
@@ -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
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Pubid
4
4
  module Csa
5
- class SingleIdentifier < Pubid::Identifier
5
+ class SingleIdentifier < Identifier
6
6
  # Generate URN for this identifier
7
7
  #
8
8
  # @return [String] URN representation
@@ -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,16 +6,57 @@ 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"
15
16
 
16
17
  def self.parse(identifier_string)
18
+ if identifier_string.length > Pubid::MAX_INPUT_LENGTH
19
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
20
+ end
21
+
17
22
  Identifier.parse(identifier_string)
18
23
  end
24
+
25
+ # Auto-discover all identifier types from the Identifiers namespace
26
+ # @return [Array<Class>] identifier classes that define a self.type Hash
27
+ def self.identifier_types
28
+ @identifier_types ||= Identifiers.constants
29
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
30
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
31
+ .select { |c| c.type.is_a?(Hash) }
32
+ end
33
+
34
+ # Build typed stage index from identifier types
35
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
36
+ def self.all_typed_stages
37
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
38
+ if klass.const_defined?(:TYPED_STAGES)
39
+ klass.const_get(:TYPED_STAGES)
40
+ else
41
+ []
42
+ end
43
+ end
44
+ end
45
+
46
+ # Lookup: type code -> identifier class
47
+ # @param code [String, Symbol] the type key to find
48
+ # @return [Class, nil] the matching identifier class
49
+ def self.locate_type(code)
50
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
51
+ end
52
+
53
+ # Lookup: abbreviation -> typed stage
54
+ # @param abbr [String, Symbol] the abbreviation to find
55
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
56
+ def self.locate_stage(abbr)
57
+ abbr_str = abbr.to_s.upcase
58
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
59
+ end
19
60
  end
20
61
 
21
62
  # Register this flavor with the Pubid registry
@@ -23,3 +64,7 @@ end
23
64
 
24
65
  # Register Ucsa flavor with the registry
25
66
  Pubid::Registry.register(:csa, Pubid::Csa)
67
+
68
+ # Per-flavor format registry: inherits global formats, overrides :human
69
+ Pubid::Csa::SingleIdentifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
70
+ Pubid::Csa::SingleIdentifier.format_registry.register(:human, renderer: Pubid::Csa::Renderer)
@@ -10,16 +10,13 @@ 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
16
- attribute :parts, :string, collection: true # Parts array
17
-
18
- def initialize(number:, minor: nil, parts: nil)
19
- @number = number
20
- @minor = minor
21
- @parts = parts || []
22
- end
17
+ attribute :number, :string # Main number
18
+ attribute :minor, :string # Optional minor part
19
+ attribute :parts, :string, collection: true, default: [] # Parts array
23
20
 
24
21
  # Render code with space for minor and dash-separated parts
25
22
  def to_s
@@ -29,6 +26,10 @@ module Pubid
29
26
  result
30
27
  end
31
28
 
29
+ def render(context: nil)
30
+ to_s
31
+ end
32
+
32
33
  def ==(other)
33
34
  return false unless other.is_a?(Code)
34
35
 
@@ -13,11 +13,6 @@ module Pubid
13
13
  false
14
14
  } # true for ed.N format
15
15
 
16
- def initialize(version:, is_edition: false)
17
- @version = version
18
- @is_edition = is_edition
19
- end
20
-
21
16
  def to_s
22
17
  if is_edition
23
18
  "ed.#{version}"
@@ -1,57 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Pubid
4
- module Etsi
5
- class Identifier
6
- def self.parse(identifier)
7
- parsed = Parser.parse(identifier)
8
- Builder.build(parsed)
9
- rescue Parslet::ParseFailed => e
10
- raise "Failed to parse ETSI identifier '#{identifier}': #{e.message}"
11
- end
12
-
13
- # Factory mirroring pubid 1.x's `Pubid::Etsi::Identifier.create` API.
14
- #
15
- # ETSI's `type` kwarg (EN, ES, EG, TS, TR, GS, GR, GTS, …) is data
16
- # stored on the identifier instance, not a class-dispatch key — all
17
- # ETSI standards share the {Identifiers::EtsiStandard} class.
18
- #
19
- # @param opts [Hash] :type, :code/:number, :parts, :version, :year,
20
- # :month, :date
21
- def self.create(**opts)
22
- Identifiers::EtsiStandard.new(**coerce_create_attrs(opts))
23
- end
24
-
25
- def self.coerce_create_attrs(opts)
26
- attrs = {}
27
- attrs[:type] = opts[:type].to_s if opts[:type]
28
-
29
- code_value = opts[:code] || opts[:number]
30
- if code_value
31
- attrs[:code] = Pubid::Etsi::Components::Code.new(
32
- number: code_value.to_s,
33
- parts: opts[:parts] ? Array(opts[:parts]).map(&:to_s) : nil,
34
- )
35
- end
36
-
37
- if (v = opts[:version])
38
- attrs[:version] = Pubid::Etsi::Components::Version.new(
39
- version: v.to_s,
40
- )
41
- end
42
-
43
- if opts[:year] || opts[:month]
44
- attrs[:date] = ::Pubid::Components::Date.new(
45
- year: opts[:year]&.to_s,
46
- month: opts[:month]&.to_s,
47
- )
48
- end
49
-
50
- # TODO(create-shim): Amendment and Corrigendum supplements need a
51
- # base_identifier and aren't yet wired through.
52
- attrs
53
- end
54
- private_class_method :coerce_create_attrs
55
- end
56
- end
57
- end
3
+ # Pubid::Etsi::Identifier is the ETSI base class (a real Pubid::Identifier
4
+ # subclass); its body, `.parse`, and the Identifiers::Base back-compat alias
5
+ # live in identifiers/base.rb. This file just ensures it is loaded.
6
+ require_relative "identifiers/base"
@@ -2,37 +2,41 @@
2
2
 
3
3
  module Pubid
4
4
  module Etsi
5
- module Identifiers
6
- # Base class for all ETSI identifiers
7
- class Base < Pubid::Identifier
8
- # Generate URN for this identifier
9
- #
10
- # @return [String] URN representation
11
- attribute :type, :string
12
- attribute :code, Pubid::Etsi::Components::Code
13
- attribute :version, Pubid::Etsi::Components::Version
14
- attribute :date, Pubid::Components::Date
15
-
16
- def publisher
17
- "ETSI"
18
- end
5
+ # Base class for all ETSI identifiers. Canonical name Pubid::Etsi::Identifier
6
+ # (Identifiers::Base is a back-compat alias); every concrete ETSI identifier
7
+ # descends from it.
8
+ class Identifier < ::Pubid::Identifier
9
+ def self.parse(identifier)
10
+ parsed = Parser.parse(identifier)
11
+ Builder.build(parsed)
12
+ rescue Parslet::ParseFailed => e
13
+ raise "Failed to parse ETSI identifier '#{identifier}': #{e.message}"
14
+ end
19
15
 
20
- def to_s
21
- result = "#{publisher} #{type} #{code}"
22
- result += " #{version} (#{date.year}-#{date.month.to_s.rjust(2,
23
- '0')})"
24
- result
25
- end
16
+ attribute :type, :string
17
+ attribute :code, Pubid::Etsi::Components::Code
18
+ attribute :version, Pubid::Etsi::Components::Version
19
+ attribute :date, Pubid::Components::Date
20
+ # Stored as a plain string (always "ETSI") so it round-trips through
21
+ # to_hash/from_hash. Was previously a `def publisher` method, which made
22
+ # lutaml serialize a String against the Components::Publisher attribute and
23
+ # raise on to_hash.
24
+ attribute :publisher, :string, default: -> { "ETSI" }
26
25
 
27
- def ==(other)
28
- return false unless other.is_a?(Base)
26
+ def ==(other)
27
+ return false unless other.is_a?(Pubid::Etsi::Identifier)
29
28
 
30
- type == other.type &&
31
- code == other.code &&
32
- version == other.version &&
33
- date == other.date
34
- end
29
+ type == other.type &&
30
+ code == other.code &&
31
+ version == other.version &&
32
+ date == other.date
35
33
  end
36
34
  end
35
+
36
+ module Identifiers
37
+ # Backward-compatible alias: ETSI's base class used to be
38
+ # Pubid::Etsi::Identifiers::Base. It is now Pubid::Etsi::Identifier.
39
+ Base = Pubid::Etsi::Identifier
40
+ end
37
41
  end
38
42
  end
@@ -25,17 +25,7 @@ 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
30
- 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
- )})"
38
- end
28
+ # Render via renderer
39
29
 
40
30
  # Recursively collect supplement notations from the supplement chain
41
31
  def collect_supplement_notations(current_supplement, notations)
@@ -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