pubid 2.0.0.pre.alpha.8 → 2.0.0.pre.alpha.9

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 (484) hide show
  1. checksums.yaml +4 -4
  2. data/data/bipm/update_codes.yaml +9 -0
  3. data/data/iec/update_codes.yaml +3 -0
  4. data/data/ieee/update_codes.yaml +107 -1
  5. data/data/nist/series.yaml +155 -0
  6. data/data/nist/update_codes.yaml +8 -0
  7. data/lib/pubid/adobe/builder.rb +52 -0
  8. data/lib/pubid/adobe/identifier.rb +49 -0
  9. data/lib/pubid/adobe/identifiers/publication.rb +31 -0
  10. data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
  11. data/lib/pubid/adobe/identifiers.rb +10 -0
  12. data/lib/pubid/adobe/parser.rb +128 -0
  13. data/lib/pubid/adobe/renderer.rb +39 -0
  14. data/lib/pubid/adobe/urn_generator.rb +42 -0
  15. data/lib/pubid/adobe/urn_parser.rb +69 -0
  16. data/lib/pubid/adobe.rb +60 -0
  17. data/lib/pubid/amca/builder.rb +2 -2
  18. data/lib/pubid/amca/identifier.rb +1 -3
  19. data/lib/pubid/amca/identifiers/base.rb +1 -6
  20. data/lib/pubid/amca/identifiers/interpretation.rb +1 -1
  21. data/lib/pubid/amca/identifiers/publication.rb +1 -1
  22. data/lib/pubid/amca/identifiers/standard.rb +1 -1
  23. data/lib/pubid/amca/identifiers.rb +0 -1
  24. data/lib/pubid/amca/single_identifier.rb +1 -1
  25. data/lib/pubid/amca.rb +3 -3
  26. data/lib/pubid/ashrae/builder.rb +22 -22
  27. data/lib/pubid/ashrae/identifier.rb +3 -4
  28. data/lib/pubid/ashrae/identifiers/addenda_package.rb +1 -1
  29. data/lib/pubid/ashrae/identifiers/addendum.rb +1 -1
  30. data/lib/pubid/ashrae/identifiers/base.rb +14 -8
  31. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +1 -1
  32. data/lib/pubid/ashrae/identifiers.rb +0 -1
  33. data/lib/pubid/ashrae/parser.rb +14 -9
  34. data/lib/pubid/ashrae/renderer.rb +19 -19
  35. data/lib/pubid/ashrae/single_identifier.rb +1 -1
  36. data/lib/pubid/ashrae/supplement_identifier.rb +6 -6
  37. data/lib/pubid/ashrae.rb +3 -3
  38. data/lib/pubid/bipm/builder.rb +107 -0
  39. data/lib/pubid/bipm/identifier.rb +160 -0
  40. data/lib/pubid/bipm/identifiers/committee_document.rb +24 -0
  41. data/lib/pubid/bipm/identifiers/guide.rb +24 -0
  42. data/lib/pubid/bipm/identifiers/meeting.rb +41 -0
  43. data/lib/pubid/bipm/identifiers/mep.rb +21 -0
  44. data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
  45. data/lib/pubid/bipm/identifiers/si_brochure.rb +20 -0
  46. data/lib/pubid/bipm/identifiers.rb +15 -0
  47. data/lib/pubid/bipm/parser.rb +184 -0
  48. data/lib/pubid/bipm/renderer.rb +110 -0
  49. data/lib/pubid/bipm/urn_generator.rb +58 -0
  50. data/lib/pubid/bipm/urn_parser.rb +52 -0
  51. data/lib/pubid/bipm.rb +86 -0
  52. data/lib/pubid/bsi/builder.rb +14 -14
  53. data/lib/pubid/bsi/identifier.rb +0 -1
  54. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
  55. data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
  56. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
  57. data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
  58. data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
  59. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
  60. data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
  61. data/lib/pubid/bsi/renderer.rb +8 -8
  62. data/lib/pubid/bsi/single_identifier.rb +48 -0
  63. data/lib/pubid/builder/base.rb +5 -3
  64. data/lib/pubid/bundled_identifier.rb +3 -3
  65. data/lib/pubid/calconnect/builder.rb +38 -0
  66. data/lib/pubid/calconnect/identifier.rb +117 -0
  67. data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
  68. data/lib/pubid/calconnect/identifiers.rb +9 -0
  69. data/lib/pubid/calconnect/parser.rb +54 -0
  70. data/lib/pubid/calconnect/renderer.rb +36 -0
  71. data/lib/pubid/calconnect/urn_generator.rb +33 -0
  72. data/lib/pubid/calconnect/urn_parser.rb +34 -0
  73. data/lib/pubid/calconnect.rb +77 -0
  74. data/lib/pubid/ccsds/builder.rb +1 -1
  75. data/lib/pubid/ccsds/identifier.rb +1 -1
  76. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  77. data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
  78. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  79. data/lib/pubid/cen_cenelec/builder.rb +46 -12
  80. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -2
  81. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +6 -0
  82. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -2
  83. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
  84. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  85. data/lib/pubid/cen_cenelec/renderer.rb +5 -5
  86. data/lib/pubid/cen_cenelec/supplement_identifier.rb +5 -5
  87. data/lib/pubid/cen_cenelec/urn_generator.rb +1 -1
  88. data/lib/pubid/cen_cenelec.rb +76 -72
  89. data/lib/pubid/cie/builder.rb +139 -24
  90. data/lib/pubid/cie/identifier.rb +7 -3
  91. data/lib/pubid/cie/identifiers/bundle.rb +32 -4
  92. data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
  93. data/lib/pubid/cie/identifiers/conference.rb +9 -4
  94. data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
  95. data/lib/pubid/cie/identifiers/dual_published.rb +4 -4
  96. data/lib/pubid/cie/identifiers/identical.rb +7 -7
  97. data/lib/pubid/cie/identifiers/joint_published.rb +8 -8
  98. data/lib/pubid/cie/identifiers/proceedings.rb +39 -0
  99. data/lib/pubid/cie/identifiers/standard.rb +33 -7
  100. data/lib/pubid/cie/identifiers/supplement.rb +24 -22
  101. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +6 -2
  102. data/lib/pubid/cie/identifiers.rb +2 -0
  103. data/lib/pubid/cie/parser.rb +54 -5
  104. data/lib/pubid/cie/single_identifier.rb +40 -1
  105. data/lib/pubid/cie/supplement_identifier.rb +29 -16
  106. data/lib/pubid/cie/urn_generator.rb +11 -8
  107. data/lib/pubid/cie.rb +0 -1
  108. data/lib/pubid/components/date.rb +21 -5
  109. data/lib/pubid/csa/builder.rb +1 -1
  110. data/lib/pubid/csa/composite_identifier.rb +17 -1
  111. data/lib/pubid/csa/identifier.rb +48 -3
  112. data/lib/pubid/csa/identifiers/bundled.rb +6 -0
  113. data/lib/pubid/csa/identifiers/combined.rb +6 -0
  114. data/lib/pubid/csa/identifiers/package.rb +2 -2
  115. data/lib/pubid/csa/parser.rb +6 -6
  116. data/lib/pubid/csa/wrapper_identifier.rb +17 -0
  117. data/lib/pubid/doi/builder.rb +18 -0
  118. data/lib/pubid/doi/identifier.rb +46 -0
  119. data/lib/pubid/doi/identifiers/resource.rb +30 -0
  120. data/lib/pubid/doi/identifiers.rb +9 -0
  121. data/lib/pubid/doi/parser.rb +52 -0
  122. data/lib/pubid/doi/renderer.rb +13 -0
  123. data/lib/pubid/doi.rb +55 -0
  124. data/lib/pubid/easc/builder.rb +55 -0
  125. data/lib/pubid/easc/identifier.rb +61 -0
  126. data/lib/pubid/easc/identifiers/pmg.rb +20 -0
  127. data/lib/pubid/easc/identifiers/rmg.rb +19 -0
  128. data/lib/pubid/easc/identifiers.rb +10 -0
  129. data/lib/pubid/easc/parser.rb +80 -0
  130. data/lib/pubid/easc/renderer.rb +48 -0
  131. data/lib/pubid/easc/urn_generator.rb +46 -0
  132. data/lib/pubid/easc/urn_parser.rb +57 -0
  133. data/lib/pubid/easc.rb +52 -0
  134. data/lib/pubid/ecma/builder.rb +31 -0
  135. data/lib/pubid/ecma/identifier.rb +76 -0
  136. data/lib/pubid/ecma/identifiers/memento.rb +30 -0
  137. data/lib/pubid/ecma/identifiers/standard.rb +31 -0
  138. data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
  139. data/lib/pubid/ecma/identifiers.rb +11 -0
  140. data/lib/pubid/ecma/parser.rb +41 -0
  141. data/lib/pubid/ecma/renderer.rb +46 -0
  142. data/lib/pubid/ecma/urn_generator.rb +25 -0
  143. data/lib/pubid/ecma/urn_parser.rb +35 -0
  144. data/lib/pubid/ecma.rb +67 -0
  145. data/lib/pubid/etsi/builder.rb +7 -3
  146. data/lib/pubid/etsi/identifier.rb +1 -3
  147. data/lib/pubid/etsi/identifiers/base.rb +28 -10
  148. data/lib/pubid/etsi/identifiers/etsi_standard.rb +128 -4
  149. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +35 -3
  150. data/lib/pubid/etsi/identifiers.rb +0 -1
  151. data/lib/pubid/etsi/parser.rb +8 -2
  152. data/lib/pubid/etsi/renderer.rb +8 -2
  153. data/lib/pubid/etsi.rb +5 -5
  154. data/lib/pubid/export/exporter.rb +2 -1
  155. data/lib/pubid/export/flavor_exporter.rb +18 -3
  156. data/lib/pubid/gb/builder.rb +45 -0
  157. data/lib/pubid/gb/identifier.rb +64 -0
  158. data/lib/pubid/gb/identifiers/standard.rb +34 -0
  159. data/lib/pubid/gb/identifiers.rb +9 -0
  160. data/lib/pubid/gb/parser.rb +63 -0
  161. data/lib/pubid/gb/renderer.rb +35 -0
  162. data/lib/pubid/gb.rb +87 -0
  163. data/lib/pubid/gost/builder.rb +148 -0
  164. data/lib/pubid/gost/identifier.rb +49 -0
  165. data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
  166. data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
  167. data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
  168. data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
  169. data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
  170. data/lib/pubid/gost/identifiers.rb +13 -0
  171. data/lib/pubid/gost/parser.rb +97 -0
  172. data/lib/pubid/gost/renderer.rb +48 -0
  173. data/lib/pubid/gost/urn_generator.rb +46 -0
  174. data/lib/pubid/gost/urn_parser.rb +52 -0
  175. data/lib/pubid/gost.rb +49 -0
  176. data/lib/pubid/iala/builder.rb +22 -27
  177. data/lib/pubid/iala/identifier.rb +27 -2
  178. data/lib/pubid/iala/identifiers/advice.rb +1 -1
  179. data/lib/pubid/iala/identifiers/annex.rb +10 -10
  180. data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
  181. data/lib/pubid/iala/identifiers/guideline.rb +3 -1
  182. data/lib/pubid/iala/identifiers/letter.rb +1 -1
  183. data/lib/pubid/iala/identifiers/manual.rb +3 -1
  184. data/lib/pubid/iala/identifiers/model_course.rb +3 -1
  185. data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
  186. data/lib/pubid/iala/identifiers/report.rb +1 -1
  187. data/lib/pubid/iala/identifiers/resolution.rb +1 -1
  188. data/lib/pubid/iala/identifiers/standard.rb +3 -1
  189. data/lib/pubid/iala/identifiers.rb +0 -1
  190. data/lib/pubid/iala/renderer.rb +1 -1
  191. data/lib/pubid/iala/urn_generator.rb +1 -1
  192. data/lib/pubid/iala/urn_parser.rb +19 -2
  193. data/lib/pubid/iala.rb +4 -4
  194. data/lib/pubid/iana/builder.rb +20 -0
  195. data/lib/pubid/iana/identifier.rb +72 -0
  196. data/lib/pubid/iana/identifiers/registry.rb +33 -0
  197. data/lib/pubid/iana/identifiers.rb +9 -0
  198. data/lib/pubid/iana/parser.rb +38 -0
  199. data/lib/pubid/iana/renderer.rb +29 -0
  200. data/lib/pubid/iana/urn_generator.rb +15 -0
  201. data/lib/pubid/iana/urn_parser.rb +24 -0
  202. data/lib/pubid/iana.rb +69 -0
  203. data/lib/pubid/identifier.rb +210 -23
  204. data/lib/pubid/idf/builder.rb +1 -1
  205. data/lib/pubid/idf/parser.rb +2 -2
  206. data/lib/pubid/idf/renderer.rb +1 -1
  207. data/lib/pubid/idf/supplement_identifier.rb +3 -3
  208. data/lib/pubid/iec/builder.rb +35 -25
  209. data/lib/pubid/iec/identifier.rb +47 -2
  210. data/lib/pubid/iec/identifiers/base.rb +2 -2
  211. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
  212. data/lib/pubid/iec/identifiers/fragment_identifier.rb +11 -11
  213. data/lib/pubid/iec/identifiers/international_standard.rb +8 -5
  214. data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
  215. data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
  216. data/lib/pubid/iec/identifiers/technical_report.rb +1 -1
  217. data/lib/pubid/iec/identifiers/technical_specification.rb +1 -1
  218. data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
  219. data/lib/pubid/iec/identifiers.rb +1 -0
  220. data/lib/pubid/iec/parser.rb +51 -10
  221. data/lib/pubid/iec/renderer.rb +18 -8
  222. data/lib/pubid/iec/single_identifier.rb +1 -1
  223. data/lib/pubid/iec/supplement_identifier.rb +32 -19
  224. data/lib/pubid/iec.rb +1 -6
  225. data/lib/pubid/ieee/aiee/builder.rb +17 -3
  226. data/lib/pubid/ieee/aiee/identifier.rb +45 -61
  227. data/lib/pubid/ieee/builder.rb +341 -68
  228. data/lib/pubid/ieee/compaction.rb +121 -0
  229. data/lib/pubid/ieee/components/draft.rb +47 -7
  230. data/lib/pubid/ieee/identifier.rb +1 -3
  231. data/lib/pubid/ieee/identifiers/adopted_standard.rb +30 -5
  232. data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
  233. data/lib/pubid/ieee/identifiers/base.rb +106 -13
  234. data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
  235. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
  236. data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
  237. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +3 -3
  238. data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
  239. data/lib/pubid/ieee/identifiers/dual_published.rb +3 -3
  240. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
  241. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +2 -1
  242. data/lib/pubid/ieee/identifiers/joint_development.rb +56 -11
  243. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -1
  244. data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
  245. data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
  246. data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
  247. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
  248. data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
  249. data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
  250. data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
  251. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
  252. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
  253. data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
  254. data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
  255. data/lib/pubid/ieee/identifiers/standard.rb +4 -1
  256. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
  257. data/lib/pubid/ieee/identifiers.rb +2 -1
  258. data/lib/pubid/ieee/ire/builder.rb +7 -6
  259. data/lib/pubid/ieee/ire/identifier.rb +48 -33
  260. data/lib/pubid/ieee/nesc/builder.rb +33 -20
  261. data/lib/pubid/ieee/nesc/parser.rb +15 -14
  262. data/lib/pubid/ieee/parser.rb +461 -43
  263. data/lib/pubid/ieee/pre_parser.rb +1 -1
  264. data/lib/pubid/ieee/renderer.rb +154 -57
  265. data/lib/pubid/ieee/typed_stages.rb +12 -1
  266. data/lib/pubid/ieee/urn_generator.rb +3 -5
  267. data/lib/pubid/ieee.rb +56 -3
  268. data/lib/pubid/ietf/builder.rb +62 -0
  269. data/lib/pubid/ietf/identifier.rb +5 -0
  270. data/lib/pubid/ietf/identifiers/base.rb +75 -0
  271. data/lib/pubid/ietf/identifiers/bcp.rb +25 -0
  272. data/lib/pubid/ietf/identifiers/fyi.rb +25 -0
  273. data/lib/pubid/ietf/identifiers/internet_draft.rb +29 -0
  274. data/lib/pubid/ietf/identifiers/rfc.rb +25 -0
  275. data/lib/pubid/ietf/identifiers/std.rb +25 -0
  276. data/lib/pubid/ietf/identifiers.rb +13 -0
  277. data/lib/pubid/ietf/parser.rb +43 -0
  278. data/lib/pubid/ietf/renderer.rb +26 -0
  279. data/lib/pubid/ietf/urn_generator.rb +23 -0
  280. data/lib/pubid/ietf/urn_parser.rb +35 -0
  281. data/lib/pubid/ietf.rb +76 -0
  282. data/lib/pubid/iho/identifier.rb +1 -3
  283. data/lib/pubid/iho/identifiers/base.rb +1 -7
  284. data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
  285. data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
  286. data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
  287. data/lib/pubid/iho/identifiers/publication.rb +1 -1
  288. data/lib/pubid/iho/identifiers/standard.rb +1 -1
  289. data/lib/pubid/iho/identifiers.rb +0 -1
  290. data/lib/pubid/iho.rb +7 -7
  291. data/lib/pubid/isbn/builder.rb +44 -0
  292. data/lib/pubid/isbn/check_digit.rb +53 -0
  293. data/lib/pubid/isbn/identifier.rb +63 -0
  294. data/lib/pubid/isbn/identifiers/book.rb +30 -0
  295. data/lib/pubid/isbn/identifiers.rb +9 -0
  296. data/lib/pubid/isbn/parser.rb +45 -0
  297. data/lib/pubid/isbn/renderer.rb +16 -0
  298. data/lib/pubid/isbn.rb +52 -0
  299. data/lib/pubid/iso/builder.rb +9 -4
  300. data/lib/pubid/iso/combined_identifier.rb +2 -2
  301. data/lib/pubid/iso/identifier.rb +17 -1
  302. data/lib/pubid/iso/identifiers/directives_supplement.rb +8 -8
  303. data/lib/pubid/iso/normalizer.rb +2 -2
  304. data/lib/pubid/iso/parser.rb +16 -12
  305. data/lib/pubid/iso/supplement_identifier.rb +19 -6
  306. data/lib/pubid/iso/urn_generator.rb +4 -1
  307. data/lib/pubid/iso/urn_parser.rb +1 -1
  308. data/lib/pubid/itu/builder.rb +230 -29
  309. data/lib/pubid/itu/components/code.rb +48 -5
  310. data/lib/pubid/itu/components/designation.rb +35 -0
  311. data/lib/pubid/itu/components.rb +1 -0
  312. data/lib/pubid/itu/identifier.rb +1 -3
  313. data/lib/pubid/itu/identifiers/addendum.rb +15 -0
  314. data/lib/pubid/itu/identifiers/amendment.rb +6 -28
  315. data/lib/pubid/itu/identifiers/annex.rb +13 -2
  316. data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
  317. data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
  318. data/lib/pubid/itu/identifiers/base.rb +341 -23
  319. data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
  320. data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
  321. data/lib/pubid/itu/identifiers/errata.rb +15 -0
  322. data/lib/pubid/itu/identifiers/handbook.rb +38 -0
  323. data/lib/pubid/itu/identifiers/question.rb +63 -0
  324. data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
  325. data/lib/pubid/itu/identifiers/report.rb +39 -0
  326. data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
  327. data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
  328. data/lib/pubid/itu/identifiers/supplement.rb +119 -14
  329. data/lib/pubid/itu/identifiers.rb +10 -1
  330. data/lib/pubid/itu/model.rb +1 -1
  331. data/lib/pubid/itu/parser.rb +480 -26
  332. data/lib/pubid/itu/urn_generator.rb +36 -6
  333. data/lib/pubid/itu/urn_parser.rb +8 -0
  334. data/lib/pubid/itu.rb +11 -3
  335. data/lib/pubid/jcgm/builder.rb +23 -13
  336. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
  337. data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
  338. data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
  339. data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
  340. data/lib/pubid/jcgm/identifiers.rb +2 -0
  341. data/lib/pubid/jcgm/parser.rb +66 -6
  342. data/lib/pubid/jcgm/renderer.rb +26 -12
  343. data/lib/pubid/jcgm/single_identifier.rb +74 -5
  344. data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
  345. data/lib/pubid/jcgm/urn_generator.rb +21 -13
  346. data/lib/pubid/jcgm/urn_parser.rb +15 -3
  347. data/lib/pubid/jis/identifier.rb +52 -0
  348. data/lib/pubid/nist/builder.rb +29 -9
  349. data/lib/pubid/nist/caster.rb +7 -45
  350. data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
  351. data/lib/pubid/nist/components/supplement.rb +5 -2
  352. data/lib/pubid/nist/configuration.rb +7 -1
  353. data/lib/pubid/nist/identifier.rb +1 -3
  354. data/lib/pubid/nist/identifiers/base.rb +121 -37
  355. data/lib/pubid/nist/identifiers/circular.rb +1 -1
  356. data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  358. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +1 -1
  359. data/lib/pubid/nist/identifiers/crpl_report.rb +1 -1
  360. data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
  361. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
  362. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
  363. data/lib/pubid/nist/identifiers/handbook.rb +1 -1
  364. data/lib/pubid/nist/identifiers/internal_report.rb +1 -1
  365. data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
  366. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +1 -1
  367. data/lib/pubid/nist/identifiers/monograph.rb +1 -1
  368. data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
  369. data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
  370. data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
  371. data/lib/pubid/nist/identifiers/report.rb +1 -1
  372. data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
  373. data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
  374. data/lib/pubid/nist/identifiers.rb +0 -1
  375. data/lib/pubid/nist/parser.rb +26 -3
  376. data/lib/pubid/nist/preprocessor.rb +15 -0
  377. data/lib/pubid/nist/router.rb +2 -2
  378. data/lib/pubid/nist/series/ir.rb +0 -3
  379. data/lib/pubid/nist/supplement_identifier.rb +9 -9
  380. data/lib/pubid/nist.rb +12 -12
  381. data/lib/pubid/oasis/builder.rb +77 -0
  382. data/lib/pubid/oasis/identifier.rb +82 -0
  383. data/lib/pubid/oasis/identifiers/standard.rb +29 -0
  384. data/lib/pubid/oasis/identifiers.rb +9 -0
  385. data/lib/pubid/oasis/parser.rb +34 -0
  386. data/lib/pubid/oasis/renderer.rb +29 -0
  387. data/lib/pubid/oasis/urn_generator.rb +25 -0
  388. data/lib/pubid/oasis/urn_parser.rb +22 -0
  389. data/lib/pubid/oasis.rb +74 -0
  390. data/lib/pubid/ogc/builder.rb +33 -0
  391. data/lib/pubid/ogc/identifier.rb +77 -0
  392. data/lib/pubid/ogc/identifiers/document.rb +26 -0
  393. data/lib/pubid/ogc/identifiers.rb +10 -0
  394. data/lib/pubid/ogc/parser.rb +40 -0
  395. data/lib/pubid/ogc/renderer.rb +33 -0
  396. data/lib/pubid/ogc/urn_generator.rb +14 -0
  397. data/lib/pubid/ogc/urn_parser.rb +22 -0
  398. data/lib/pubid/ogc.rb +71 -0
  399. data/lib/pubid/oiml/builder.rb +31 -7
  400. data/lib/pubid/oiml/identifier.rb +9 -1
  401. data/lib/pubid/oiml/parser.rb +11 -12
  402. data/lib/pubid/oiml/renderer.rb +13 -13
  403. data/lib/pubid/oiml/single_identifier.rb +20 -0
  404. data/lib/pubid/oiml/supplement_identifier.rb +9 -9
  405. data/lib/pubid/oiml/urn_parser.rb +23 -6
  406. data/lib/pubid/oiml.rb +4 -0
  407. data/lib/pubid/omg/builder.rb +19 -0
  408. data/lib/pubid/omg/identifier.rb +44 -0
  409. data/lib/pubid/omg/identifiers/specification.rb +32 -0
  410. data/lib/pubid/omg/identifiers.rb +9 -0
  411. data/lib/pubid/omg/parser.rb +40 -0
  412. data/lib/pubid/omg/renderer.rb +19 -0
  413. data/lib/pubid/omg.rb +51 -0
  414. data/lib/pubid/parsers/mr_string.rb +101 -7
  415. data/lib/pubid/plateau/builder.rb +8 -4
  416. data/lib/pubid/plateau/identifier.rb +1 -3
  417. data/lib/pubid/plateau/identifiers/base.rb +1 -6
  418. data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
  419. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  420. data/lib/pubid/plateau/identifiers.rb +0 -1
  421. data/lib/pubid/plateau/parser.rb +15 -5
  422. data/lib/pubid/plateau/renderer.rb +1 -1
  423. data/lib/pubid/plateau/supplement_identifier.rb +11 -11
  424. data/lib/pubid/plateau.rb +4 -4
  425. data/lib/pubid/renderers/human_readable.rb +3 -1
  426. data/lib/pubid/renderers/mr_string.rb +46 -4
  427. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  428. data/lib/pubid/rendering/supplement.rb +4 -4
  429. data/lib/pubid/sae/builder.rb +1 -1
  430. data/lib/pubid/sae/identifier.rb +1 -3
  431. data/lib/pubid/sae/identifiers/base.rb +10 -7
  432. data/lib/pubid/sae/identifiers.rb +0 -1
  433. data/lib/pubid/sae.rb +3 -3
  434. data/lib/pubid/tgpp/builder.rb +41 -0
  435. data/lib/pubid/tgpp/identifier.rb +91 -0
  436. data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
  437. data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
  438. data/lib/pubid/tgpp/identifiers.rb +11 -0
  439. data/lib/pubid/tgpp/parser.rb +62 -0
  440. data/lib/pubid/tgpp/renderer.rb +36 -0
  441. data/lib/pubid/tgpp/urn_generator.rb +20 -0
  442. data/lib/pubid/tgpp/urn_parser.rb +28 -0
  443. data/lib/pubid/tgpp.rb +78 -0
  444. data/lib/pubid/type_resolver.rb +59 -0
  445. data/lib/pubid/un/builder.rb +42 -0
  446. data/lib/pubid/un/identifier.rb +37 -0
  447. data/lib/pubid/un/identifiers/document.rb +24 -0
  448. data/lib/pubid/un/identifiers.rb +9 -0
  449. data/lib/pubid/un/parser.rb +25 -0
  450. data/lib/pubid/un/renderer.rb +11 -0
  451. data/lib/pubid/un.rb +46 -0
  452. data/lib/pubid/version.rb +1 -1
  453. data/lib/pubid/w3c/builder.rb +55 -0
  454. data/lib/pubid/w3c/identifier.rb +101 -0
  455. data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
  456. data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
  457. data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
  458. data/lib/pubid/w3c/identifiers/note.rb +30 -0
  459. data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
  460. data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
  461. data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
  462. data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
  463. data/lib/pubid/w3c/identifiers/standard.rb +12 -0
  464. data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
  465. data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
  466. data/lib/pubid/w3c/identifiers.rb +25 -0
  467. data/lib/pubid/w3c/parser.rb +43 -0
  468. data/lib/pubid/w3c/renderer.rb +35 -0
  469. data/lib/pubid/w3c/urn_generator.rb +18 -0
  470. data/lib/pubid/w3c/urn_parser.rb +36 -0
  471. data/lib/pubid/w3c.rb +67 -0
  472. data/lib/pubid/xsf/builder.rb +17 -0
  473. data/lib/pubid/xsf/identifier.rb +62 -0
  474. data/lib/pubid/xsf/identifiers/xep.rb +31 -0
  475. data/lib/pubid/xsf/identifiers.rb +9 -0
  476. data/lib/pubid/xsf/parser.rb +25 -0
  477. data/lib/pubid/xsf/renderer.rb +23 -0
  478. data/lib/pubid/xsf/urn_generator.rb +13 -0
  479. data/lib/pubid/xsf/urn_parser.rb +18 -0
  480. data/lib/pubid/xsf.rb +76 -0
  481. data/lib/pubid.rb +25 -1
  482. metadata +205 -4
  483. data/lib/pubid/cie/components/code.rb +0 -80
  484. data/lib/pubid/iala/identifiers/base.rb +0 -14
data/lib/pubid/gost.rb ADDED
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gost
5
+ extend Pubid::PrefixesSupport
6
+
7
+ # Leading identifier tokens that a GOST document id can start with.
8
+ # Latin "GOST" and Cyrillic "ГОСТ" are both official; "R" (Russian
9
+ # national, e.g. "GOST R 34.12-2015") routes to this flavor too.
10
+ PREFIXES = ["GOST", "ГОСТ"].freeze
11
+
12
+ autoload :Builder, "#{__dir__}/gost/builder"
13
+ autoload :Identifier, "#{__dir__}/gost/identifier"
14
+ autoload :Identifiers, "#{__dir__}/gost/identifiers"
15
+ autoload :Parser, "#{__dir__}/gost/parser"
16
+ autoload :Renderer, "#{__dir__}/gost/renderer"
17
+ autoload :UrnGenerator, "#{__dir__}/gost/urn_generator"
18
+ autoload :UrnParser, "#{__dir__}/gost/urn_parser"
19
+
20
+ # Parse a GOST identifier string into an identifier object.
21
+ # @param identifier [String]
22
+ # @return [Pubid::Gost::Identifier]
23
+ def self.parse(identifier)
24
+ Identifier.parse(identifier)
25
+ end
26
+
27
+ # Per-flavor format registry: inherits global formats, overrides :human.
28
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
29
+ Identifier.format_registry.register(:human, renderer: Gost::Renderer)
30
+
31
+ # Auto-discover identifier types from the Identifiers namespace.
32
+ # @return [Array<Class>]
33
+ def self.identifier_types
34
+ @identifier_types ||= Identifiers.constants
35
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
36
+ .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
37
+ .reject { |c| c == Identifier }
38
+ end
39
+
40
+ # Lookup: type key → identifier class
41
+ # @param code [String, Symbol]
42
+ # @return [Class, nil]
43
+ def self.locate_type(code)
44
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
45
+ end
46
+ end
47
+ end
48
+
49
+ Pubid::Registry.register(:gost, Pubid::Gost)
@@ -10,14 +10,15 @@ module Pubid
10
10
  return build_annex(hash) if hash[:annex_marker]
11
11
 
12
12
  type_letter = stringify(hash[:type_letter])&.upcase
13
+ klass = Iala.identifier_klass_for_type_letter(type_letter)
13
14
 
14
15
  attrs = {
15
- number: build_number(hash, type_letter),
16
+ number: build_number(hash, klass),
16
17
  edition: stringify(hash.dig(:edition, :edition_value)),
17
18
  language: stringify(hash.dig(:language_group, :language))&.upcase,
18
19
  }.compact
19
20
 
20
- Iala.identifier_klass_for_type_letter(type_letter).new(**attrs)
21
+ klass.new(**attrs)
21
22
  end
22
23
 
23
24
  def self.build(parsed)
@@ -32,11 +33,11 @@ module Pubid
32
33
  def build_annex(hash)
33
34
  base_hash = hash[:base]
34
35
  base_type = stringify(base_hash[:type_letter])&.upcase
35
- base_number = build_number(base_hash, base_type)
36
- base = Iala.identifier_klass_for_type_letter(base_type).new(number: base_number)
36
+ base_klass = Iala.identifier_klass_for_type_letter(base_type)
37
+ base = base_klass.new(number: build_number(base_hash, base_klass))
37
38
 
38
39
  attrs = {
39
- base_identifier: base,
40
+ base: base,
40
41
  annex_form: stringify(hash[:annex_marker]),
41
42
  letter: stringify(hash[:annex_letter]),
42
43
  edition: stringify(hash.dig(:edition, :edition_value)),
@@ -49,43 +50,37 @@ module Pubid
49
50
  # Compose the full number string from the leading doc_number plus any
50
51
  # dotted continuation (GA01.13 → "01.13", L2.1.11 → "2.1.11") plus
51
52
  # the optional dash-separated subpart (C0103-1 → "0103-1", L2.7.1-2
52
- # → "2.7.1-2"). Padding is type-aware per IALA's canonical form:
53
- # typed S/R/G/M/C zero-pad to 4 digits; GeneralAssembly (GA) zero-
54
- # pads each segment to 2; Advices (A) and Letters (L) preserve input
55
- # (their canonical form is already what the IALA site prints).
56
- def build_number(hash, type_letter = nil)
53
+ # → "2.7.1-2"). Padding is class-driven: the resolved identifier
54
+ # class declares its canonical IALA cover-page widths via
55
+ # `canonical_number_width` / `canonical_dotted_segment_width`, so a
56
+ # new type declares its padding on its own class instead of editing
57
+ # this builder's case statement.
58
+ def build_number(hash, klass)
57
59
  base = stringify(hash[:doc_number])
58
60
  return base unless base
59
61
 
60
- base = canonical_base(base, type_letter)
62
+ base = canonical_base(base, klass)
61
63
 
62
64
  dots = hash[:doc_number_dots]
63
- dots_str = dots.is_a?(Array) ? "" : canonical_dots(stringify(dots).to_s, type_letter)
65
+ dots_str = dots.is_a?(Array) ? "" : canonical_dots(stringify(dots).to_s, klass)
64
66
 
65
67
  subpart_str = hash[:subpart] ? "-#{subpart_to_s(hash[:subpart])}" : ""
66
68
  subpart_str = "" if subpart_str == "-"
67
69
  "#{base}#{dots_str}#{subpart_str}"
68
70
  end
69
71
 
70
- # Per-type canonical width for the leading numeric run.
71
- def canonical_base(base, type_letter)
72
- case type_letter
73
- when "S", "R", "G", "M", "C", "X", "P" then base.rjust(4, "0")
74
- when "GA" then base.rjust(2, "0")
75
- else base
76
- end
72
+ def canonical_base(base, klass)
73
+ width = klass&.canonical_number_width
74
+ width ? base.rjust(width, "0") : base
77
75
  end
78
76
 
79
- # Per-type canonical width for each dotted continuation segment.
80
- # `str` looks like ".13" or ".1.11" (leading dot, then digits).
81
- def canonical_dots(str, type_letter)
77
+ def canonical_dots(str, klass)
82
78
  return "" if str.empty?
83
79
 
84
- if type_letter == "GA"
85
- str.split(".", -1).map { |seg| seg.empty? ? seg : seg.rjust(2, "0") }.join(".")
86
- else
87
- str
88
- end
80
+ width = klass&.canonical_dotted_segment_width
81
+ return str unless width
82
+
83
+ str.split(".", -1).map { |seg| seg.empty? ? seg : seg.rjust(width, "0") }.join(".")
89
84
  end
90
85
 
91
86
  # The subpart capture may be an array of {subpart_number: "1"},
@@ -4,8 +4,7 @@ module Pubid
4
4
  module Iala
5
5
  # Base class for all IALA identifiers. Canonical name
6
6
  # Pubid::Iala::Identifier; every concrete IALA identifier
7
- # (Identifiers::*) descends from it, and Identifiers::Base — aliased
8
- # at the foot of identifiers/base.rb — points back to it.
7
+ # (Identifiers::*) descends from it.
9
8
  #
10
9
  # IALA identifiers have the form:
11
10
  # [IALA ]{S|R|G|M|C|X|P}<4-digit number>[-<subpart>][ Ed <edition>][ (<LangLetter>)]
@@ -62,6 +61,32 @@ module Pubid
62
61
  def type_letter
63
62
  self.class.type[:short]
64
63
  end
64
+
65
+ class << self
66
+ # Zero-pad the leading numeric run of the document number to this
67
+ # width. nil means preserve the input verbatim. Subclasses declare
68
+ # their canonical IALA cover-page form via `number_width` (e.g.
69
+ # Standard declares 4 → M0001; GeneralAssembly declares 2 → GA01).
70
+ # The builder consults this instead of branching on type_letter.
71
+ attr_reader :canonical_number_width
72
+
73
+ # Zero-pad each dotted continuation segment of the number to this
74
+ # width. nil means preserve verbatim. Only GeneralAssembly (GA)
75
+ # sets this today — its series.index form (01.01, 01.13) is the
76
+ # canonical cover-page shape.
77
+ attr_reader :canonical_dotted_segment_width
78
+
79
+ # DSL: declare the canonical zero-pad width for the leading number.
80
+ private
81
+
82
+ def number_width(width)
83
+ @canonical_number_width = width
84
+ end
85
+
86
+ def dotted_segment_width(width)
87
+ @canonical_dotted_segment_width = width
88
+ end
89
+ end
65
90
  end
66
91
  end
67
92
  end
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA Advices (A prefix). Numbering is dashed: A12-01, A13-04.
7
7
  # Carries no edition in the corpus.
8
- class Advice < Base
8
+ class Advice < Identifier
9
9
  def self.type
10
10
  { key: :advice, title: "Advice", short: "A" }
11
11
  end
@@ -11,19 +11,19 @@ module Pubid
11
11
  #
12
12
  # The case of the marker is preserved (Annex vs ANNEX) for round-trip
13
13
  # fidelity. Edition and language apply to the Annex itself, not the base.
14
- class Annex < Base
14
+ class Annex < Identifier
15
15
  # The publication this annex supplements. Always present; carries the
16
16
  # type letter and number (e.g. G1045).
17
- attribute :base_identifier, ::Pubid::Iala::Identifier, polymorphic: true
17
+ attribute :base, ::Pubid::Iala::Identifier, polymorphic: true
18
18
  # "Annex" or "ANNEX" — preserved verbatim for exact round-trip.
19
19
  attribute :annex_form, :string
20
20
  # "A", "B", "C", "D", or nil for the bare form.
21
21
  attribute :letter, :string
22
22
 
23
23
  key_value do
24
- map "base_identifier",
25
- with: { to: :base_identifier_to_kv,
26
- from: :base_identifier_from_kv }
24
+ map "base",
25
+ with: { to: :base_to_kv,
26
+ from: :base_from_kv }
27
27
  map "annex_form", to: :annex_form
28
28
  map "letter", to: :letter
29
29
  end
@@ -36,20 +36,20 @@ module Pubid
36
36
  # methods via public_send during (de)serialization — a `private`
37
37
  # section here raises NoMethodError on to_hash (matches the public
38
38
  # visibility of Oiml::SupplementIdentifier's identical helpers).
39
- def base_identifier_to_kv(model, doc)
40
- base = model.base_identifier
39
+ def base_to_kv(model, doc)
40
+ base = model.base
41
41
  return unless base
42
42
 
43
43
  doc.add_child(
44
- Lutaml::KeyValue::DataModel::Element.new("base_identifier",
44
+ Lutaml::KeyValue::DataModel::Element.new("base",
45
45
  base.to_hash),
46
46
  )
47
47
  end
48
48
 
49
- def base_identifier_from_kv(model, value)
49
+ def base_from_kv(model, value)
50
50
  return unless value
51
51
 
52
- model.base_identifier = ::Pubid::Iala::Identifier.from_hash(value)
52
+ model.base = ::Pubid::Iala::Identifier.from_hash(value)
53
53
  end
54
54
  end
55
55
  end
@@ -5,9 +5,12 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA General Assembly resolutions (GA prefix). Numbering is dotted
7
7
  # with a series and an index: GA01.01, GA01.13. No edition.
8
- class GeneralAssembly < Base
8
+ class GeneralAssembly < Identifier
9
+ number_width 2
10
+ dotted_segment_width 2
11
+
9
12
  def self.type
10
- { key: :"general-assembly", title: "General Assembly Resolution",
13
+ { key: :"general-assembly", title: "General Assembly Resolution",
11
14
  short: "GA" }
12
15
  end
13
16
  end
@@ -5,7 +5,9 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA Guidelines (G series).
7
7
  # Examples: G1015 Ed 2.2, G1078 Ed 2.1.
8
- class Guideline < Base
8
+ class Guideline < Identifier
9
+ number_width 4
10
+
9
11
  def self.type
10
12
  { key: :guideline, title: "Guideline", short: "G" }
11
13
  end
@@ -6,7 +6,7 @@ module Pubid
6
6
  # IALA Letters (L prefix). Numbering is dotted with a series, sub-series,
7
7
  # and item: L2.1.11, L2.7.1-2 (the trailing -2 is a sub-part on top of
8
8
  # the dotted number).
9
- class Letter < Base
9
+ class Letter < Identifier
10
10
  def self.type
11
11
  { key: :letter, title: "Letter", short: "L" }
12
12
  end
@@ -6,7 +6,9 @@ module Pubid
6
6
  # IALA Manuals (M prefix, planned).
7
7
  # Today manuals carry no code (NAVGUIDE, VTS Manual, …); M is
8
8
  # reserved for future numbered manuals.
9
- class Manual < Base
9
+ class Manual < Identifier
10
+ number_width 4
11
+
10
12
  def self.type
11
13
  { key: :manual, title: "Manual", short: "M" }
12
14
  end
@@ -5,7 +5,9 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA Model Courses (C series).
7
7
  # Examples: C0103-1 Ed 3.0, C2001-1 Ed 1.0.
8
- class ModelCourse < Base
8
+ class ModelCourse < Identifier
9
+ number_width 4
10
+
9
11
  def self.type
10
12
  { key: :"model-course", title: "Model Course", short: "C" }
11
13
  end
@@ -5,7 +5,9 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA Recommendations (R series).
7
7
  # Examples: R0103 Ed 3.1, R0126 Ed 2.0, R1024 Ed 1.0.
8
- class Recommendation < Base
8
+ class Recommendation < Identifier
9
+ number_width 4
10
+
9
11
  def self.type
10
12
  { key: :recommendation, title: "Recommendation", short: "R" }
11
13
  end
@@ -6,7 +6,7 @@ module Pubid
6
6
  # IALA Reports & Proceedings (X prefix, planned).
7
7
  # Today reports carry no code; X is reserved for future numbered
8
8
  # reports.
9
- class Report < Base
9
+ class Report < Identifier
10
10
  def self.type
11
11
  { key: :report, title: "Report", short: "X" }
12
12
  end
@@ -6,7 +6,7 @@ module Pubid
6
6
  # IALA Resolutions and other Council publications (P prefix,
7
7
  # planned). Today resolutions carry no code; P is reserved for
8
8
  # future numbered resolutions.
9
- class Resolution < Base
9
+ class Resolution < Identifier
10
10
  def self.type
11
11
  { key: :resolution, title: "Resolution", short: "P" }
12
12
  end
@@ -5,7 +5,9 @@ module Pubid
5
5
  module Identifiers
6
6
  # IALA Standards (S series).
7
7
  # Examples: S1010, S1020 Ed 2.0, S1070 Ed 2.0.
8
- class Standard < Base
8
+ class Standard < Identifier
9
+ number_width 4
10
+
9
11
  def self.type
10
12
  { key: :standard, title: "Standard", short: "S" }
11
13
  end
@@ -3,7 +3,6 @@
3
3
  module Pubid
4
4
  module Iala
5
5
  module Identifiers
6
- autoload :Base, "#{__dir__}/identifiers/base"
7
6
  autoload :Advice, "#{__dir__}/identifiers/advice"
8
7
  autoload :Annex, "#{__dir__}/identifiers/annex"
9
8
  autoload :Standard, "#{__dir__}/identifiers/standard"
@@ -24,7 +24,7 @@ module Pubid
24
24
  # the marker form is preserved verbatim ("Annex" vs "ANNEX"), then the
25
25
  # optional letter, edition, and language.
26
26
  def render_annex(id)
27
- base_str = id.base_identifier.to_s
27
+ base_str = id.base.to_s
28
28
  rendered = "#{base_str} #{id.annex_form}"
29
29
  rendered << " #{id.letter}" if id.letter
30
30
  rendered << " Ed #{id.edition}" if id.edition
@@ -31,7 +31,7 @@ module Pubid
31
31
  # G1045 Annex Ed 1 → urn:mrn:iala:pub:g1045:annex:ed1
32
32
  # G1128 ANNEX A Ed 1.6 (E) → urn:mrn:iala:pub:g1128:annex-a:ed1.6:e
33
33
  def generate_annex
34
- base = identifier.base_identifier
34
+ base = identifier.base
35
35
  parts = ["urn:mrn:iala:pub",
36
36
  "#{base.type_letter.downcase}#{base.number}"]
37
37
  annex_seg = identifier.letter ? "annex-#{identifier.letter.downcase}" : "annex"
@@ -6,11 +6,15 @@ module Pubid
6
6
  #
7
7
  # UrnGenerator emits:
8
8
  # urn:mrn:iala:pub:<type-lower><number>[:ed<edition>][:<lang-lower>]
9
+ # and for Annex identifiers:
10
+ # urn:mrn:iala:pub:<base-code>:annex[-<letter>][:ed<edition>][:<lang>]
9
11
  #
10
12
  # Examples:
11
13
  # urn:mrn:iala:pub:s1070:ed2.0 → IALA S1070 Ed 2.0
12
14
  # urn:mrn:iala:pub:r1016:ed2.0:f → IALA R1016 Ed 2.0 (F)
13
15
  # urn:mrn:iala:pub:c0103-1 → IALA C0103-1
16
+ # urn:mrn:iala:pub:g1045:annex:ed1 → IALA G1045 Annex Ed 1
17
+ # urn:mrn:iala:pub:g1128:annex-a:ed1.6 → IALA G1128 ANNEX A Ed 1.6
14
18
  class UrnParser < Pubid::UrnParser::Base
15
19
  PREFIX = "urn:mrn:iala:pub:".freeze
16
20
 
@@ -21,15 +25,28 @@ module Pubid
21
25
 
22
26
  edition = nil
23
27
  language = nil
28
+ annex_form = nil
29
+ annex_letter = nil
30
+
24
31
  parts.drop(1).each do |seg|
25
- if seg.start_with?("ed")
32
+ case seg
33
+ when /\Aannex(-([a-z]))?\z/i
34
+ # UrnGenerator emits "annex" (bare) for the Annex-without-letter
35
+ # form and "annex-X" (lettered) for the uppercase ANNEX form.
36
+ # The human parser accepts both "Annex" and "ANNEX"; mirror the
37
+ # generator's casing so URN round-trip is exact.
38
+ annex_letter = Regexp.last_match(2)&.upcase
39
+ annex_form = annex_letter ? "ANNEX" : "Annex"
40
+ when /\Aed/
26
41
  edition = seg.sub(/\Aed/, "")
27
- elsif seg.length == 1 && seg.match?(/\A[a-z]\z/i)
42
+ when /\A[a-z]\z/i
28
43
  language = seg.upcase
29
44
  end
30
45
  end
31
46
 
32
47
  text = "IALA #{code.upcase}"
48
+ text += " #{annex_form}" if annex_form
49
+ text += " #{annex_letter}" if annex_letter
33
50
  text += " Ed #{edition}" if edition
34
51
  text += " (#{language})" if language
35
52
  flavor_parse(text)
data/lib/pubid/iala.rb CHANGED
@@ -23,8 +23,8 @@ module Pubid
23
23
  end
24
24
 
25
25
  # Per-flavor format registry: inherits global formats, overrides :human
26
- Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
27
- Identifiers::Base.format_registry.register(:human, renderer: Iala::Renderer)
26
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
27
+ Identifier.format_registry.register(:human, renderer: Iala::Renderer)
28
28
 
29
29
  # Auto-discover all identifier types from the Identifiers namespace.
30
30
  # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
@@ -32,7 +32,7 @@ module Pubid
32
32
  @identifier_types ||= Identifiers.constants
33
33
  .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
34
34
  .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
35
- .reject { |c| c == Identifiers::Base }
35
+ .reject { |c| c == Identifier }
36
36
  end
37
37
 
38
38
  # Build typed stage index from identifier types
@@ -60,7 +60,7 @@ module Pubid
60
60
 
61
61
  # Look up an identifier class by its IALA type letter (S, R, G, M, C, X, P).
62
62
  # @param letter [String]
63
- # @return [Class<Identifiers::Base>]
63
+ # @return [Class<Identifier>]
64
64
  def self.identifier_klass_for_type_letter(letter)
65
65
  @by_letter ||= identifier_types.to_h { |klass| [klass.type[:short], klass] }
66
66
  @by_letter.fetch(letter.to_s.upcase)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Iana
5
+ # Builds an IANA identifier object from a parse tree. There is a single
6
+ # concrete type (Registry), so the builder just extracts the slug fields.
7
+ class Builder
8
+ def self.build(parsed_data)
9
+ new.build(parsed_data)
10
+ end
11
+
12
+ def build(data)
13
+ Identifiers::Registry.new(
14
+ registry: data[:registry].to_s,
15
+ sub_registry: data[:sub_registry]&.to_s,
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Iana
5
+ # Base class for every IANA identifier AND the flavor's parse/create entry
6
+ # point. Concrete identifiers under Pubid::Iana::Identifiers descend from
7
+ # this class, so a parsed IANA id is an instance of Pubid::Iana::Identifier.
8
+ #
9
+ # IANA entries are protocol registries, not numbered standards: the value is
10
+ # a hierarchical registry slug (`registry` before the single "/", optional
11
+ # `sub_registry` after it). Both are kept verbatim.
12
+ class Identifier < ::Pubid::Identifier
13
+ # The registry slug (e.g. "_6lowpan-parameters"). Required.
14
+ attribute :registry, :string
15
+ # The sub-registry slug (e.g. "lowpan_nhc"). nil for top registries; a nil
16
+ # default means it is dropped from the serialized hash when absent.
17
+ attribute :sub_registry, :string
18
+
19
+ # Polymorphic type map for lutaml::Model key_value (de)serialization: maps
20
+ # the single Registry subclass's polymorphic_name to its class name so a
21
+ # stored hash rebuilds the correct identifier type via from_hash.
22
+ IANA_TYPE_MAP = {
23
+ "pubid:iana:registry" => "Pubid::Iana::Identifiers::Registry",
24
+ }.freeze
25
+
26
+ key_value do
27
+ map "_type", to: :_type, polymorphic_map: IANA_TYPE_MAP
28
+ map "registry", to: :registry
29
+ map "sub_registry", to: :sub_registry
30
+ end
31
+
32
+ # Publisher is always "IANA". A plain constant (not a `publisher` method)
33
+ # so it doesn't shadow the inherited lutaml `publisher` attribute, which
34
+ # would otherwise fail serialization type validation.
35
+ PUBLISHER = "IANA"
36
+
37
+ # Render-time flag stashed by #to_s; when false, the "IANA " token is
38
+ # dropped so callers can recover the bare index-key slug.
39
+ attr_reader :with_publisher
40
+
41
+ # The rendered registry code, e.g. "_6lowpan-parameters/lowpan_nhc".
42
+ def code
43
+ sub_registry ? "#{registry}/#{sub_registry}" : registry
44
+ end
45
+
46
+ # Basic string representation. Delegates to the renderer. Always emits the
47
+ # "IANA " token (the authoritative printed form) unless with_publisher is
48
+ # false, in which case the bare slug is rendered.
49
+ def to_s(with_publisher: true, **opts)
50
+ @with_publisher = with_publisher
51
+ render(format: :human, **opts)
52
+ end
53
+
54
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier;
55
+ # IANA_TYPE_MAP remains as the key_value polymorphic_map.
56
+
57
+ # Parse an IANA identifier string into an identifier object
58
+ # @param identifier [String] The IANA identifier string to parse
59
+ # @return [Identifier] The appropriate identifier object
60
+ def self.parse(identifier)
61
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
62
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
63
+ end
64
+
65
+ parsed = Parser.parse(identifier)
66
+ Builder.build(parsed)
67
+ rescue Parslet::ParseFailed => e
68
+ raise "Failed to parse IANA identifier '#{identifier}': #{e.message}"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Iana
5
+ module Identifiers
6
+ # The sole IANA identifier type: a protocol registry (optionally with a
7
+ # sub-registry). Its class name yields the polymorphic `_type` tag
8
+ # "pubid:iana:registry".
9
+ #
10
+ # Examples:
11
+ # IANA _6lowpan-parameters
12
+ # IANA _6lowpan-parameters/lowpan_nhc
13
+ class Registry < Identifier
14
+ # IANA registries carry no revision/stage lifecycle; a single published
15
+ # typed stage keeps parity with the other flavors' type registries.
16
+ TYPED_STAGES = [
17
+ Pubid::Components::TypedStage.new(
18
+ code: :pubiana,
19
+ stage_code: :published,
20
+ type_code: :iana,
21
+ abbr: ["IANA"],
22
+ name: "IANA Registry",
23
+ harmonized_stages: [],
24
+ ),
25
+ ].freeze
26
+
27
+ def self.type
28
+ { key: :iana, web: :registry, title: "IANA Registry", short: "IANA" }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Iana
5
+ module Identifiers
6
+ autoload :Registry, "#{__dir__}/identifiers/registry"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Iana
7
+ # Parslet grammar for IANA registry identifiers.
8
+ #
9
+ # Accepts the authoritative printed form "IANA <slug>[/<sub-slug>]" as well
10
+ # as a bare index-key slug (no "IANA " prefix). The optional prefix is
11
+ # consumed and discarded — the renderer always re-emits it.
12
+ #
13
+ # Slugs use only [a-zA-Z0-9._-] and contain at most one "/", so a plain
14
+ # character-class repeat parses them; there is no ReDoS surface.
15
+ class Parser < Parslet::Parser
16
+ # A single registry slug: letters, digits, dot, underscore, hyphen.
17
+ rule(:slug) { match['a-zA-Z0-9._\-'].repeat(1) }
18
+
19
+ # Optional publisher prefix. The trailing space is required, so a
20
+ # space-free slug never triggers it; PEG `.maybe` backtracks the whole
21
+ # sequence if the space is absent (e.g. a slug that happens to start
22
+ # "IANA...").
23
+ rule(:iana_prefix) { (str("IANA") >> str(" ")).maybe }
24
+
25
+ rule(:identifier) do
26
+ iana_prefix >>
27
+ slug.as(:registry) >>
28
+ (str("/") >> slug.as(:sub_registry)).maybe
29
+ end
30
+
31
+ rule(:root) { identifier }
32
+
33
+ def self.parse(input)
34
+ new.parse(input)
35
+ end
36
+ end
37
+ end
38
+ end