pubid 2.0.0.pre.alpha.1 → 2.0.0.pre.alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +27 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -0
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -1
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -4
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -0
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifiers/base.rb +0 -60
  55. data/lib/pubid/asme/renderer.rb +66 -0
  56. data/lib/pubid/asme/urn_parser.rb +31 -0
  57. data/lib/pubid/asme.rb +42 -1
  58. data/lib/pubid/astm/components/code.rb +9 -0
  59. data/lib/pubid/{jis → astm}/components.rb +1 -1
  60. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  61. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  62. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  63. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  64. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  65. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  66. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  67. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  68. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  69. data/lib/pubid/astm/identifiers.rb +18 -0
  70. data/lib/pubid/astm/renderer.rb +172 -0
  71. data/lib/pubid/astm/single_identifier.rb +0 -10
  72. data/lib/pubid/astm/urn_parser.rb +30 -0
  73. data/lib/pubid/astm.rb +39 -27
  74. data/lib/pubid/bsi/builder.rb +21 -12
  75. data/lib/pubid/bsi/identifier.rb +8 -2
  76. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  77. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  78. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  79. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  80. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  81. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  82. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  83. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  84. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  85. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  87. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  88. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  89. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  90. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  91. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  92. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  93. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  94. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  95. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  96. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  97. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  98. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  99. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  100. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  101. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  102. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  103. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  104. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  105. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  106. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  107. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  108. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  109. data/lib/pubid/bsi/identifiers.rb +0 -1
  110. data/lib/pubid/bsi/renderer.rb +1050 -0
  111. data/lib/pubid/bsi/single_identifier.rb +6 -70
  112. data/lib/pubid/bsi/urn_generator.rb +2 -3
  113. data/lib/pubid/bsi/urn_parser.rb +52 -0
  114. data/lib/pubid/bsi.rb +224 -1
  115. data/lib/pubid/builder/base.rb +57 -10
  116. data/lib/pubid/bundled_identifier.rb +0 -1
  117. data/lib/pubid/ccsds/builder.rb +4 -3
  118. data/lib/pubid/ccsds/identifier.rb +66 -1
  119. data/lib/pubid/ccsds/identifiers/base.rb +11 -50
  120. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  121. data/lib/pubid/ccsds/parser.rb +4 -2
  122. data/lib/pubid/ccsds/single_identifier.rb +4 -1
  123. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  124. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  125. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  126. data/lib/pubid/ccsds.rb +39 -1
  127. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  128. data/lib/pubid/cen_cenelec/identifier.rb +8 -2
  129. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  130. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  131. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  132. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  133. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  135. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  136. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  137. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  138. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  140. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  141. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  143. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  144. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  145. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  146. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  147. data/lib/pubid/cen_cenelec.rb +168 -1
  148. data/lib/pubid/cie/components/code.rb +8 -0
  149. data/lib/pubid/cie/identifier.rb +6 -4
  150. data/lib/pubid/cie/urn_parser.rb +28 -0
  151. data/lib/pubid/cie.rb +43 -1
  152. data/lib/pubid/components/adoption.rb +104 -0
  153. data/lib/pubid/components/code.rb +22 -8
  154. data/lib/pubid/components/date.rb +23 -16
  155. data/lib/pubid/components/edition.rb +9 -6
  156. data/lib/pubid/components/iteration.rb +32 -0
  157. data/lib/pubid/components/language.rb +6 -4
  158. data/lib/pubid/components/locality.rb +10 -1
  159. data/lib/pubid/components/publisher.rb +9 -6
  160. data/lib/pubid/components/relationship.rb +151 -0
  161. data/lib/pubid/components/stage.rb +5 -14
  162. data/lib/pubid/components/supplement.rb +184 -0
  163. data/lib/pubid/components/type.rb +5 -15
  164. data/lib/pubid/components/typed_stage.rb +11 -8
  165. data/lib/pubid/components.rb +4 -0
  166. data/lib/pubid/core/update_codes.rb +28 -7
  167. data/lib/pubid/csa/identifier.rb +0 -3
  168. data/lib/pubid/csa/identifiers/base.rb +2 -122
  169. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  170. data/lib/pubid/csa/identifiers/series.rb +2 -102
  171. data/lib/pubid/csa/renderer.rb +292 -0
  172. data/lib/pubid/csa/urn_generator.rb +1 -1
  173. data/lib/pubid/csa/urn_parser.rb +33 -0
  174. data/lib/pubid/csa.rb +42 -1
  175. data/lib/pubid/etsi/components/code.rb +9 -2
  176. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  177. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  178. data/lib/pubid/etsi/renderer.rb +42 -0
  179. data/lib/pubid/etsi/urn_parser.rb +34 -0
  180. data/lib/pubid/etsi.rb +42 -1
  181. data/lib/pubid/export/exporter.rb +4 -46
  182. data/lib/pubid/export/flavor_exporter.rb +111 -278
  183. data/lib/pubid/export.rb +0 -6
  184. data/lib/pubid/identifier.rb +10 -18
  185. data/lib/pubid/identifier_facade.rb +114 -0
  186. data/lib/pubid/identifier_metadata.rb +1 -1
  187. data/lib/pubid/idf/builder.rb +3 -3
  188. data/lib/pubid/idf/identifier.rb +3 -6
  189. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  190. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  191. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  192. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  193. data/lib/pubid/idf/parser.rb +3 -2
  194. data/lib/pubid/idf/renderer.rb +84 -0
  195. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  196. data/lib/pubid/idf/urn_generator.rb +4 -39
  197. data/lib/pubid/idf/urn_parser.rb +25 -0
  198. data/lib/pubid/idf.rb +51 -1
  199. data/lib/pubid/iec/builder.rb +48 -65
  200. data/lib/pubid/iec/components/code.rb +9 -32
  201. data/lib/pubid/iec/components/publisher.rb +1 -1
  202. data/lib/pubid/iec/components.rb +14 -0
  203. data/lib/pubid/iec/identifier.rb +276 -3
  204. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  205. data/lib/pubid/iec/identifiers/base.rb +8 -28
  206. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  207. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  208. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -30
  209. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  210. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -26
  211. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  212. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  213. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  214. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  215. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  216. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -15
  217. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  218. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  219. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  220. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  222. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  223. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -23
  224. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  225. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  226. data/lib/pubid/iec/identifiers.rb +30 -0
  227. data/lib/pubid/iec/parser.rb +20 -14
  228. data/lib/pubid/iec/renderer.rb +254 -0
  229. data/lib/pubid/iec/single_identifier.rb +6 -12
  230. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  231. data/lib/pubid/iec/urn_generator.rb +57 -171
  232. data/lib/pubid/iec/urn_parser.rb +53 -252
  233. data/lib/pubid/iec.rb +40 -68
  234. data/lib/pubid/ieee/builder.rb +12 -12
  235. data/lib/pubid/ieee/components/code.rb +8 -0
  236. data/lib/pubid/ieee/components/draft.rb +14 -0
  237. data/lib/pubid/ieee/components/relationship.rb +5 -149
  238. data/lib/pubid/ieee/identifier.rb +6 -0
  239. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  240. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  241. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  242. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  243. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  246. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  247. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  248. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  249. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  250. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  251. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  252. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  253. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  254. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  255. data/lib/pubid/ieee/pre_parser.rb +301 -0
  256. data/lib/pubid/ieee/renderer.rb +307 -0
  257. data/lib/pubid/ieee/urn_parser.rb +34 -0
  258. data/lib/pubid/ieee.rb +62 -1
  259. data/lib/pubid/ieee_debug.rb +0 -1
  260. data/lib/pubid/iho/builder.rb +2 -2
  261. data/lib/pubid/iho/identifier.rb +8 -0
  262. data/lib/pubid/iho/identifiers/base.rb +49 -10
  263. data/lib/pubid/iho/identifiers/bibliographic.rb +0 -4
  264. data/lib/pubid/iho/identifiers/circular_letter.rb +0 -4
  265. data/lib/pubid/iho/identifiers/miscellaneous.rb +0 -4
  266. data/lib/pubid/iho/identifiers/publication.rb +0 -4
  267. data/lib/pubid/iho/identifiers/standard.rb +0 -4
  268. data/lib/pubid/iho/parser.rb +3 -3
  269. data/lib/pubid/iho/renderer.rb +30 -0
  270. data/lib/pubid/iho/urn_generator.rb +3 -3
  271. data/lib/pubid/iho/urn_parser.rb +58 -0
  272. data/lib/pubid/iho.rb +50 -1
  273. data/lib/pubid/iso/builder.rb +59 -53
  274. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  275. data/lib/pubid/iso/components/code.rb +7 -19
  276. data/lib/pubid/iso/components/publisher.rb +10 -8
  277. data/lib/pubid/iso/components.rb +2 -4
  278. data/lib/pubid/iso/identifier.rb +233 -6
  279. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  280. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  281. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  282. data/lib/pubid/iso/identifiers/data.rb +0 -1
  283. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  284. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  285. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  286. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  287. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  288. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  289. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  290. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  291. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  292. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  293. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  294. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  295. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  296. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  297. data/lib/pubid/iso/identifiers.rb +0 -1
  298. data/lib/pubid/iso/normalizer.rb +89 -0
  299. data/lib/pubid/iso/parser.rb +26 -6
  300. data/lib/pubid/iso/single_identifier.rb +6 -3
  301. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  302. data/lib/pubid/iso/urn_generator.rb +74 -176
  303. data/lib/pubid/iso/urn_parser.rb +28 -9
  304. data/lib/pubid/iso.rb +173 -2
  305. data/lib/pubid/itu/builder.rb +0 -12
  306. data/lib/pubid/itu/components/code.rb +8 -0
  307. data/lib/pubid/itu/components.rb +11 -0
  308. data/lib/pubid/itu/identifier.rb +6 -39
  309. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  310. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  311. data/lib/pubid/itu/identifiers/base.rb +0 -6
  312. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  313. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  314. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  315. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  316. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  317. data/lib/pubid/itu/urn_parser.rb +23 -0
  318. data/lib/pubid/itu.rb +42 -1
  319. data/lib/pubid/jcgm/builder.rb +16 -8
  320. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  321. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  322. data/lib/pubid/jcgm/renderer.rb +68 -0
  323. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  324. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  325. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  326. data/lib/pubid/jcgm.rb +43 -2
  327. data/lib/pubid/jis/builder.rb +44 -52
  328. data/lib/pubid/jis/identifier.rb +132 -3
  329. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  330. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  331. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  332. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  333. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  334. data/lib/pubid/jis/identifiers.rb +1 -1
  335. data/lib/pubid/jis/parser.rb +31 -5
  336. data/lib/pubid/jis/renderer.rb +69 -0
  337. data/lib/pubid/jis/single_identifier.rb +6 -12
  338. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  339. data/lib/pubid/jis/urn_parser.rb +23 -0
  340. data/lib/pubid/jis.rb +42 -2
  341. data/lib/pubid/nist/builder.rb +122 -1761
  342. data/lib/pubid/nist/caster.rb +1272 -0
  343. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  344. data/lib/pubid/nist/components/code.rb +9 -20
  345. data/lib/pubid/nist/components/edition.rb +16 -0
  346. data/lib/pubid/nist/components/supplement.rb +88 -21
  347. data/lib/pubid/nist/components.rb +0 -1
  348. data/lib/pubid/nist/identifier.rb +25 -0
  349. data/lib/pubid/nist/identifiers/base.rb +206 -64
  350. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  351. data/lib/pubid/nist/identifiers/circular_supplement.rb +3 -2
  352. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  353. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  354. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  355. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -11
  356. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  357. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +17 -16
  358. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  359. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  360. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  361. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  362. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  363. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  364. data/lib/pubid/nist/identifiers/report.rb +4 -3
  365. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  366. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  367. data/lib/pubid/nist/identifiers.rb +1 -0
  368. data/lib/pubid/nist/parser.rb +67 -424
  369. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  370. data/lib/pubid/nist/preprocessor.rb +416 -0
  371. data/lib/pubid/nist/renderer.rb +43 -0
  372. data/lib/pubid/nist/router.rb +148 -0
  373. data/lib/pubid/nist/series/base.rb +58 -0
  374. data/lib/pubid/nist/series/crpl.rb +13 -0
  375. data/lib/pubid/nist/series/fips.rb +14 -0
  376. data/lib/pubid/nist/series/ir.rb +60 -0
  377. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  378. data/lib/pubid/nist/series/mono.rb +19 -0
  379. data/lib/pubid/nist/series/ncstar.rb +20 -0
  380. data/lib/pubid/nist/series.rb +49 -0
  381. data/lib/pubid/nist/supplement_identifier.rb +11 -25
  382. data/lib/pubid/nist/urn_generator.rb +14 -8
  383. data/lib/pubid/nist/urn_parser.rb +67 -0
  384. data/lib/pubid/nist.rb +83 -4
  385. data/lib/pubid/oiml/components/code.rb +10 -0
  386. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  387. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  388. data/lib/pubid/oiml/renderer.rb +161 -0
  389. data/lib/pubid/oiml/single_identifier.rb +6 -45
  390. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  391. data/lib/pubid/oiml/urn_generator.rb +0 -8
  392. data/lib/pubid/oiml/urn_parser.rb +22 -0
  393. data/lib/pubid/oiml.rb +42 -1
  394. data/lib/pubid/plateau/identifier.rb +23 -0
  395. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  396. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  397. data/lib/pubid/plateau/renderer.rb +51 -0
  398. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  399. data/lib/pubid/plateau/urn_parser.rb +43 -0
  400. data/lib/pubid/plateau.rb +44 -1
  401. data/lib/pubid/renderers/base.rb +34 -0
  402. data/lib/pubid/renderers/directives_renderer.rb +27 -14
  403. data/lib/pubid/renderers/guide_renderer.rb +7 -1
  404. data/lib/pubid/renderers/human_readable.rb +31 -8
  405. data/lib/pubid/renderers/iwa_renderer.rb +5 -1
  406. data/lib/pubid/renderers/supplement_renderer.rb +4 -1
  407. data/lib/pubid/rendering/context.rb +33 -21
  408. data/lib/pubid/rendering.rb +0 -3
  409. data/lib/pubid/sae/components/date.rb +8 -0
  410. data/lib/pubid/sae/components/type.rb +5 -1
  411. data/lib/pubid/sae/identifiers/base.rb +2 -16
  412. data/lib/pubid/sae/renderer.rb +36 -0
  413. data/lib/pubid/sae/urn_generator.rb +2 -10
  414. data/lib/pubid/sae/urn_parser.rb +36 -0
  415. data/lib/pubid/sae.rb +42 -1
  416. data/lib/pubid/urn_generator/base.rb +12 -12
  417. data/lib/pubid/urn_parser/base.rb +81 -0
  418. data/lib/pubid/urn_parser/errors.rb +9 -0
  419. data/lib/pubid/urn_parser.rb +14 -0
  420. data/lib/pubid/version.rb +1 -1
  421. data/lib/pubid.rb +29 -7
  422. data/lib/tasks/website-data.json +1940 -1882
  423. metadata +77 -43
  424. data/lib/pubid/amca/scheme.rb +0 -16
  425. data/lib/pubid/ansi/scheme.rb +0 -15
  426. data/lib/pubid/api/scheme.rb +0 -66
  427. data/lib/pubid/ashrae/scheme.rb +0 -53
  428. data/lib/pubid/asme/scheme.rb +0 -37
  429. data/lib/pubid/astm/scheme.rb +0 -55
  430. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  431. data/lib/pubid/bsi/scheme.rb +0 -243
  432. data/lib/pubid/ccsds/scheme.rb +0 -57
  433. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  434. data/lib/pubid/cie/scheme.rb +0 -64
  435. data/lib/pubid/csa/scheme.rb +0 -44
  436. data/lib/pubid/etsi/scheme.rb +0 -42
  437. data/lib/pubid/export/data_class_exporter.rb +0 -59
  438. data/lib/pubid/export/ieee_exporter.rb +0 -78
  439. data/lib/pubid/export/itu_exporter.rb +0 -66
  440. data/lib/pubid/export/nist_exporter.rb +0 -64
  441. data/lib/pubid/export/registry_exporter.rb +0 -90
  442. data/lib/pubid/export/scheme_exporter.rb +0 -70
  443. data/lib/pubid/identifier_registry.rb +0 -198
  444. data/lib/pubid/idf/scheme.rb +0 -61
  445. data/lib/pubid/iec/scheme.rb +0 -71
  446. data/lib/pubid/ieee/scheme.rb +0 -90
  447. data/lib/pubid/iho/scheme.rb +0 -29
  448. data/lib/pubid/iso/identifiers/base.rb +0 -115
  449. data/lib/pubid/iso/scheme.rb +0 -187
  450. data/lib/pubid/itu/scheme.rb +0 -174
  451. data/lib/pubid/jcgm/scheme.rb +0 -60
  452. data/lib/pubid/jis/components/code.rb +0 -59
  453. data/lib/pubid/jis/identifiers/base.rb +0 -72
  454. data/lib/pubid/jis/scheme.rb +0 -49
  455. data/lib/pubid/nist/components/publisher.rb +0 -24
  456. data/lib/pubid/nist/scheme.rb +0 -199
  457. data/lib/pubid/oiml/scheme.rb +0 -46
  458. data/lib/pubid/plateau/scheme.rb +0 -45
  459. data/lib/pubid/rendering/base.rb +0 -73
  460. data/lib/pubid/rendering/common.rb +0 -211
  461. data/lib/pubid/rendering/format.rb +0 -25
  462. data/lib/pubid/sae/scheme.rb +0 -47
  463. data/lib/pubid/scheme.rb +0 -207
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # Human-readable renderer for NIST identifiers.
6
+ #
7
+ # NIST supports multiple output formats (:full, :long, :abbreviated,
8
+ # :short, :mr). Each series class defines public style methods
9
+ # (to_short_style, to_mr_style, etc.) with series-specific formatting
10
+ # logic, so this renderer delegates to those methods rather than
11
+ # reimplementing them.
12
+ #
13
+ # Registered as the `:human` format in the NIST format registry and
14
+ # invoked via `render(format: :human, nist_format: :short)`.
15
+ class Renderer < ::Pubid::Renderers::Base
16
+ # Render the identifier in the requested NIST format.
17
+ #
18
+ # @param context [Object, nil] rendering context (unused by NIST)
19
+ # @param nist_format [Symbol, nil] NIST output format (:full, :long,
20
+ # :abbreviated, :abbrev, :short, :mr). Defaults to :short.
21
+ # @return [String] formatted identifier string
22
+ def render(context: nil, nist_format: nil, **_opts)
23
+ id = @id
24
+
25
+ effective_format = nist_format || :short
26
+ effective_format = effective_format.to_sym if effective_format.is_a?(String)
27
+
28
+ case effective_format
29
+ when :full, :long
30
+ id.public_send(:to_full_style)
31
+ when :abbreviated, :abbrev
32
+ id.public_send(:to_abbreviated_style)
33
+ when :short
34
+ id.public_send(:to_short_style)
35
+ when :mr
36
+ id.public_send(:to_mr_style)
37
+ else
38
+ id.public_send(:to_short_style)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # Router class for NIST series-to-class mapping
6
+ # Single Responsibility: Resolve parsed data to the correct identifier class
7
+ #
8
+ # Delegates to Pubid::Nist.locate_stage / Pubid::Nist.locate_type
9
+ # for series-to-class resolution.
10
+ class Router
11
+ # All valid series codes (comprehensive list)
12
+ VALID_SERIES = [
13
+ # Major series with dedicated classes
14
+ "SP", "FIPS", "IR", "HB", "TN",
15
+ # Specialized series with dedicated classes
16
+ "CIRC", "CRPL", "CS", "CSM",
17
+ # Other series (use Base class)
18
+ "GCR", "AMS", "BSS", "BMS", "BH", "MONO", "MP",
19
+ "NCSTAR", "NSRDS", "CSWP", "VTS", "AI", "OWMWP",
20
+ "PC", "RPT", "SIBS", "TIBM", "TTB", "EAB",
21
+ "JPCRD", "JRES", "CIS", "HR", "IRPL", "IP",
22
+ "LC", "PS", "LCIRC",
23
+ # Compound series
24
+ "BRPD-CRPL-D", "CRPL-F-A", "CRPL-F-B", "CS-E",
25
+ "CSRC Building Block", "CSRC Use Case", "CSRC Book",
26
+ "ITL Bulletin", "NIST LC", "NIST PS", "NIST DCI",
27
+ "NIST Other", "NSRDS-NBS",
28
+ ].freeze
29
+
30
+ # Check if series is valid
31
+ # @param series_code [String] the series code
32
+ # @return [Boolean] true if series is valid
33
+ def valid_series?(series_code)
34
+ VALID_SERIES.include?(series_code)
35
+ end
36
+
37
+ # Locate identifier class by series and pattern
38
+ # @param parsed_hash [Hash] the parsed identifier data
39
+ # @return [Class] the identifier class
40
+ def locate_identifier_klass(parsed_hash)
41
+ # Date-style identifier (no series) dispatches here, not via series lookup.
42
+ if parsed_hash[:dated_date] && parsed_hash[:dated_seq]
43
+ return Identifiers::DatedDocument
44
+ end
45
+
46
+ series = parsed_hash[:series]&.to_s
47
+
48
+ # Handle compound series that include publisher (both space and dot separated)
49
+ if series&.start_with?("NBS ")
50
+ simple_series = series.sub("NBS ", "")
51
+
52
+ # Check for CIRC supplement
53
+ if simple_series == "CIRC"
54
+ if has_supplement?(parsed_hash)
55
+ return Identifiers::CircularSupplement
56
+ else
57
+ return Identifiers::Circular
58
+ end
59
+ end
60
+
61
+ # Use simple series for lookup (TYPED_STAGES abbr handles compound forms)
62
+ series = simple_series
63
+ elsif series&.start_with?("NBS.")
64
+ # Handle dot-separated patterns (e.g., "NBS.LCIRC" after preprocessing)
65
+ simple_series = series.sub("NBS.", "")
66
+
67
+ # Check for LCIRC supplement (dot-separated variant)
68
+ if simple_series == "LCIRC"
69
+ if has_supplement?(parsed_hash)
70
+ return Identifiers::CircularSupplement
71
+ else
72
+ return Identifiers::LetterCircular
73
+ end
74
+ end
75
+
76
+ # Check for CIRC supplement (dot-separated variant)
77
+ if simple_series == "CIRC"
78
+ if has_supplement?(parsed_hash)
79
+ return Identifiers::CircularSupplement
80
+ else
81
+ return Identifiers::Circular
82
+ end
83
+ end
84
+
85
+ # Use simple series for lookup
86
+ series = simple_series
87
+ elsif series&.start_with?("NIST.")
88
+ # Handle dot-separated NIST patterns
89
+ simple_series = series.sub("NIST.", "")
90
+
91
+ # Check for LCIRC supplement (dot-separated variant)
92
+ if simple_series == "LCIRC"
93
+ if has_supplement?(parsed_hash)
94
+ return Identifiers::CircularSupplement
95
+ else
96
+ return Identifiers::LetterCircular
97
+ end
98
+ end
99
+
100
+ # Use simple series for lookup
101
+ series = simple_series
102
+ end
103
+
104
+ # Check for CS variants (works for both compound "NBS CS" and simple "CS")
105
+ if series == "CS"
106
+ first_num = parsed_hash[:first_number]
107
+
108
+ # Check for CSM (monthly) - v#n# pattern inside first_number hash
109
+ if first_num.is_a?(Hash) && first_num[:volume_number] && first_num[:issue_number]
110
+ return Identifiers::CommercialStandardsMonthly
111
+ end
112
+
113
+ # Check for CS-E (emergency) - e-prefix with 3+ digits
114
+ # Handle Parslet::Slice by converting to string
115
+ first_num_str = first_num.is_a?(String) ? first_num.to_str : first_num.to_s
116
+
117
+ # Match e104 or e104 (when "e104-43" is split into first+second)
118
+ if /^e\d{3,}/.match?(first_num_str)
119
+ return Identifiers::CommercialStandardEmergency
120
+ end
121
+ end
122
+
123
+ # Look up using TYPED_STAGES registry (replaces series_to_class_map)
124
+ # This handles simple series, compound series (via abbr array), and all variants
125
+ # Delegates to Pubid::Nist.locate_stage / Pubid::Nist.locate_type
126
+ # instead of an injected dependency.
127
+ typed_stage = Pubid::Nist.locate_stage(series)
128
+ if typed_stage
129
+ Pubid::Nist.locate_type(typed_stage.type_code) || Identifiers::Base
130
+ else
131
+ # Fallback to Base for unmapped series (e.g., "AMS", "VTS")
132
+ Identifiers::Base
133
+ end
134
+ end
135
+
136
+ # Check if parsed hash has supplement indicators
137
+ # @param parsed_hash [Hash] the parsed identifier data
138
+ # @return [Boolean] true if supplement indicators are present
139
+ def has_supplement?(parsed_hash)
140
+ parsed_hash[:supplement] ||
141
+ parsed_hash[:supplement_date_range] ||
142
+ parsed_hash[:supplement_date] ||
143
+ parsed_hash[:supplement_slash_year] ||
144
+ parsed_hash[:supplement_with_rev]
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # Default series behavior. All hooks return the "generic" answer so a
7
+ # series bug can be fixed by overriding the relevant hook in a subclass.
8
+ class Base
9
+ # Whether an uppercase letter at the end of `first_number` stays in the
10
+ # number (true) or is extracted as a separate Part component (false).
11
+ def self.preserve_letter_suffix?(parsed_hash)
12
+ parsed_hash[:parsed_format] == :mr
13
+ end
14
+
15
+ # Cast a `:letter_number` parser hash (e.g., from "800-56A").
16
+ # Return a cast hash, or nil to skip assignment.
17
+ # Default: split letter suffix into a Part component.
18
+ def self.cast_letter_number(value, _parsed_hash)
19
+ full = combine_letter_suffix(value)
20
+ return nil if full.nil? || full.empty?
21
+
22
+ { part: Components::Part.new(type: "", value: full.upcase) }
23
+ end
24
+
25
+ # Whether the edition-year cast should use modern (numeric) date format
26
+ # instead of preserving historical month names. FIPS uses modern.
27
+ def self.modern_edition_date?
28
+ false
29
+ end
30
+
31
+ # Whether `part_num` alongside `second_num` becomes a Part component
32
+ # (true) or is folded into the compound number (false). IR uses Part.
33
+ def self.part_num_as_component?
34
+ false
35
+ end
36
+
37
+ # Hook: build compound number when `letter_num` is present.
38
+ # Return true if the series handled it; false to fall back to default.
39
+ def self.handle_letter_num_compound?(_identifier,
40
+ first_num:, letter_base:,
41
+ letter_suffix:)
42
+ false
43
+ end
44
+
45
+ # Hook: post-process the identifier after compound number is assigned.
46
+ # Override to reverse series-specific preprocessing side effects.
47
+ def self.finalize_identifier(_identifier, _parsed_hash); end
48
+
49
+ # Combine `:letter_suffix` and `:letter_suffix_extra` (e.g., "U" + "r").
50
+ def self.combine_letter_suffix(value)
51
+ suffix = value[:letter_suffix].to_s.strip
52
+ extra = value[:letter_suffix_extra].to_s.strip
53
+ extra.empty? ? suffix : "#{suffix}#{extra}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # CRPL series: letter suffix preserved in first_number.
7
+ # Range parsing ("2_3-1") is handled by the dedicated :crpl_range case
8
+ # in the caster; this class only carries the letter-suffix policy.
9
+ class Crpl < LetterPreserving
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # FIPS series: letter suffix preserved; edition dates use modern format.
7
+ class Fips < LetterPreserving
8
+ def self.modern_edition_date?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # IR (Interagency Report) series carries the most series-specific logic:
7
+ #
8
+ # - "R" or "Ur" letter suffix becomes revision "r1" (e.g., "79-1786R").
9
+ # - part_num alongside second_num becomes a Part component (type "pt").
10
+ # - Preprocessing converts "84-2946" → "84e2946"; this class reverses
11
+ # that side effect so IR keeps the compound number form.
12
+ class Ir < LetterPreserving
13
+ def self.cast_letter_number(value, _parsed_hash)
14
+ full = combine_letter_suffix(value)
15
+ return nil if full.nil? || full.empty?
16
+
17
+ if ["R", "Ur"].include?(full)
18
+ value[:letter_suffix] = full
19
+ value
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ def self.part_num_as_component?
26
+ true
27
+ end
28
+
29
+ def self.handle_letter_num_compound?(identifier,
30
+ first_num:, letter_base:,
31
+ letter_suffix:)
32
+ return false unless letter_suffix == "R"
33
+
34
+ identifier.number = Components::Code.new(
35
+ value: "#{first_num.value}-#{letter_base}",
36
+ )
37
+ edition_obj = Components::Edition.new(type: "r", id: "1")
38
+ identifier.edition = edition_obj
39
+ identifier.edition_component = edition_obj
40
+ identifier.revision = "r1"
41
+ true
42
+ end
43
+
44
+ def self.finalize_identifier(identifier, _parsed_hash)
45
+ return unless identifier.number
46
+
47
+ value = identifier.number.value.to_s
48
+ match = value.match(/^(\d+)e(\d{4})$/)
49
+ return unless match
50
+
51
+ identifier.number = Components::Code.new(
52
+ value: "#{match[1]}-#{match[2]}",
53
+ )
54
+ identifier.edition = nil
55
+ identifier.edition_component = nil
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # Series where the letter suffix on `first_number` stays in the number.
7
+ # Used for: RPT, MP, LC, CRPL, MONO, FIPS, IR (subclasses refine further).
8
+ class LetterPreserving < Base
9
+ def self.preserve_letter_suffix?(_parsed_hash)
10
+ true
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # MONO series: letter suffix preserved in first_number AND in
7
+ # letter_number (e.g., "NBS MONO 1A" — letter stays in the number).
8
+ class Mono < LetterPreserving
9
+ def self.cast_letter_number(value, _parsed_hash)
10
+ full = combine_letter_suffix(value)
11
+ return nil if full.nil? || full.empty?
12
+
13
+ value[:letter_suffix] = full
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ module Series
6
+ # NCSTAR series: letter suffix in letter_number stays in the number
7
+ # (e.g., "NIST NCSTAR 1-1A" — "1A" remains the compound suffix).
8
+ # Unlike MONO, first_number letter suffix is NOT preserved.
9
+ class Ncstar < Base
10
+ def self.cast_letter_number(value, _parsed_hash)
11
+ full = combine_letter_suffix(value)
12
+ return nil if full.nil? || full.empty?
13
+
14
+ value[:letter_suffix] = full
15
+ value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # Per-series behavior policies for the NIST caster and builder.
6
+ #
7
+ # Series-specific casting decisions (letter-suffix preservation, IR revision
8
+ # handling, FIPS date format, etc.) live behind this interface so the
9
+ # caster and builder never read `parsed_hash[:series]` directly. A series
10
+ # bug now lives in exactly one file.
11
+ module Series
12
+ autoload :Base, "#{__dir__}/series/base"
13
+ autoload :LetterPreserving, "#{__dir__}/series/letter_preserving"
14
+ autoload :Crpl, "#{__dir__}/series/crpl"
15
+ autoload :Fips, "#{__dir__}/series/fips"
16
+ autoload :Ir, "#{__dir__}/series/ir"
17
+ autoload :Mono, "#{__dir__}/series/mono"
18
+ autoload :Ncstar, "#{__dir__}/series/ncstar"
19
+
20
+ # Order matters: longer / more-specific codes first so that substrings
21
+ # do not shadow them (e.g., LCIRC must be matched before IR, since
22
+ # "LCIRC" contains "IR").
23
+ REGISTRY = [
24
+ ["LCIRC", LetterPreserving],
25
+ ["FIPS", Fips],
26
+ ["CRPL", Crpl],
27
+ ["NCSTAR", Ncstar],
28
+ ["MONO", Mono],
29
+ ["IR", Ir],
30
+ ["MP", LetterPreserving],
31
+ ["RPT", LetterPreserving],
32
+ ["LC", LetterPreserving],
33
+ ].freeze
34
+
35
+ def self.for(parsed_hash)
36
+ return Base if parsed_hash.nil?
37
+
38
+ series_code = parsed_hash[:series]
39
+ return Base if series_code.nil?
40
+
41
+ series_str = series_code.to_s.upcase
42
+ REGISTRY.each do |code, klass|
43
+ return klass if series_str.include?(code)
44
+ end
45
+ Base
46
+ end
47
+ end
48
+ end
49
+ end
@@ -28,7 +28,7 @@ module Pubid
28
28
  def to_s(format = :short)
29
29
  # Handle date range supplements (no base identifier)
30
30
  if supplement_date_range_start && supplement_date_range_end
31
- return "NBS CIRC supp#{supplement_date_range_start}-#{supplement_date_range_end}"
31
+ return "NBS CIRC sup#{supplement_date_range_start}-#{supplement_date_range_end}"
32
32
  end
33
33
 
34
34
  return super unless base_identifier
@@ -37,34 +37,20 @@ module Pubid
37
37
 
38
38
  # NEW: Handle update attribute (e.g., "Upd12-1926" for supplement patterns)
39
39
  if update
40
- # Check if this is an implicit supplement (no explicit "sup/supp" marker, just update)
41
- # For implicit supplements like "145r11/1925", don't add "sup" before the update
40
+ # Implicit supplements (e.g. "145r11/1925") have no explicit marker;
41
+ # everything else uses the canonical single-p "sup" marker
42
+ # (relaton-data-nist uses "sup" across all series).
42
43
  is_implicit = self.class.attributes.key?(:implicit_supplement) && implicit_supplement == true
43
-
44
- if is_implicit
45
- # Implicit supplement: "{base}/{update}" (e.g., "145/Upd1-192511")
46
- else
47
- # Explicit supplement: "{base}sup/{update}" (e.g., "118sup/Upd12-1926")
48
- is_circ_supplement = ["LCIRC", "CIRC"].include?(series.to_s)
49
- result += is_circ_supplement ? "sup" : "supp"
50
- end
51
- result += "/#{update}"
44
+ result += "sup" unless is_implicit
45
+ # Update#to_s emits its own leading separator (/Upd… short, -upd… mr),
46
+ # so append it directly instead of hardcoding the slash.
47
+ result += update.to_s(format)
52
48
  return result
53
49
  end
54
50
 
55
- # Original supplement rendering
56
- # For LCIRC/CIRC supplements with update, use "sup"
57
- # For LCIRC/CIRC supplements without update, normalize "sup" to "supp" for consistency
58
- is_circ_supplement = ["LCIRC", "CIRC"].include?(series.to_s)
59
- # When update is present, use "sup" (e.g., "118sup/Upd1-192612")
60
- # When update is not present, use "supp" (e.g., "378Gsupp" - normalized from "sup")
61
- result += if is_circ_supplement && !update
62
- "supp"
63
- elsif is_circ_supplement
64
- "sup"
65
- else
66
- "supp"
67
- end
51
+ # Canonical supplement marker is single-p "sup" across all NIST/NBS
52
+ # series (relaton-data-nist: SP/CIRC/HB/RPT/LC/IR/MONO/BMS all use "sup").
53
+ result += "sup"
68
54
 
69
55
  # Add edition information if present (just ID, not type prefix)
70
56
  if edition&.id
@@ -61,18 +61,24 @@ module Pubid
61
61
  identifier_parts << identifier.stage.to_s
62
62
  end
63
63
 
64
+ # Supplement is now a structured component. Preserve the existing URN
65
+ # branching exactly: range → "supp{start}-{end}", revision → "supprev",
66
+ # a valued supplement → "suppX"/"supp-X" (dash unless it starts with an
67
+ # uppercase letter), and — quirk retained — a nil (absent) supplement
68
+ # still emits "supp", while a present-but-empty one emits nothing.
64
69
  supp = identifier.supplement
65
- if identifier.supplement_date_range_start && identifier.supplement_date_range_end
66
- identifier_parts << "supp#{identifier.supplement_date_range_start}-#{identifier.supplement_date_range_end}"
67
- elsif identifier.supplement_has_revision
70
+ if supp&.range?
71
+ identifier_parts << "supp#{supp.month}#{supp.year}-#{supp.month_end}#{supp.year_end}"
72
+ elsif supp&.has_revision
68
73
  identifier_parts << "supprev"
69
- elsif supp && !supp.empty?
70
- identifier_parts << if supp.match?(/^[A-Z]/)
71
- "supp#{supp}"
74
+ elsif supp && !supp.value_string.empty?
75
+ value = supp.value_string
76
+ identifier_parts << if value.match?(/^[A-Z]/)
77
+ "supp#{value}"
72
78
  else
73
- "supp-#{supp}"
79
+ "supp-#{value}"
74
80
  end
75
- elsif !supp
81
+ elsif supp.nil?
76
82
  identifier_parts << "supp"
77
83
  end
78
84
 
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # Parses NIST URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:nist:{type}:{code}[.{revision}].supp
9
+ #
10
+ # type is the lowercase series (sp, fips, ir, nistcir, …). code is the
11
+ # alphanumeric designation. revision is `r{N}` when present. The `.supp`
12
+ # suffix marks the series as supplementable.
13
+ #
14
+ # Examples:
15
+ # - urn:nist:sp:800-53.supp → NIST SP 800-53
16
+ # - urn:nist:sp:800-53.r5.supp → NIST SP 800-53r5
17
+ # - urn:nist:fips:199.supp → NIST FIPS 199
18
+ class UrnParser < Pubid::UrnParser::Base
19
+ TYPE_UPCASE = {
20
+ "sp" => "SP",
21
+ "fips" => "FIPS",
22
+ "ir" => "IR",
23
+ "nistcir" => "NISTCIR",
24
+ "nbs" => "NBS",
25
+ "nistir" => "NISTIR",
26
+ "csf" => "CSF",
27
+ "gcr" => "GCR",
28
+ "itl" => "ITL",
29
+ "jres" => "JRES",
30
+ "lcirc" => "LCIRC",
31
+ "mon" => "MONO",
32
+ "ms" => "MS",
33
+ "nsrds" => "NSRDS",
34
+ "tn" => "TN",
35
+ "wp" => "WP",
36
+ }.freeze
37
+
38
+ def parse_urn(urn)
39
+ body = strip_namespace(urn)
40
+ parts = split_parts(body)
41
+
42
+ type_token, payload = parts
43
+ code, revision = parse_payload(payload)
44
+
45
+ text = "NIST #{type_label(type_token)} #{code}"
46
+ text += revision if revision
47
+ flavor_parse(text)
48
+ end
49
+
50
+ private
51
+
52
+ def parse_payload(payload)
53
+ # Strip the trailing ".supp" supplement marker.
54
+ stripped = payload.sub(/\.supp\z/, "")
55
+ # Split revision suffix from code (e.g., "800-53.r5" → ["800-53", "r5"]).
56
+ match = stripped.match(/^(.*)\.(r\d+)$/i)
57
+ return [stripped, nil] unless match
58
+
59
+ [match[1], match[2]]
60
+ end
61
+
62
+ def type_label(token)
63
+ TYPE_UPCASE.fetch(token.downcase) { token.upcase }
64
+ end
65
+ end
66
+ end
67
+ end