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
@@ -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
@@ -42,7 +42,9 @@ module Pubid
42
42
  # (relaton-data-nist uses "sup" across all series).
43
43
  is_implicit = self.class.attributes.key?(:implicit_supplement) && implicit_supplement == true
44
44
  result += "sup" unless is_implicit
45
- result += "/#{update}"
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)
46
48
  return result
47
49
  end
48
50
 
@@ -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
data/lib/pubid/nist.rb CHANGED
@@ -3,14 +3,51 @@
3
3
  module Pubid
4
4
  module Nist
5
5
  autoload :Builder, "#{__dir__}/nist/builder"
6
+ autoload :Caster, "#{__dir__}/nist/caster"
7
+ autoload :CircularSupplementBuilder, "#{__dir__}/nist/circular_supplement_builder"
6
8
  autoload :Components, "#{__dir__}/nist/components"
7
9
  autoload :Configuration, "#{__dir__}/nist/configuration"
8
10
  autoload :Identifier, "#{__dir__}/nist/identifier"
9
11
  autoload :Identifiers, "#{__dir__}/nist/identifiers"
10
12
  autoload :Parser, "#{__dir__}/nist/parser"
11
- autoload :Scheme, "#{__dir__}/nist/scheme"
13
+ autoload :ParserOutputNormalizer, "#{__dir__}/nist/parser_output_normalizer"
14
+ autoload :Preprocessor, "#{__dir__}/nist/preprocessor"
15
+ autoload :Renderer, "#{__dir__}/nist/renderer"
16
+ autoload :Router, "#{__dir__}/nist/router"
17
+ autoload :Series, "#{__dir__}/nist/series"
12
18
  autoload :SupplementIdentifier, "#{__dir__}/nist/supplement_identifier"
13
19
  autoload :UrnGenerator, "#{__dir__}/nist/urn_generator"
20
+ autoload :UrnParser, "#{__dir__}/nist/urn_parser"
21
+
22
+ # Explicit registry of NIST identifier classes.
23
+ #
24
+ # NIST identifier classes use `typed_stages` (not the `self.type` Hash
25
+ # pattern used by CEN/JCGM/ANSI), so they cannot be auto-discovered.
26
+ # Identifiers::Base is the fallback for unmapped series (e.g. AMS, VTS)
27
+ # and must be excluded from typed-stage aggregation.
28
+ IDENTIFIER_TYPES = [
29
+ Identifiers::SpecialPublication,
30
+ Identifiers::FederalInformationProcessingStandards,
31
+ Identifiers::InteragencyReport,
32
+ Identifiers::Handbook,
33
+ Identifiers::TechnicalNote,
34
+ Identifiers::Circular,
35
+ Identifiers::CircularSupplement,
36
+ Identifiers::CrplReport,
37
+ Identifiers::Report,
38
+ Identifiers::Monograph,
39
+ Identifiers::MiscellaneousPublication,
40
+ Identifiers::GrantContractorReport,
41
+ Identifiers::Ncstar,
42
+ Identifiers::Owmwp,
43
+ Identifiers::Nsrds,
44
+ Identifiers::LetterCircular,
45
+ Identifiers::CommercialStandard,
46
+ Identifiers::CommercialStandardEmergency,
47
+ Identifiers::CommercialStandardsMonthly,
48
+ Identifiers::DatedDocument,
49
+ Identifiers::Base, # Fallback for unmapped series
50
+ ].freeze
14
51
 
15
52
  # Parse a NIST identifier string
16
53
  # @param identifier [String] the identifier string to parse
@@ -20,9 +57,8 @@ module Pubid
20
57
  # Note: We call the class method directly to ensure preprocessing is applied
21
58
  parsed = Parser.class_parse_with_preprocessing(identifier)
22
59
 
23
- # Use Scheme and Builder for clean architecture
24
- # ONE CLASS PER SERIES TYPE (like ISO)
25
- builder = Builder.new(Scheme)
60
+ # Builder is stateless lookups go through this module (Pubid::Nist)
61
+ builder = Builder.new
26
62
  builder.build(parsed)
27
63
  end
28
64
 
@@ -31,6 +67,48 @@ module Pubid
31
67
  def self.configuration
32
68
  @configuration ||= Configuration.new
33
69
  end
70
+
71
+ # Per-flavor format registry: inherits global formats, overrides :human
72
+ Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
73
+ Identifiers::Base.format_registry.register(:human, renderer: Nist::Renderer)
74
+
75
+ # All identifier classes for external consumption (export, website).
76
+ # Identifiers::Base is the fallback for unmapped series and is excluded
77
+ # from external type listings.
78
+ # @return [Array<Class>] identifier classes
79
+ def self.identifier_types
80
+ IDENTIFIER_TYPES.reject { |klass| klass == Identifiers::Base }
81
+ end
82
+
83
+ # Aggregate TYPED_STAGES from all identifier classes.
84
+ # Identifiers::Base is excluded because it has no typed stages and acts
85
+ # as the fallback for unmapped series.
86
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
87
+ def self.all_typed_stages
88
+ @all_typed_stages ||= identifier_types
89
+ .reject { |klass| klass == Identifiers::Base }
90
+ .flat_map(&:typed_stages)
91
+ .freeze
92
+ end
93
+
94
+ # Lookup: type code -> identifier class.
95
+ # Identifiers::Base is excluded so it never gets selected by type code.
96
+ # @param code [String, Symbol] the type code to find
97
+ # @return [Class, nil] the matching identifier class, or nil
98
+ def self.locate_type(code)
99
+ type_str = code.to_s
100
+ identifier_types
101
+ .reject { |klass| klass == Identifiers::Base }
102
+ .find { |klass| klass.typed_stages.any? { |ts| ts.type_code.to_s == type_str } }
103
+ end
104
+
105
+ # Lookup: abbreviation -> typed stage
106
+ # @param abbr [String, Symbol] the abbreviation to find
107
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
108
+ def self.locate_stage(abbr)
109
+ abbr_str = abbr.to_s.upcase
110
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
111
+ end
34
112
  end
35
113
  end
36
114
 
@@ -3,6 +3,12 @@
3
3
  module Pubid
4
4
  module Oiml
5
5
  module Components
6
+ # Code component for OIML identifiers.
7
+ #
8
+ # Stays independent of Pubid::Components::Code because OIML uses
9
+ # +number+ as the primary field (shared Code uses +value+). The
10
+ # shape is otherwise compatible; a future rename of +number+ →
11
+ # +value+ would let this become a subclass.
6
12
  class Code < Lutaml::Model::Serializable
7
13
  attribute :number, :string
8
14
  attribute :part, :string
@@ -14,6 +20,10 @@ module Pubid
14
20
  result += "-#{subpart}" if subpart
15
21
  result
16
22
  end
23
+
24
+ def render(context: nil)
25
+ to_s
26
+ end
17
27
  end
18
28
  end
19
29
  end