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
data/lib/pubid/plateau.rb CHANGED
@@ -8,9 +8,10 @@ module Pubid
8
8
  autoload :Identifier, "#{__dir__}/plateau/identifier"
9
9
  autoload :Identifiers, "#{__dir__}/plateau/identifiers"
10
10
  autoload :Parser, "#{__dir__}/plateau/parser"
11
- autoload :Scheme, "#{__dir__}/plateau/scheme"
11
+ autoload :Renderer, "#{__dir__}/plateau/renderer"
12
12
  autoload :SupplementIdentifier, "#{__dir__}/plateau/supplement_identifier"
13
13
  autoload :UrnGenerator, "#{__dir__}/plateau/urn_generator"
14
+ autoload :UrnParser, "#{__dir__}/plateau/urn_parser"
14
15
 
15
16
  def self.parse(input)
16
17
  # Apply legacy update_codes normalization first
@@ -19,6 +20,47 @@ module Pubid
19
20
  parsed = parser.parse(normalized)
20
21
  Builder.build(parsed)
21
22
  end
23
+
24
+ # Per-flavor format registry: inherits global formats, overrides :human
25
+ Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
26
+ Identifiers::Base.format_registry.register(:human, renderer: Plateau::Renderer)
27
+ SupplementIdentifier.format_registry = Identifiers::Base.format_registry
28
+
29
+ # Auto-discover all identifier types from the Identifiers namespace
30
+ # @return [Array<Class>] identifier classes that define a self.type Hash
31
+ def self.identifier_types
32
+ @identifier_types ||= Identifiers.constants
33
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
34
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
35
+ .select { |c| c.type.is_a?(Hash) }
36
+ end
37
+
38
+ # Build typed stage index from identifier types
39
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
40
+ def self.all_typed_stages
41
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
42
+ if klass.const_defined?(:TYPED_STAGES)
43
+ klass.const_get(:TYPED_STAGES)
44
+ else
45
+ []
46
+ end
47
+ end
48
+ end
49
+
50
+ # Lookup: type code -> identifier class
51
+ # @param code [String, Symbol] the type key to find
52
+ # @return [Class, nil] the matching identifier class
53
+ def self.locate_type(code)
54
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
55
+ end
56
+
57
+ # Lookup: abbreviation -> typed stage
58
+ # @param abbr [String, Symbol] the abbreviation to find
59
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
60
+ def self.locate_stage(abbr)
61
+ abbr_str = abbr.to_s.upcase
62
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
63
+ end
22
64
  end
23
65
  end
24
66
 
@@ -28,10 +28,15 @@ module Pubid
28
28
 
29
29
  def render_publisher_portion(context)
30
30
  ann = context.annotated
31
- pub_str = annotate(@id.publisher.render(context:), "publisher",
32
- annotated: ann) if @id.publisher
31
+ if @id.publisher
32
+ pub_str = annotate(@id.publisher.render(context:), "publisher",
33
+ annotated: ann)
34
+ end
33
35
  abbr = @id.typed_stage ? @id.typed_stage.abbreviation(format_long: false) : ""
34
- abbr = annotate(abbr, typed_stage_css(@id.typed_stage), annotated: ann) unless abbr.empty?
36
+ unless abbr.empty?
37
+ abbr = annotate(abbr, typed_stage_css(@id.typed_stage),
38
+ annotated: ann)
39
+ end
35
40
  subgroup_str = @id.subgroup.render(context:) if @id.subgroup
36
41
 
37
42
  [
@@ -44,12 +49,21 @@ module Pubid
44
49
  def render_number_portion(context)
45
50
  ann = context.annotated
46
51
  parts = []
47
- parts << annotate(@id.number.render(context:), "docnumber",
48
- annotated: ann) if @id.number
49
- parts << " #{annotate(@id.part.render(context:), 'part', annotated: ann)}" if @id.part
50
- parts << "-#{annotate(@id.subpart.render(context:), 'part', annotated: ann)}" if @id.subpart
52
+ if @id.number
53
+ parts << annotate(@id.number.render(context:), "docnumber",
54
+ annotated: ann)
55
+ end
56
+ if @id.part
57
+ parts << " #{annotate(@id.part.render(context:), 'part',
58
+ annotated: ann)}"
59
+ end
60
+ if @id.subpart
61
+ parts << "-#{annotate(@id.subpart.render(context:), 'part',
62
+ annotated: ann)}"
63
+ end
51
64
  if @id.stage_iteration
52
- parts << ".#{annotate(@id.stage_iteration.render(context:), 'iteration', annotated: ann)}"
65
+ parts << ".#{annotate(@id.stage_iteration.render(context:),
66
+ 'iteration', annotated: ann)}"
53
67
  end
54
68
  date_str = @id.date.render(context:) if @id.date && context.with_date
55
69
  parts << ":#{annotate(date_str, 'year', annotated: ann)}" if date_str
@@ -7,8 +7,10 @@ module Pubid
7
7
 
8
8
  def render_publisher_and_stage(context)
9
9
  ann = context.annotated
10
- pub_str = annotate(@id.publisher.render(context:), "publisher",
11
- annotated: ann) if @id.publisher
10
+ if @id.publisher
11
+ pub_str = annotate(@id.publisher.render(context:), "publisher",
12
+ annotated: ann)
13
+ end
12
14
  stage_str = @id.typed_stage.render(context:) if @id.typed_stage
13
15
 
14
16
  if stage_str && !stage_str.empty?
@@ -18,8 +18,10 @@ module Pubid
18
18
 
19
19
  def render_publisher_and_stage(context)
20
20
  ann = context.annotated
21
- pub_str = annotate(@id.publisher.render(context:), "publisher",
22
- annotated: ann) if @id.publisher
21
+ if @id.publisher
22
+ pub_str = annotate(@id.publisher.render(context:), "publisher",
23
+ annotated: ann)
24
+ end
23
25
  stage_str = @id.typed_stage.render(context:) if @id.typed_stage
24
26
 
25
27
  if stage_str && !stage_str.empty?
@@ -36,12 +38,21 @@ module Pubid
36
38
  def render_number_portion(context)
37
39
  ann = context.annotated
38
40
  parts = []
39
- parts << annotate(@id.number.render(context:), "docnumber",
40
- annotated: ann) if @id.number
41
- parts << "-#{annotate(@id.part.render(context:), 'part', annotated: ann)}" if @id.part
42
- parts << "-#{annotate(@id.subpart.render(context:), 'part', annotated: ann)}" if @id.subpart
41
+ if @id.number
42
+ parts << annotate(@id.number.render(context:), "docnumber",
43
+ annotated: ann)
44
+ end
45
+ if @id.part
46
+ parts << "-#{annotate(@id.part.render(context:), 'part',
47
+ annotated: ann)}"
48
+ end
49
+ if @id.subpart
50
+ parts << "-#{annotate(@id.subpart.render(context:), 'part',
51
+ annotated: ann)}"
52
+ end
43
53
  if @id.stage_iteration
44
- parts << ".#{annotate(@id.stage_iteration.render(context:), 'iteration', annotated: ann)}"
54
+ parts << ".#{annotate(@id.stage_iteration.render(context:),
55
+ 'iteration', annotated: ann)}"
45
56
  end
46
57
  date_str = @id.date.render(context:) if @id.date && context.with_date
47
58
  parts << ":#{annotate(date_str, 'year', annotated: ann)}" if date_str
@@ -2,31 +2,20 @@
2
2
 
3
3
  module Pubid
4
4
  module Rendering
5
- # Context object for flavor-specific rendering rules
6
- #
7
- # This encapsulates the rendering rules that vary between flavors,
8
- # allowing components to render themselves correctly based on context.
9
- #
10
- # == Usage
11
- #
12
- # context = RenderingContext.new(
13
- # stage_separator: "/",
14
- # stage_separator_with_copublisher: " ",
15
- # type_separator: "/",
16
- # type_separator_with_prefix: " ",
17
- # default_type_abbr: "IS"
18
- # )
19
- # identifier.to_s(context: context)
5
+ # Context object for flavor-specific and format-specific rendering rules
20
6
  #
7
+ # Encapsulates rendering rules that vary between flavors and between
8
+ # output formats (human-readable, URN, MR string). Components receive
9
+ # this context and render themselves accordingly — renderers and
10
+ # URN generators never reach into component internals.
21
11
  class RenderingContext
22
- attr_reader :stage_separator, :stage_separator_with_copublisher,
12
+ attr_reader :format, :stage_separator, :stage_separator_with_copublisher,
23
13
  :type_separator, :type_separator_with_prefix,
24
14
  :default_type_abbr, :lang, :lang_single,
25
15
  :with_language_code, :stage_format_long, :with_date,
26
16
  :annotated
27
17
 
28
- # Initialize a new rendering context
29
- #
18
+ # @param format [Symbol] output format: :human, :urn, or :mr
30
19
  # @param stage_separator [String] separator before stage without copublisher
31
20
  # @param stage_separator_with_copublisher [String] separator before stage with copublisher
32
21
  # @param type_separator [String] separator before type (default)
@@ -34,7 +23,8 @@ module Pubid
34
23
  # @param default_type_abbr [String] default type abbreviation to skip rendering
35
24
  # @param lang [Symbol] language for rendering (:en or :fr)
36
25
  # @param lang_single [Boolean] use single char language format
37
- def initialize(stage_separator: "/",
26
+ def initialize(format: :human,
27
+ stage_separator: "/",
38
28
  stage_separator_with_copublisher: " ",
39
29
  type_separator: "/",
40
30
  type_separator_with_prefix: " ",
@@ -45,6 +35,7 @@ module Pubid
45
35
  stage_format_long: false,
46
36
  with_date: true,
47
37
  annotated: false)
38
+ @format = format
48
39
  @stage_separator = stage_separator
49
40
  @stage_separator_with_copublisher = stage_separator_with_copublisher
50
41
  @type_separator = type_separator
@@ -58,6 +49,18 @@ module Pubid
58
49
  @annotated = annotated
59
50
  end
60
51
 
52
+ def urn?
53
+ @format == :urn
54
+ end
55
+
56
+ def human?
57
+ @format == :human
58
+ end
59
+
60
+ def mr?
61
+ @format == :mr
62
+ end
63
+
61
64
  # Get the appropriate stage separator based on whether there's a copublisher
62
65
  #
63
66
  # @param has_copublisher [Boolean] whether identifier has copublisher
@@ -118,6 +121,12 @@ module Pubid
118
121
  )
119
122
  end
120
123
 
124
+ # URN rendering context: components emit URN-format fragments
125
+ # @return [RenderingContext] URN-specific context
126
+ def self.urn
127
+ @urn ||= new(format: :urn)
128
+ end
129
+
121
130
  # Format factory methods — replace RenderingStyle hierarchy
122
131
  def self.ref_num_short
123
132
  new(with_language_code: :single, stage_format_long: false,
@@ -2,10 +2,7 @@
2
2
 
3
3
  module Pubid
4
4
  module Rendering
5
- autoload :Base, "pubid/rendering/base"
6
- autoload :Common, "pubid/rendering/common"
7
5
  autoload :Date, "pubid/rendering/date"
8
- autoload :Format, "pubid/rendering/format"
9
6
  autoload :Language, "pubid/rendering/language"
10
7
  autoload :Numbering, "pubid/rendering/numbering"
11
8
  autoload :Publisher, "pubid/rendering/publisher"
@@ -10,7 +10,15 @@ module Pubid
10
10
  class Date < Lutaml::Model::Serializable
11
11
  attribute :year, :integer
12
12
 
13
+ def present?
14
+ !year.nil?
15
+ end
16
+
13
17
  def to_s
18
+ render
19
+ end
20
+
21
+ def render(context: nil)
14
22
  year.to_s
15
23
  end
16
24
  end
@@ -6,11 +6,15 @@ module Pubid
6
6
  module Sae
7
7
  module Components
8
8
  # Type component for SAE document types
9
- # AMS, AIR,, ARP, AS, MA
9
+ # AMS, AIR, ARP, AS, MA
10
10
  class Type < Lutaml::Model::Serializable
11
11
  attribute :abbr, :string
12
12
 
13
13
  def to_s
14
+ render
15
+ end
16
+
17
+ def render(context: nil)
14
18
  abbr.to_s
15
19
  end
16
20
  end
@@ -9,29 +9,6 @@ module Pubid
9
9
  rescue Parslet::ParseFailed => e
10
10
  raise "Failed to parse SAE identifier: #{input}\n#{e.message}"
11
11
  end
12
-
13
- # Factory that builds a SAE identifier from a hash of primitives.
14
- # SAE has only one identifier class ({Identifiers::Base}); `:type`
15
- # is data (the document-type abbreviation: "J", "AS", "ARP", "AMS",
16
- # "AIR", "MA") rather than a class-dispatch key.
17
- def self.create(**opts)
18
- Identifiers::Base.new(**coerce_create_attrs(opts))
19
- end
20
-
21
- def self.coerce_create_attrs(opts)
22
- attrs = { publisher: (opts[:publisher] || "SAE").to_s }
23
- if (v = opts[:type])
24
- attrs[:type] = Pubid::Sae::Components::Type.new(abbr: v.to_s)
25
- end
26
- if (v = opts[:number])
27
- attrs[:number] = Pubid::Components::Code.new(value: v.to_s)
28
- end
29
- if (v = opts[:year])
30
- attrs[:date] = Pubid::Components::Date.new(year: v.to_s)
31
- end
32
- attrs
33
- end
34
- private_class_method :coerce_create_attrs
35
12
  end
36
13
  end
37
14
  end
@@ -15,22 +15,8 @@ module Pubid
15
15
  attribute :number, Sae::Components::Code
16
16
  attribute :date, Sae::Components::Date
17
17
 
18
- def to_s
19
- parts = []
20
-
21
- # Publisher and type
22
- parts << publisher if publisher
23
- parts << type.to_s if type
24
-
25
- # Number
26
- parts << number.to_s if number
27
-
28
- result = parts.join(" ")
29
-
30
- # Date
31
- result += ":#{date.year}" if date
32
-
33
- result
18
+ def self.type
19
+ { key: :base, web: :standard, title: "Standard", short: "SAE" }
34
20
  end
35
21
 
36
22
  def year
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Sae
5
+ # Human-readable renderer for SAE identifiers.
6
+ #
7
+ # Produces strings like:
8
+ # "SAE AS5553"
9
+ # "SAE ARP4754A"
10
+ # "SAE AMS2475:2023"
11
+ #
12
+ # The renderer is registered as the +:human+ format in the SAE format
13
+ # registry and invoked via +render(format: :human)+.
14
+ class Renderer < ::Pubid::Renderers::Base
15
+ def render(context: nil, **_opts)
16
+ id = @id
17
+
18
+ parts = []
19
+
20
+ # Publisher and type
21
+ parts << id.publisher if id.publisher
22
+ parts << id.type.to_s if id.type
23
+
24
+ # Number
25
+ parts << id.number.to_s if id.number
26
+
27
+ result = parts.join(" ")
28
+
29
+ # Date
30
+ result += ":#{id.date.render(context:)}" if id.date
31
+
32
+ result
33
+ end
34
+ end
35
+ end
36
+ end
@@ -9,18 +9,10 @@ module Pubid
9
9
  identifier.type.abbr.to_s.downcase
10
10
  end
11
11
 
12
- def urn_year
13
- if identifier.date&.year
14
- return identifier.date.year.to_s
15
- end
16
-
17
- identifier.year&.to_s
18
- end
19
-
20
12
  def urn_number
21
13
  return nil unless identifier.number
22
14
 
23
- identifier.number.value.to_s
15
+ identifier.number.render(context: URN_CONTEXT)
24
16
  end
25
17
 
26
18
  def generate
@@ -29,7 +21,7 @@ module Pubid
29
21
  parts << urn_number if urn_number
30
22
  parts << urn_year if urn_year
31
23
 
32
- parts[1] = identifier.publisher.to_s.downcase if identifier.publisher
24
+ parts[1] = urn_publisher if urn_publisher
33
25
 
34
26
  parts.join(":")
35
27
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Sae
5
+ # Parses SAE URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:sae:{type|std}:{number}:{year}
9
+ # where slot[1] is overwritten with the publisher string when a publisher
10
+ # is set. The common single-publisher case keeps slot[1] = "sae".
11
+ #
12
+ # Examples:
13
+ # - urn:sae:j:300:2019 → SAE J300:2019
14
+ # - urn:sae:air:500 → SAE AIR500
15
+ # - urn:sae:ams:5000:2020 → SAE AMS5000:2020
16
+ class UrnParser < Pubid::UrnParser::Base
17
+ def parse_urn(urn)
18
+ body = strip_namespace(urn)
19
+ parts = split_parts(body)
20
+
21
+ type_token, number, year = parts
22
+ text = build_text(type_token, number, year)
23
+ flavor_parse(text)
24
+ end
25
+
26
+ private
27
+
28
+ def build_text(type_token, number, year)
29
+ head = type_token == "std" ? "" : type_token.upcase
30
+ text = "SAE #{head}#{number}"
31
+ text += ":#{year}" if year
32
+ text
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/pubid/sae.rb CHANGED
@@ -7,13 +7,54 @@ module Pubid
7
7
  autoload :Identifier, "#{__dir__}/sae/identifier"
8
8
  autoload :Identifiers, "#{__dir__}/sae/identifiers"
9
9
  autoload :Parser, "#{__dir__}/sae/parser"
10
- autoload :Scheme, "#{__dir__}/sae/scheme"
10
+ autoload :Renderer, "#{__dir__}/sae/renderer"
11
11
  autoload :UrnGenerator, "#{__dir__}/sae/urn_generator"
12
+ autoload :UrnParser, "#{__dir__}/sae/urn_parser"
12
13
 
13
14
  def self.parse(input)
14
15
  Identifier.parse(input)
15
16
  end
17
+
18
+ # Auto-discover all identifier types from the Identifiers namespace.
19
+ # SAE has only one identifier class (Base), which IS the document type.
20
+ # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
21
+ def self.identifier_types
22
+ @identifier_types ||= Identifiers.constants
23
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
24
+ .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
25
+ end
26
+
27
+ # Build typed stage index from identifier types
28
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
29
+ def self.all_typed_stages
30
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
31
+ if klass.const_defined?(:TYPED_STAGES)
32
+ klass.const_get(:TYPED_STAGES)
33
+ else
34
+ []
35
+ end
36
+ end
37
+ end
38
+
39
+ # Lookup: type code -> identifier class
40
+ # @param code [String, Symbol] the type key to find
41
+ # @return [Class, nil] the matching identifier class
42
+ def self.locate_type(code)
43
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
44
+ end
45
+
46
+ # Lookup: abbreviation -> typed stage
47
+ # @param abbr [String, Symbol] the abbreviation to find
48
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
49
+ def self.locate_stage(abbr)
50
+ abbr_str = abbr.to_s.upcase
51
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
52
+ end
16
53
  end
17
54
  end
18
55
 
19
56
  Pubid::Registry.register(:sae, Pubid::Sae)
57
+
58
+ # Per-flavor format registry: inherits global formats, overrides :human
59
+ Pubid::Sae::Identifiers::Base.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
60
+ Pubid::Sae::Identifiers::Base.format_registry.register(:human, renderer: Pubid::Sae::Renderer)
@@ -6,6 +6,9 @@ module Pubid
6
6
  # Provides template methods for common URN parts.
7
7
  # Flavors subclass and override only what differs.
8
8
  class Base
9
+ URN_CONTEXT = Rendering::RenderingContext.urn.freeze
10
+ private_constant :URN_CONTEXT
11
+
9
12
  attr_reader :identifier
10
13
 
11
14
  def initialize(identifier)
@@ -35,7 +38,7 @@ module Pubid
35
38
  pub = maybe(:publisher)
36
39
  return nil unless pub
37
40
 
38
- pub.to_s.downcase
41
+ pub.is_a?(Components::Publisher) ? pub.render(context: URN_CONTEXT) : pub.to_s.downcase
39
42
  end
40
43
 
41
44
  def urn_type
@@ -46,34 +49,31 @@ module Pubid
46
49
  val = maybe(:number) || maybe(:code)
47
50
  return nil unless val
48
51
 
49
- val.is_a?(Components::Code) ? val.value.to_s : val.to_s
52
+ val.is_a?(Components::Code) ? val.render(context: URN_CONTEXT) : val.to_s
50
53
  end
51
54
 
52
55
  def urn_part
53
56
  val = maybe(:part)
54
57
  return nil unless val
55
58
 
56
- "-#{val.is_a?(Components::Code) ? val.value : val}"
59
+ "-#{val.is_a?(Components::Code) ? val.render(context: URN_CONTEXT) : val}"
57
60
  end
58
61
 
59
62
  def urn_subpart
60
63
  val = maybe(:subpart)
61
64
  return nil unless val
62
65
 
63
- "-#{val.is_a?(Components::Code) ? val.value : val}"
66
+ "-#{val.is_a?(Components::Code) ? val.render(context: URN_CONTEXT) : val}"
64
67
  end
65
68
 
66
69
  def urn_year
67
70
  date = maybe(:date)
68
- if date
69
- year = date.is_a?(Components::Date) ? date.year : date.to_s
70
- return year.to_s if year
71
- end
72
- if maybe(:year)
73
- return identifier.year.to_s
71
+ if date.is_a?(Components::Date)
72
+ return date.render(context: URN_CONTEXT) if date.present?
73
+ elsif date
74
+ return date.to_s
74
75
  end
75
-
76
- nil
76
+ maybe(:year)&.to_s
77
77
  end
78
78
 
79
79
  def urn_edition
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module UrnParser
5
+ # Base class for flavor-specific URN parsers.
6
+ #
7
+ # A UrnParser inverts its sibling UrnGenerator: it consumes the URN
8
+ # emitted by {Pubid::{Flavor}::UrnGenerator} and rebuilds an Identifier.
9
+ # The preferred strategy is to reconstruct a human-readable identifier
10
+ # string from the URN fields and delegate to the flavor's text parser —
11
+ # this keeps parsing logic in one place (the flavor's text parser).
12
+ #
13
+ # Subclasses MUST override {#parse_urn}. They typically use
14
+ # {#strip_namespace} and {#flavor_parse} helpers and may pass through
15
+ # {#build_from_parts} for the common `urn:{flavor}:{publisher}:{type}:
16
+ # {number}:{year}` shape.
17
+ class Base
18
+ # Parse a URN string into an Identifier.
19
+ # @param urn [String]
20
+ # @return [Pubid::Identifier]
21
+ def self.parse(urn)
22
+ new.parse_urn(urn)
23
+ end
24
+
25
+ # Subclasses override.
26
+ # @raise [NotImplementedError]
27
+ def parse_urn(_urn)
28
+ raise NotImplementedError,
29
+ "#{self.class} must implement #parse_urn"
30
+ end
31
+
32
+ protected
33
+
34
+ # The flavor module this parser belongs to (e.g., Pubid::Sae).
35
+ # Derived from the class name: Pubid::Sae::UrnParser → Pubid::Sae.
36
+ def flavor_module
37
+ @flavor_module ||=
38
+ begin
39
+ path = self.class.name.to_s.split("::")
40
+ Object.const_get(path[0..-2].join("::"))
41
+ end
42
+ end
43
+
44
+ # The lowercase flavor name used as the URN namespace (e.g., "sae").
45
+ # Defaults to the last segment of the module name. Override in
46
+ # subclasses whose URN namespace differs from the module name
47
+ # (e.g., CenCenelec emits URNs under "urn:cen:").
48
+ def flavor_name
49
+ @flavor_name ||= flavor_module.name.split("::").last.downcase
50
+ end
51
+
52
+ # Validate the URN starts with `urn:{flavor}:` and return the body.
53
+ # @param urn [String]
54
+ # @return [String] body after `urn:{flavor}:`
55
+ # @raise [Errors::ParseError] if prefix is wrong
56
+ def strip_namespace(urn)
57
+ prefix = "urn:#{flavor_name}:"
58
+ unless urn.downcase.start_with?(prefix)
59
+ raise Errors::ParseError,
60
+ "Invalid #{flavor_name.upcase} URN: #{urn.inspect}"
61
+ end
62
+
63
+ urn[prefix.length..]
64
+ end
65
+
66
+ # Delegate to the flavor's text parser.
67
+ # @param code [String] human-readable identifier
68
+ # @return [Pubid::Identifier]
69
+ def flavor_parse(code)
70
+ flavor_module.parse(code)
71
+ end
72
+
73
+ # Split the URN body on ":" into parts.
74
+ # @param body [String]
75
+ # @return [Array<String>]
76
+ def split_parts(body)
77
+ body.split(":")
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module UrnParser
5
+ module Errors
6
+ class ParseError < StandardError; end
7
+ end
8
+ end
9
+ end