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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -39
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -43
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -51
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -39
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifier.rb +0 -46
  55. data/lib/pubid/asme/identifiers/base.rb +0 -60
  56. data/lib/pubid/asme/renderer.rb +66 -0
  57. data/lib/pubid/asme/urn_parser.rb +31 -0
  58. data/lib/pubid/asme.rb +42 -1
  59. data/lib/pubid/astm/components/code.rb +9 -0
  60. data/lib/pubid/{jis → astm}/components.rb +1 -1
  61. data/lib/pubid/astm/identifier.rb +0 -77
  62. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  63. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  64. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  65. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  66. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  67. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  68. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  69. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  70. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  71. data/lib/pubid/astm/identifiers.rb +18 -0
  72. data/lib/pubid/astm/renderer.rb +172 -0
  73. data/lib/pubid/astm/single_identifier.rb +0 -10
  74. data/lib/pubid/astm/urn_parser.rb +30 -0
  75. data/lib/pubid/astm.rb +39 -27
  76. data/lib/pubid/bsi/builder.rb +21 -12
  77. data/lib/pubid/bsi/identifier.rb +8 -62
  78. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  79. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  80. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  81. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  82. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  84. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  87. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  88. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  89. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  90. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  91. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  92. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  93. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  94. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  95. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  96. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  97. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  98. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  99. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  100. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  101. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  102. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  103. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  104. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  105. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  106. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  107. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  108. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  109. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  110. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  111. data/lib/pubid/bsi/identifiers.rb +0 -1
  112. data/lib/pubid/bsi/renderer.rb +1050 -0
  113. data/lib/pubid/bsi/single_identifier.rb +6 -70
  114. data/lib/pubid/bsi/urn_generator.rb +2 -3
  115. data/lib/pubid/bsi/urn_parser.rb +52 -0
  116. data/lib/pubid/bsi.rb +224 -1
  117. data/lib/pubid/builder/base.rb +57 -10
  118. data/lib/pubid/bundled_identifier.rb +0 -1
  119. data/lib/pubid/ccsds/builder.rb +4 -3
  120. data/lib/pubid/ccsds/identifier.rb +63 -66
  121. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  122. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  123. data/lib/pubid/ccsds/parser.rb +4 -2
  124. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  125. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  126. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  127. data/lib/pubid/ccsds.rb +39 -1
  128. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  129. data/lib/pubid/cen_cenelec/identifier.rb +7 -38
  130. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  131. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  132. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  133. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  135. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  136. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  137. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  139. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  140. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  141. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  143. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  145. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  146. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  147. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  148. data/lib/pubid/cen_cenelec.rb +168 -1
  149. data/lib/pubid/cie/components/code.rb +8 -0
  150. data/lib/pubid/cie/identifier.rb +6 -57
  151. data/lib/pubid/cie/urn_parser.rb +28 -0
  152. data/lib/pubid/cie.rb +43 -1
  153. data/lib/pubid/components/adoption.rb +104 -0
  154. data/lib/pubid/components/code.rb +22 -8
  155. data/lib/pubid/components/date.rb +23 -16
  156. data/lib/pubid/components/edition.rb +9 -6
  157. data/lib/pubid/components/iteration.rb +32 -0
  158. data/lib/pubid/components/language.rb +6 -4
  159. data/lib/pubid/components/locality.rb +10 -1
  160. data/lib/pubid/components/publisher.rb +9 -6
  161. data/lib/pubid/components/relationship.rb +151 -0
  162. data/lib/pubid/components/stage.rb +5 -14
  163. data/lib/pubid/components/supplement.rb +184 -0
  164. data/lib/pubid/components/type.rb +5 -15
  165. data/lib/pubid/components/typed_stage.rb +10 -11
  166. data/lib/pubid/components.rb +4 -1
  167. data/lib/pubid/core/update_codes.rb +28 -7
  168. data/lib/pubid/csa/identifier.rb +0 -59
  169. data/lib/pubid/csa/identifiers/base.rb +2 -122
  170. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  171. data/lib/pubid/csa/identifiers/series.rb +2 -102
  172. data/lib/pubid/csa/renderer.rb +292 -0
  173. data/lib/pubid/csa/urn_generator.rb +1 -1
  174. data/lib/pubid/csa/urn_parser.rb +33 -0
  175. data/lib/pubid/csa.rb +42 -1
  176. data/lib/pubid/etsi/components/code.rb +9 -2
  177. data/lib/pubid/etsi/identifier.rb +0 -43
  178. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  179. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  180. data/lib/pubid/etsi/renderer.rb +42 -0
  181. data/lib/pubid/etsi/urn_parser.rb +34 -0
  182. data/lib/pubid/etsi.rb +42 -1
  183. data/lib/pubid/export/exporter.rb +4 -46
  184. data/lib/pubid/export/flavor_exporter.rb +111 -278
  185. data/lib/pubid/export.rb +0 -6
  186. data/lib/pubid/identifier.rb +2 -17
  187. data/lib/pubid/identifier_facade.rb +114 -0
  188. data/lib/pubid/identifier_metadata.rb +1 -1
  189. data/lib/pubid/idf/builder.rb +3 -3
  190. data/lib/pubid/idf/identifier.rb +3 -66
  191. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  192. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  193. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  194. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  195. data/lib/pubid/idf/parser.rb +3 -2
  196. data/lib/pubid/idf/renderer.rb +84 -0
  197. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  198. data/lib/pubid/idf/urn_generator.rb +4 -39
  199. data/lib/pubid/idf/urn_parser.rb +25 -0
  200. data/lib/pubid/idf.rb +51 -1
  201. data/lib/pubid/iec/builder.rb +46 -64
  202. data/lib/pubid/iec/components/code.rb +8 -32
  203. data/lib/pubid/iec/components/publisher.rb +0 -1
  204. data/lib/pubid/iec/components.rb +14 -0
  205. data/lib/pubid/iec/identifier.rb +251 -213
  206. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  207. data/lib/pubid/iec/identifiers/base.rb +8 -32
  208. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  209. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  210. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -26
  211. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  212. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -22
  213. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  214. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  215. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  216. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  217. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  218. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -11
  219. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  220. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  222. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  223. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  224. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  225. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -19
  226. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  227. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  228. data/lib/pubid/iec/identifiers.rb +30 -0
  229. data/lib/pubid/iec/parser.rb +13 -12
  230. data/lib/pubid/iec/renderer.rb +254 -0
  231. data/lib/pubid/iec/single_identifier.rb +6 -12
  232. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  233. data/lib/pubid/iec/urn_generator.rb +3 -3
  234. data/lib/pubid/iec/urn_parser.rb +3 -3
  235. data/lib/pubid/iec.rb +40 -68
  236. data/lib/pubid/ieee/builder.rb +12 -12
  237. data/lib/pubid/ieee/components/code.rb +8 -0
  238. data/lib/pubid/ieee/components/draft.rb +14 -0
  239. data/lib/pubid/ieee/components/relationship.rb +5 -149
  240. data/lib/pubid/ieee/identifier.rb +6 -41
  241. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  242. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  243. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  245. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  246. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  247. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  248. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  249. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  250. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  251. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  256. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  257. data/lib/pubid/ieee/pre_parser.rb +301 -0
  258. data/lib/pubid/ieee/renderer.rb +307 -0
  259. data/lib/pubid/ieee/urn_parser.rb +34 -0
  260. data/lib/pubid/ieee.rb +62 -1
  261. data/lib/pubid/ieee_debug.rb +0 -1
  262. data/lib/pubid/iho/builder.rb +2 -2
  263. data/lib/pubid/iho/identifier.rb +8 -42
  264. data/lib/pubid/iho/identifiers/base.rb +49 -10
  265. data/lib/pubid/iho/parser.rb +3 -3
  266. data/lib/pubid/iho/renderer.rb +30 -0
  267. data/lib/pubid/iho/urn_generator.rb +2 -2
  268. data/lib/pubid/iho/urn_parser.rb +58 -0
  269. data/lib/pubid/iho.rb +50 -1
  270. data/lib/pubid/iso/builder.rb +55 -53
  271. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  272. data/lib/pubid/iso/components/code.rb +7 -19
  273. data/lib/pubid/iso/components/publisher.rb +10 -8
  274. data/lib/pubid/iso/components.rb +2 -4
  275. data/lib/pubid/iso/identifier.rb +218 -252
  276. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  277. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  278. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  279. data/lib/pubid/iso/identifiers/data.rb +0 -1
  280. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  281. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  282. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  283. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  284. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  285. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  286. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  287. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  288. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  289. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  290. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  291. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  292. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  293. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  294. data/lib/pubid/iso/identifiers.rb +0 -1
  295. data/lib/pubid/iso/normalizer.rb +89 -0
  296. data/lib/pubid/iso/parser.rb +22 -4
  297. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  298. data/lib/pubid/iso/urn_generator.rb +66 -182
  299. data/lib/pubid/iso/urn_parser.rb +12 -7
  300. data/lib/pubid/iso.rb +173 -2
  301. data/lib/pubid/itu/builder.rb +0 -12
  302. data/lib/pubid/itu/components/code.rb +8 -0
  303. data/lib/pubid/itu/components.rb +11 -0
  304. data/lib/pubid/itu/identifier.rb +6 -104
  305. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  306. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  307. data/lib/pubid/itu/identifiers/base.rb +0 -6
  308. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  309. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  310. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  311. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  312. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  313. data/lib/pubid/itu/urn_parser.rb +23 -0
  314. data/lib/pubid/itu.rb +42 -1
  315. data/lib/pubid/jcgm/builder.rb +16 -8
  316. data/lib/pubid/jcgm/identifier.rb +0 -43
  317. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  318. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  319. data/lib/pubid/jcgm/renderer.rb +68 -0
  320. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  321. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  322. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  323. data/lib/pubid/jcgm.rb +43 -2
  324. data/lib/pubid/jis/builder.rb +44 -52
  325. data/lib/pubid/jis/identifier.rb +132 -46
  326. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  327. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  328. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  329. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  330. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  331. data/lib/pubid/jis/identifiers.rb +1 -1
  332. data/lib/pubid/jis/parser.rb +31 -5
  333. data/lib/pubid/jis/renderer.rb +69 -0
  334. data/lib/pubid/jis/single_identifier.rb +6 -12
  335. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  336. data/lib/pubid/jis/urn_parser.rb +23 -0
  337. data/lib/pubid/jis.rb +42 -2
  338. data/lib/pubid/nist/builder.rb +63 -1871
  339. data/lib/pubid/nist/caster.rb +1272 -0
  340. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  341. data/lib/pubid/nist/components/code.rb +9 -20
  342. data/lib/pubid/nist/components/supplement.rb +2 -2
  343. data/lib/pubid/nist/components.rb +0 -1
  344. data/lib/pubid/nist/identifier.rb +11 -48
  345. data/lib/pubid/nist/identifiers/base.rb +110 -47
  346. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  347. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  348. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  349. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  350. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  351. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  352. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  353. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  354. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  355. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  356. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  357. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  358. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  359. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  360. data/lib/pubid/nist/identifiers/report.rb +4 -2
  361. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  362. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  363. data/lib/pubid/nist/identifiers.rb +1 -0
  364. data/lib/pubid/nist/parser.rb +62 -452
  365. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  366. data/lib/pubid/nist/preprocessor.rb +416 -0
  367. data/lib/pubid/nist/renderer.rb +43 -0
  368. data/lib/pubid/nist/router.rb +148 -0
  369. data/lib/pubid/nist/series/base.rb +58 -0
  370. data/lib/pubid/nist/series/crpl.rb +13 -0
  371. data/lib/pubid/nist/series/fips.rb +14 -0
  372. data/lib/pubid/nist/series/ir.rb +60 -0
  373. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  374. data/lib/pubid/nist/series/mono.rb +19 -0
  375. data/lib/pubid/nist/series/ncstar.rb +20 -0
  376. data/lib/pubid/nist/series.rb +49 -0
  377. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  378. data/lib/pubid/nist/urn_parser.rb +67 -0
  379. data/lib/pubid/nist.rb +82 -4
  380. data/lib/pubid/oiml/components/code.rb +10 -0
  381. data/lib/pubid/oiml/identifier.rb +0 -50
  382. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  383. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  384. data/lib/pubid/oiml/renderer.rb +161 -0
  385. data/lib/pubid/oiml/single_identifier.rb +6 -45
  386. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  387. data/lib/pubid/oiml/urn_generator.rb +0 -8
  388. data/lib/pubid/oiml/urn_parser.rb +22 -0
  389. data/lib/pubid/oiml.rb +42 -1
  390. data/lib/pubid/plateau/identifier.rb +7 -41
  391. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  392. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  393. data/lib/pubid/plateau/renderer.rb +51 -0
  394. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  395. data/lib/pubid/plateau/urn_parser.rb +43 -0
  396. data/lib/pubid/plateau.rb +43 -1
  397. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  398. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  399. data/lib/pubid/renderers/human_readable.rb +18 -7
  400. data/lib/pubid/rendering/context.rb +28 -19
  401. data/lib/pubid/rendering.rb +0 -3
  402. data/lib/pubid/sae/components/date.rb +8 -0
  403. data/lib/pubid/sae/components/type.rb +5 -1
  404. data/lib/pubid/sae/identifier.rb +0 -23
  405. data/lib/pubid/sae/identifiers/base.rb +2 -16
  406. data/lib/pubid/sae/renderer.rb +36 -0
  407. data/lib/pubid/sae/urn_generator.rb +2 -10
  408. data/lib/pubid/sae/urn_parser.rb +36 -0
  409. data/lib/pubid/sae.rb +42 -1
  410. data/lib/pubid/urn_generator/base.rb +12 -12
  411. data/lib/pubid/urn_parser/base.rb +81 -0
  412. data/lib/pubid/urn_parser/errors.rb +9 -0
  413. data/lib/pubid/urn_parser.rb +14 -0
  414. data/lib/pubid/version.rb +1 -1
  415. data/lib/pubid.rb +29 -7
  416. data/lib/tasks/website-data.json +1940 -1882
  417. metadata +75 -44
  418. data/lib/pubid/amca/scheme.rb +0 -16
  419. data/lib/pubid/ansi/scheme.rb +0 -15
  420. data/lib/pubid/api/scheme.rb +0 -66
  421. data/lib/pubid/ashrae/scheme.rb +0 -53
  422. data/lib/pubid/asme/scheme.rb +0 -37
  423. data/lib/pubid/astm/scheme.rb +0 -55
  424. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  425. data/lib/pubid/bsi/scheme.rb +0 -243
  426. data/lib/pubid/ccsds/scheme.rb +0 -57
  427. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  428. data/lib/pubid/cie/scheme.rb +0 -64
  429. data/lib/pubid/components/factory.rb +0 -50
  430. data/lib/pubid/csa/scheme.rb +0 -44
  431. data/lib/pubid/etsi/scheme.rb +0 -42
  432. data/lib/pubid/export/data_class_exporter.rb +0 -59
  433. data/lib/pubid/export/ieee_exporter.rb +0 -78
  434. data/lib/pubid/export/itu_exporter.rb +0 -66
  435. data/lib/pubid/export/nist_exporter.rb +0 -64
  436. data/lib/pubid/export/registry_exporter.rb +0 -90
  437. data/lib/pubid/export/scheme_exporter.rb +0 -70
  438. data/lib/pubid/identifier_registry.rb +0 -198
  439. data/lib/pubid/idf/scheme.rb +0 -61
  440. data/lib/pubid/iec/scheme.rb +0 -71
  441. data/lib/pubid/ieee/scheme.rb +0 -90
  442. data/lib/pubid/iho/scheme.rb +0 -29
  443. data/lib/pubid/iso/identifiers/base.rb +0 -115
  444. data/lib/pubid/iso/scheme.rb +0 -193
  445. data/lib/pubid/itu/scheme.rb +0 -174
  446. data/lib/pubid/jcgm/scheme.rb +0 -60
  447. data/lib/pubid/jis/components/code.rb +0 -59
  448. data/lib/pubid/jis/identifiers/base.rb +0 -72
  449. data/lib/pubid/jis/scheme.rb +0 -49
  450. data/lib/pubid/nist/components/publisher.rb +0 -24
  451. data/lib/pubid/nist/scheme.rb +0 -199
  452. data/lib/pubid/oiml/scheme.rb +0 -46
  453. data/lib/pubid/plateau/scheme.rb +0 -45
  454. data/lib/pubid/rendering/base.rb +0 -73
  455. data/lib/pubid/rendering/common.rb +0 -211
  456. data/lib/pubid/rendering/format.rb +0 -25
  457. data/lib/pubid/sae/scheme.rb +0 -47
  458. data/lib/pubid/scheme.rb +0 -219
@@ -9,10 +9,19 @@ module Pubid
9
9
 
10
10
  DASH_CHARS = ["-", "‑", "‐"].freeze
11
11
 
12
+ # Supplement identifier type keys (kept as a hard-coded list to match
13
+ # the previous identifier split; only the base identifier registry
14
+ # is auto-discovered from the Identifiers namespace).
15
+ SUPPLEMENT_TYPE_KEYS = %i[amd cor suppl ext add].freeze
16
+
12
17
  # We need to sort by length to match longest first because that's how Parslet works
13
- TYPED_STAGES = Pubid::Iso::Scheme.typed_stages
18
+ TYPED_STAGES = Pubid::Iso.identifier_types
19
+ .reject { |k| SUPPLEMENT_TYPE_KEYS.include?(k.type[:key]) }
20
+ .flat_map { |k| k.const_defined?(:TYPED_STAGES) ? k.const_get(:TYPED_STAGES) : [] }
14
21
  .map(&:abbr).flatten.sort_by(&:length).reverse
15
- TYPED_STAGES_SUPPLEMENTS = Pubid::Iso::Scheme.supplement_typed_stages
22
+ TYPED_STAGES_SUPPLEMENTS = Pubid::Iso.identifier_types
23
+ .select { |k| SUPPLEMENT_TYPE_KEYS.include?(k.type[:key]) }
24
+ .flat_map { |k| k.const_defined?(:TYPED_STAGES) ? k.const_get(:TYPED_STAGES) : [] }
16
25
  .map(&:abbr).flatten.sort_by(&:length).reverse
17
26
 
18
27
  root :identifier
@@ -66,7 +75,9 @@ module Pubid
66
75
  end
67
76
 
68
77
  rule(:sc_type) do
69
- str("SC").as(:sc_type)
78
+ # "SC" plus the "SC/QC" quality-committee variant
79
+ # (e.g. ISO/TC 184/SC/QC 4 N 246). Longest first for Parslet.
80
+ (str("SC/QC") | str("SC")).as(:sc_type)
70
81
  end
71
82
 
72
83
  rule(:wg_type) do
@@ -327,7 +338,9 @@ module Pubid
327
338
  rule(:supplement_identifier_no_third) do
328
339
  identifier_copublishers_no_third.as(:base_identifier) >>
329
340
  str("/") >> supplement_type_with_stage >>
330
- ((space? >> second_part) | (str(".") >> digits.as(:number)) | (space? >> date))
341
+ # The trailing number/date is optional: some draft supplements have no
342
+ # number yet, e.g. "ISO/IEC 9579/WD Amd".
343
+ ((space? >> second_part) | (str(".") >> digits.as(:number)) | (space? >> date)).maybe
331
344
  end
332
345
 
333
346
  rule(:supplement_identifier) do
@@ -383,6 +396,11 @@ module Pubid
383
396
  prefix_with_copublishers >> space? >>
384
397
  (directives_publisher_subgroup >> space).maybe >>
385
398
  array_to_str(DIRECTIVES_TYPED_STAGES).as(:type_with_stage) >>
399
+ # The subgroup may also follow the type, e.g. "ISO/IEC DIR JTC 1"
400
+ # (canonical form is "ISO/IEC JTC 1 DIR"). Guard against a trailing
401
+ # supplement, where "JTC 1" is the supplement publisher instead
402
+ # (e.g. "ISO/IEC DIR JTC 1 SUP").
403
+ (space >> directives_publisher_subgroup >> (space >> str("SUP")).absent?).maybe >>
386
404
  (
387
405
  (space >> directives_number_with_part).maybe >>
388
406
  (str(":") >> date).maybe
@@ -7,14 +7,27 @@ module Pubid
7
7
  polymorphic: true
8
8
 
9
9
  key_value do
10
- map "base_identifier", to: :base_identifier, polymorphic: {
10
+ # Serialized key is "base" (matches JIS); the attribute/method stays
11
+ # `base_identifier`, which relaton-index's get_id_number depends on.
12
+ map "base", to: :base_identifier, polymorphic: {
11
13
  attribute: "_type",
12
14
  class_map: Identifier::ISO_TYPE_MAP,
13
15
  }
14
16
  end
15
17
 
18
+ # A supplement carries the publisher/copublishers of the document it
19
+ # supplements. Delegate to the root rather than the immediate base so a
20
+ # nested supplement (e.g. ".../Amd 1/Cor 1") reads identity from the
21
+ # underlying standard in one hop, regardless of chain depth. This keeps a
22
+ # parsed supplement and a from_hash-deserialized one in agreement (== and
23
+ # index matching compare both). Guard on base_identifier: `root` returns
24
+ # self when there is no base, which would otherwise recurse forever.
16
25
  def publisher
17
- base_identifier&.publisher
26
+ root.publisher if base_identifier
27
+ end
28
+
29
+ def copublishers
30
+ root.copublishers if base_identifier
18
31
  end
19
32
 
20
33
  def to_s(**opts)
@@ -4,6 +4,9 @@ module Pubid
4
4
  module Iso
5
5
  # Generates RFC 5141-bis compliant URNs from ISO identifiers
6
6
  #
7
+ # Components render themselves via `component.render(context: URN_CONTEXT)`;
8
+ # this class orchestrates them into the URN string structure.
9
+ #
7
10
  # RFC 5141-bis extensions implemented:
8
11
  # - Explicit language specification (explicit > implicit)
9
12
  # - Extended copublisher syntax (dynamic combinations)
@@ -12,44 +15,39 @@ module Pubid
12
15
  # - Supplement chain ordering semantics
13
16
  # - Bundled identifier syntax
14
17
  class UrnGenerator
18
+ URN_CONTEXT = Rendering::RenderingContext.urn.freeze
19
+ private_constant :URN_CONTEXT
20
+
15
21
  # Stage code mapping for RFC 5141-bis typed stages
16
- # Maps TypedStage stage_code to URN stage abbreviation
17
22
  TYPED_STAGE_MAP = {
18
- wd: "WD", # Working Draft
19
- wds: "WDS", # Working Draft Study
20
- cd: "CD", # Committee Draft
21
- cdv: "CDV", # Committee Draft for Vote
22
- dis: "DIS", # Draft International Standard
23
- fdis: "FDIS", # Final Draft International Standard
24
- pdam: "PDAM", # Proposed Draft Amendment
25
- dam: "DAM", # Draft Amendment
26
- fdamd: "FDAM", # Final Draft Amendment (note: stage_code is fdamd)
27
- dcor: "DCOR", # Draft Corrigendum
28
- fdcor: "FDCOR", # Final Draft Corrigendum
29
- cdts: "CDTS", # Committee Draft Technical Specification
30
- dts: "DTS", # Draft Technical Specification
31
- fdts: "FDTS", # Final Draft Technical Specification
23
+ wd: "WD",
24
+ wds: "WDS",
25
+ cd: "CD",
26
+ cdv: "CDV",
27
+ dis: "DIS",
28
+ fdis: "FDIS",
29
+ pdam: "PDAM",
30
+ dam: "DAM",
31
+ fdamd: "FDAM",
32
+ dcor: "DCOR",
33
+ fdcor: "FDCOR",
34
+ cdts: "CDTS",
35
+ dts: "DTS",
36
+ fdts: "FDTS",
32
37
  }.freeze
33
38
 
34
- # Document type mapping for RFC 5141-bis extended types
35
39
  TYPE_CODE_MAP = {
36
- dir: "dir", # Directive
37
- dir_sup: "dir-sup", # Directive Supplement
38
- iwa_sup: "iwa-sup", # IWA Supplement
40
+ dir: "dir",
41
+ dir_sup: "dir-sup",
42
+ iwa_sup: "iwa-sup",
39
43
  }.freeze
40
44
 
41
45
  attr_reader :identifier
42
46
 
43
- # Initialize URN generator
44
- #
45
- # @param identifier [Identifier] The ISO identifier to generate URN for
46
47
  def initialize(identifier)
47
48
  @identifier = identifier
48
49
  end
49
50
 
50
- # Generate complete URN string
51
- #
52
- # @return [String] The URN in format urn:iso:std:...
53
51
  def generate
54
52
  if identifier.is_a?(SupplementIdentifier)
55
53
  generate_supplement_urn
@@ -60,115 +58,63 @@ module Pubid
60
58
 
61
59
  protected
62
60
 
63
- # Generate URN for base identifier (SingleIdentifier)
64
61
  def generate_base_urn
65
62
  parts = ["urn", "iso", "std"]
66
-
67
- # Publisher (lowercase, hyphen-separated)
68
63
  parts << originator_component
69
-
70
- # Type (for non-IS types like TR, TS, Guide)
71
64
  type_comp = type_component
72
65
  parts << type_comp if type_comp
73
-
74
- # Number
75
- parts << identifier.number.value if identifier.number
76
-
77
- # Part (with colon-dash prefix)
66
+ parts << identifier.number.render(context: URN_CONTEXT) if identifier.number
78
67
  part_comp = part_component
79
68
  parts << part_comp if part_comp
80
-
81
- # Stage (only for non-published documents); an all-parts series
82
- # reference carries no specific stage.
83
69
  stage_comp = stage_component
84
70
  parts << stage_comp if stage_comp && !identifier.all_parts
85
-
86
- # Year (for published documents and when edition is present)
87
71
  year_comp = year_component
88
72
  parts << year_comp if year_comp
89
-
90
- # Edition
91
73
  edition_comp = edition_component
92
74
  parts << edition_comp if edition_comp
93
-
94
- # Language (RFC 5141-bis: explicit specification)
95
75
  lang_comp = language_component
96
76
  parts << lang_comp if lang_comp
97
-
98
- # Series suffix for all-parts identifiers (compact, no padding)
99
77
  parts << "ser" if identifier.all_parts
100
-
101
78
  parts.join(":")
102
79
  end
103
80
 
104
- # Generate URN for supplement identifier
105
- # Handles multi-level supplements by walking up the chain
106
81
  def generate_supplement_urn
107
- # Walk up supplement chain to collect all supplements
108
82
  current = identifier
109
83
  supplement_chain = []
110
84
 
111
85
  while current.is_a?(SupplementIdentifier)
112
- supplement_chain.unshift(current) # Add to front (reverse order)
86
+ supplement_chain.unshift(current)
113
87
  current = current.base_identifier
114
88
  end
115
89
 
116
- # Now 'current' is the base document (not a supplement)
117
90
  base_id = current
118
-
119
- # Build URN from base identifier
120
91
  parts = ["urn", "iso", "std"]
121
92
 
122
93
  if base_id
123
94
  base_gen = self.class.new(base_id)
124
-
125
- # Publisher
126
95
  parts << base_gen.originator_component
127
-
128
- # Type (for non-IS types like TR, TS, Guide)
129
96
  type_comp = base_gen.type_component
130
97
  parts << type_comp if type_comp
131
-
132
- # Number
133
- parts << base_id.number.value if base_id.number
134
-
135
- # Part
98
+ parts << base_id.number.render(context: URN_CONTEXT) if base_id.number
136
99
  part_comp = base_gen.part_component
137
100
  parts << part_comp if part_comp
138
101
 
139
- # Collect ALL editions (base + supplements) and add them here
140
- # This ensures editions come before all supplement chains
141
102
  all_editions = []
142
-
143
- # Base edition first
144
103
  edition_comp = base_gen.edition_component
145
104
  all_editions << edition_comp if edition_comp
146
-
147
- # Then supplement editions
148
105
  supplement_chain.each do |supp|
149
106
  if supp.edition&.number
150
- all_editions << "ed-#{supp.edition.number}"
107
+ all_editions << supp.edition.render(context: URN_CONTEXT)
151
108
  end
152
109
  end
153
-
154
- # Add all editions to parts
155
110
  parts.concat(all_editions)
156
111
 
157
- # Base stage logic:
158
- # - Include if base is proposal stage (10.xx) and supplement has different stage
159
- # - Don't include if base is approval/publication stage (50.xx, 60.xx)
160
- # - Don't include if supplement has same stage as base
161
112
  base_stage_comp = base_gen.stage_component
162
113
  if base_stage_comp
163
- # Check if any supplement has a stage
164
114
  supplement_stages = supplement_chain.filter_map do |supp|
165
- supp_gen = self.class.new(supp)
166
- supp_gen.stage_component
115
+ self.class.new(supp).stage_component
167
116
  end
168
117
 
169
- # Only include base stage if:
170
- # 1. No supplements have a stage, OR
171
- # 2. Base is proposal stage (starts with "stage-10.") AND supplements don't duplicate it
172
118
  if supplement_stages.empty?
173
119
  parts << base_stage_comp
174
120
  elsif base_stage_comp.start_with?("stage-10.") && !supplement_stages.include?(base_stage_comp)
@@ -176,130 +122,96 @@ module Pubid
176
122
  end
177
123
  end
178
124
 
179
- # Base language (if present)
180
125
  if base_id.languages&.any?
181
- lang_comp = base_id.languages.map(&:code).join(",")
182
- parts << lang_comp
126
+ parts << language_segment(base_id.languages)
183
127
  end
184
128
  end
185
129
 
186
- # Now flatten all supplements in order
187
130
  supplement_chain.each do |supp|
188
131
  supp_gen = self.class.new(supp)
189
-
190
- # Supplement stage (for draft supplements)
191
- # Note: editions are added at base level, not here
192
132
  stage_comp = supp_gen.stage_component
193
133
  parts << stage_comp if stage_comp
194
-
195
- # Supplement type code (amd, cor, sup)
196
134
  suppl_type = supp_gen.supplement_type_component
197
135
  parts << suppl_type if suppl_type
198
136
 
199
- # Year and version (following RFC 5141-bis supplement semantics)
200
137
  if supp.date
201
- # With date: year:vN
202
- parts << supp.date.year.to_s
203
-
204
- # Version with "v" prefix
205
- # Amendments/Corrigenda keep iteration, generic Supplements don't
138
+ parts << supp.date.render(context: URN_CONTEXT)
206
139
  if supp.number
207
140
  if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
208
- parts << "v#{supp.number.value}.#{supp.stage_iteration.value}"
141
+ parts << "v#{supp.number.render(context: URN_CONTEXT)}.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
209
142
  else
210
- parts << "v#{supp.number.value}"
143
+ parts << "v#{supp.number.render(context: URN_CONTEXT)}"
211
144
  end
212
145
  end
213
146
  else
214
- # Without date: N:v1 (number directly, then "v1")
215
- if supp.number
216
- parts << supp.number.value
217
- end
218
-
219
- # Always add "v1" when no date
220
- # Amendments/Corrigenda keep iteration, generic Supplements don't
147
+ parts << supp.number.render(context: URN_CONTEXT) if supp.number
221
148
  if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
222
- parts << "v1.#{supp.stage_iteration.value}"
149
+ parts << "v1.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
223
150
  else
224
151
  parts << "v1"
225
152
  end
226
153
  end
227
154
 
228
- # Supplement language (RFC 5141-bis: explicit specification)
229
155
  if supp.languages&.any?
230
- lang_comp = supp.languages.map(&:code).join(",")
231
- parts << lang_comp
156
+ parts << language_segment(supp.languages)
232
157
  end
233
158
  end
234
159
 
235
- # Series suffix for all-parts identifiers (compact, no padding)
236
160
  parts << "ser" if identifier.all_parts
237
-
238
161
  parts.join(":")
239
162
  end
240
163
 
241
- # Generate originator component (publisher with copublishers)
242
- # RFC 5141-bis: supports dynamic copublisher combinations
243
164
  def originator_component
244
- # For identifiers like IWA that don't render publisher, default to "iso"
245
165
  return "iso" unless identifier.publisher
246
166
 
247
167
  copubs = identifier.copublishers || []
248
-
249
- # Collect all publishers in order
250
168
  publishers = [identifier.publisher] + copubs
169
+ publishers.map { |p| p.render(context: URN_CONTEXT) }.join("-")
170
+ end
251
171
 
252
- # Convert to lowercase and join with hyphen
253
- # Keep original order (not alphabetical) for backward compatibility
254
- publishers.map(&:body).map(&:downcase).join("-")
172
+ def document_type_code
173
+ klass = identifier.class
174
+ if klass.respond_to?(:type) && klass.type.is_a?(Hash) && klass.type[:key]
175
+ klass.type[:key]
176
+ else
177
+ identifier.typed_stage&.type_code
178
+ end
255
179
  end
256
180
 
257
- # Generate type component
258
- # RFC 5141-bis: supports extended document types (dir, dir-sup, iwa-sup)
259
181
  def type_component
260
182
  return nil unless identifier.typed_stage
261
183
 
262
- type_code = identifier.typed_stage.type_code
263
- # International Standard is default (skip it)
184
+ type_code = document_type_code
264
185
  return nil if !type_code || type_code.to_s == "is"
265
186
 
266
- # Check for extended type codes first (RFC 5141-bis)
267
187
  type_code_sym = type_code.to_sym
268
188
  extended_type = TYPE_CODE_MAP[type_code_sym]
269
189
  return extended_type if extended_type
270
190
 
271
- # Use urn_type_code override if available (e.g., Recommendation uses 'r')
272
191
  urn_override = identifier.urn_type_code
273
192
  return urn_override if urn_override
274
193
 
275
- # Default: use type_code as-is (already a string)
276
194
  type_code.to_s
277
195
  end
278
196
 
279
- # Generate part component
280
197
  def part_component
281
198
  return nil unless identifier.part
282
199
 
283
- result = "-#{identifier.part.value}"
284
- result += "-#{identifier.subpart.value}" if identifier.subpart
200
+ result = "-#{identifier.part.render(context: URN_CONTEXT)}"
201
+ result += "-#{identifier.subpart.render(context: URN_CONTEXT)}" if identifier.subpart
285
202
  result
286
203
  end
287
204
 
288
- # Generate stage component
289
- # RFC 5141-bis: supports typed stage codes (WD, CD, DIS, FDIS, etc.)
290
205
  def stage_component
291
206
  return nil unless identifier.typed_stage
292
207
 
293
208
  stage_code = identifier.typed_stage.stage_code
294
209
  return nil if !stage_code || stage_code == :published
295
210
 
296
- # Try combined stage+type code first (e.g., "cdts" for CD+TS)
297
- # This handles typed stages where stage_code differs from the full typed stage code
298
211
  combined_key = nil
299
- if identifier.typed_stage.type_code &&
300
- identifier.typed_stage.type_code != "is" &&
301
- identifier.typed_stage.type_code.to_s != ""
302
- combined_key = :"#{stage_code}#{identifier.typed_stage.type_code}"
212
+ dtc = document_type_code&.to_s
213
+ if dtc && dtc != "is" && dtc != ""
214
+ combined_key = :"#{stage_code}#{dtc}"
303
215
  end
304
216
 
305
217
  stage_abbr = if combined_key && TYPED_STAGE_MAP.key?(combined_key)
@@ -309,111 +221,83 @@ module Pubid
309
221
  end
310
222
 
311
223
  if stage_abbr
312
-
313
- # Add iteration if present (no 'v' prefix for iterations)
314
224
  if identifier.stage_iteration
315
- return "#{stage_abbr}.#{identifier.stage_iteration.value}"
225
+ return "#{stage_abbr}.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
316
226
  end
317
227
 
318
228
  return stage_abbr
319
229
  end
320
230
 
321
- # Fallback: use harmonized stage codes for unmapped stages
322
- # This handles stages like PWI, NP, AWI, PRF that don't have typed abbreviations
323
231
  harmonized_codes = identifier.typed_stage.harmonized_stages
324
232
  return nil unless harmonized_codes&.any?
325
233
 
326
- # Use first harmonized code from the array
327
234
  harmonized_code = harmonized_codes.first
328
235
 
329
- # Skip published documents (60.00, 60.60) EXCEPT for PRF (Proof) stage
330
- # PRF is at 60.00 but should still be included in URNs
331
236
  if harmonized_code.start_with?("60.") && stage_code.to_s != "prf"
332
237
  return nil
333
238
  end
334
239
 
335
- # Format as stage-XX.XX
336
- # An iterated PRF (Proof) stage (e.g. "PRF TR 17716.2") renders as the
337
- # symbolic "draft" stage in the URN rather than its harmonized numeric
338
- # code; a plain PRF without an iteration keeps the harmonized code.
339
240
  stage_part = if stage_code.to_s == "prf" && identifier.stage_iteration
340
241
  "stage-draft"
341
242
  else
342
243
  "stage-#{harmonized_code}"
343
244
  end
344
245
 
345
- # For base identifiers (not supplements), include iteration in stage code
346
- # For supplements, iteration goes in the version part (v1.2)
347
246
  if identifier.stage_iteration && !identifier.is_a?(SupplementIdentifier)
348
- stage_part += ".v#{identifier.stage_iteration.value}"
247
+ stage_part += ".v#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
349
248
  end
350
249
 
351
250
  stage_part
352
251
  end
353
252
 
354
- # Generate edition component
355
253
  def edition_component
356
254
  return nil unless identifier.edition&.number
357
255
 
358
- "ed-#{identifier.edition.number}"
256
+ identifier.edition.render(context: URN_CONTEXT)
359
257
  end
360
258
 
361
- # Generate year component
362
259
  def year_component
363
- return nil unless identifier.date&.year
364
-
365
- # ISO base identifiers (SingleIdentifier) use undated URN format (no year)
366
- # Supplements include their own year in the supplement section
260
+ return nil unless identifier.date&.present?
367
261
  return nil if identifier.is_a?(Pubid::Iso::SingleIdentifier)
368
262
 
369
- identifier.date.year.to_s
263
+ identifier.date.render(context: URN_CONTEXT)
370
264
  end
371
265
 
372
- # Generate language component
373
- # RFC 5141-bis: explicit specification guidance (explicit > implicit)
374
- # URN spec: all values in lowercase
375
266
  def language_component
376
267
  return nil unless identifier.languages&.any?
377
268
 
378
- identifier.languages.map(&:code).map(&:downcase).join(",")
269
+ language_segment(identifier.languages)
270
+ end
271
+
272
+ def language_segment(languages)
273
+ languages.map { |l| l.render(context: URN_CONTEXT) }.join(",")
379
274
  end
380
275
 
381
- # Generate supplement type component
382
276
  def supplement_type_component
383
277
  return nil unless identifier.typed_stage
384
278
 
385
279
  urn_override = identifier.urn_supplement_type
386
280
  return urn_override if urn_override
387
281
 
388
- identifier.typed_stage.type_code.to_s
282
+ document_type_code.to_s
389
283
  end
390
284
 
391
- # Generate supplement year/version components
392
- # Returns array of parts to be joined with ":"
393
285
  def supplement_year_version_components
394
286
  parts = []
395
287
 
396
288
  if identifier.date
397
- # With year: year:version
398
- parts << identifier.date.year.to_s
399
-
400
- # Version number with "v" prefix
289
+ parts << identifier.date.render(context: URN_CONTEXT)
401
290
  if identifier.number
402
291
  parts << if identifier.stage_iteration
403
- "v#{identifier.number.value}.#{identifier.stage_iteration.value}"
292
+ "v#{identifier.number.render(context: URN_CONTEXT)}.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
404
293
  else
405
- "v#{identifier.number.value}"
294
+ "v#{identifier.number.render(context: URN_CONTEXT)}"
406
295
  end
407
296
  end
408
297
  else
409
- # Without year: number directly or "v1"
410
- if identifier.number
411
- parts << identifier.number.value
412
- end
413
-
414
- # Version with iteration if present
298
+ parts << identifier.number.render(context: URN_CONTEXT) if identifier.number
415
299
  parts << if identifier.stage_iteration
416
- "v1.#{identifier.stage_iteration.value}"
300
+ "v1.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
417
301
  else
418
302
  "v1"
419
303
  end
@@ -231,7 +231,7 @@ module Pubid
231
231
  # Used when URN doesn't specify a type code (defaults to IS)
232
232
  # Prefers the most specific (non-published) stage
233
233
  def scheme_is_typed_stage_by_harmonized(harmonized_code)
234
- candidates = Pubid::Iso::Scheme.instance.all_typed_stages.select do |ts|
234
+ candidates = Pubid::Iso.all_typed_stages.select do |ts|
235
235
  ts.type_code.to_s == "is" && ts.harmonized_stages&.include?(harmonized_code)
236
236
  end
237
237
 
@@ -336,6 +336,11 @@ module Pubid
336
336
  # Add type_with_stage if type_code is present
337
337
  if type_code && type_code != :is
338
338
  base_hash[:type_with_stage] = type_code.to_s.upcase
339
+ # Pin the document class to the explicit URN type token. The stage
340
+ # block below may overwrite :type_with_stage with the stage's abbr
341
+ # (e.g. "WDA" for 90.93, which only exists as an IS-typed stage), so
342
+ # the builder needs this hint to keep e.g. TR a TechnicalReport.
343
+ base_hash[:document_type] = type_code.to_s.upcase
339
344
  end
340
345
 
341
346
  # Add stage if present
@@ -348,9 +353,9 @@ module Pubid
348
353
  # The stage_from_abbr is the value from TYPED_STAGE_REVERSE_MAP
349
354
  # We need to find the reverse to get the original abbreviation
350
355
  abbr_str = TYPED_STAGE_REVERSE_MAP.key(stage_from_abbr)
351
- typed_stage = Scheme.locate_typed_stage_by_abbr(abbr_str) if abbr_str
356
+ typed_stage = Pubid::Iso.locate_stage(abbr_str) if abbr_str
352
357
  # If no exact match, fall back to stage_code lookup
353
- typed_stage ||= Scheme.locate_typed_stage_by_stage_code(stage_from_abbr)
358
+ typed_stage ||= Pubid::Iso.locate_stage_by_stage_code(stage_from_abbr)
354
359
  else
355
360
  # Stage came from a harmonized code (e.g., stage-20.20)
356
361
  # Look up by harmonized stage code
@@ -360,12 +365,12 @@ module Pubid
360
365
  end
361
366
 
362
367
  # Fall back to any typed stage if IS not found or type_code is specified
363
- typed_stage ||= Scheme.locate_typed_stage_by_harmonized_code(stage_code.to_s)
368
+ typed_stage ||= Pubid::Iso.locate_stage_by_harmonized_code(stage_code.to_s)
364
369
 
365
370
  # Special handling for stage "40.00": prefer DIS over FCD when parsing from URN
366
371
  # This is because FCD is a legacy stage that maps to DIS in URN format
367
372
  if stage_code.to_s == "40.00" && typed_stage && typed_stage.stage_code.to_s == "fcd"
368
- dis_stage = Scheme.instance.all_typed_stages.detect do |ts|
373
+ dis_stage = Pubid::Iso.all_typed_stages.detect do |ts|
369
374
  ts.stage_code.to_s == "dis" && ts.harmonized_stages&.include?("40.00")
370
375
  end
371
376
  typed_stage = dis_stage if dis_stage
@@ -395,7 +400,7 @@ module Pubid
395
400
  supp_hash = {}
396
401
 
397
402
  if supp[:stage]
398
- typed_stage = Scheme.locate_typed_stage_by_stage_code(supp[:stage])
403
+ typed_stage = Pubid::Iso.locate_stage_by_stage_code(supp[:stage])
399
404
  supp_hash[:type_with_stage] = if
400
405
  typed_stage
401
406
  typed_stage.abbr.is_a?(Array) ? typed_stage.abbr.first : typed_stage.abbr
@@ -429,7 +434,7 @@ typed_stage
429
434
  base_hash[:all_parts] = true if all_parts
430
435
 
431
436
  # Build the final identifier
432
- builder = Pubid::Iso::Builder.new(Pubid::Iso::Scheme.new)
437
+ builder = Pubid::Iso::Builder.new
433
438
  builder.build(base_hash)
434
439
  end
435
440
  end