pubid 2.0.0.pre.alpha.7 → 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 (485) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +9 -50
  3. data/data/bipm/update_codes.yaml +9 -0
  4. data/data/iec/update_codes.yaml +3 -0
  5. data/data/ieee/update_codes.yaml +107 -1
  6. data/data/nist/series.yaml +155 -0
  7. data/data/nist/update_codes.yaml +8 -0
  8. data/lib/pubid/adobe/builder.rb +52 -0
  9. data/lib/pubid/adobe/identifier.rb +49 -0
  10. data/lib/pubid/adobe/identifiers/publication.rb +31 -0
  11. data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
  12. data/lib/pubid/adobe/identifiers.rb +10 -0
  13. data/lib/pubid/adobe/parser.rb +128 -0
  14. data/lib/pubid/adobe/renderer.rb +39 -0
  15. data/lib/pubid/adobe/urn_generator.rb +42 -0
  16. data/lib/pubid/adobe/urn_parser.rb +69 -0
  17. data/lib/pubid/adobe.rb +60 -0
  18. data/lib/pubid/amca/builder.rb +2 -2
  19. data/lib/pubid/amca/identifier.rb +1 -3
  20. data/lib/pubid/amca/identifiers/base.rb +1 -6
  21. data/lib/pubid/amca/identifiers/interpretation.rb +1 -1
  22. data/lib/pubid/amca/identifiers/publication.rb +1 -1
  23. data/lib/pubid/amca/identifiers/standard.rb +1 -1
  24. data/lib/pubid/amca/identifiers.rb +0 -1
  25. data/lib/pubid/amca/single_identifier.rb +1 -1
  26. data/lib/pubid/amca.rb +3 -3
  27. data/lib/pubid/ashrae/builder.rb +22 -22
  28. data/lib/pubid/ashrae/identifier.rb +3 -4
  29. data/lib/pubid/ashrae/identifiers/addenda_package.rb +1 -1
  30. data/lib/pubid/ashrae/identifiers/addendum.rb +1 -1
  31. data/lib/pubid/ashrae/identifiers/base.rb +14 -8
  32. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +1 -1
  33. data/lib/pubid/ashrae/identifiers.rb +0 -1
  34. data/lib/pubid/ashrae/parser.rb +14 -9
  35. data/lib/pubid/ashrae/renderer.rb +19 -19
  36. data/lib/pubid/ashrae/single_identifier.rb +1 -1
  37. data/lib/pubid/ashrae/supplement_identifier.rb +6 -6
  38. data/lib/pubid/ashrae.rb +3 -3
  39. data/lib/pubid/bipm/builder.rb +107 -0
  40. data/lib/pubid/bipm/identifier.rb +160 -0
  41. data/lib/pubid/bipm/identifiers/committee_document.rb +24 -0
  42. data/lib/pubid/bipm/identifiers/guide.rb +24 -0
  43. data/lib/pubid/bipm/identifiers/meeting.rb +41 -0
  44. data/lib/pubid/bipm/identifiers/mep.rb +21 -0
  45. data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
  46. data/lib/pubid/bipm/identifiers/si_brochure.rb +20 -0
  47. data/lib/pubid/bipm/identifiers.rb +15 -0
  48. data/lib/pubid/bipm/parser.rb +184 -0
  49. data/lib/pubid/bipm/renderer.rb +110 -0
  50. data/lib/pubid/bipm/urn_generator.rb +58 -0
  51. data/lib/pubid/bipm/urn_parser.rb +52 -0
  52. data/lib/pubid/bipm.rb +86 -0
  53. data/lib/pubid/bsi/builder.rb +14 -14
  54. data/lib/pubid/bsi/identifier.rb +0 -1
  55. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
  56. data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
  57. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
  58. data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
  59. data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
  60. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
  61. data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
  62. data/lib/pubid/bsi/renderer.rb +8 -8
  63. data/lib/pubid/bsi/single_identifier.rb +48 -0
  64. data/lib/pubid/builder/base.rb +5 -3
  65. data/lib/pubid/bundled_identifier.rb +3 -3
  66. data/lib/pubid/calconnect/builder.rb +38 -0
  67. data/lib/pubid/calconnect/identifier.rb +117 -0
  68. data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
  69. data/lib/pubid/calconnect/identifiers.rb +9 -0
  70. data/lib/pubid/calconnect/parser.rb +54 -0
  71. data/lib/pubid/calconnect/renderer.rb +36 -0
  72. data/lib/pubid/calconnect/urn_generator.rb +33 -0
  73. data/lib/pubid/calconnect/urn_parser.rb +34 -0
  74. data/lib/pubid/calconnect.rb +77 -0
  75. data/lib/pubid/ccsds/builder.rb +1 -1
  76. data/lib/pubid/ccsds/identifier.rb +1 -1
  77. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  78. data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
  79. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  80. data/lib/pubid/cen_cenelec/builder.rb +46 -12
  81. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -2
  82. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +6 -0
  83. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -2
  84. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
  85. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  86. data/lib/pubid/cen_cenelec/renderer.rb +5 -5
  87. data/lib/pubid/cen_cenelec/supplement_identifier.rb +5 -5
  88. data/lib/pubid/cen_cenelec/urn_generator.rb +1 -1
  89. data/lib/pubid/cen_cenelec.rb +76 -72
  90. data/lib/pubid/cie/builder.rb +139 -24
  91. data/lib/pubid/cie/identifier.rb +7 -3
  92. data/lib/pubid/cie/identifiers/bundle.rb +32 -4
  93. data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
  94. data/lib/pubid/cie/identifiers/conference.rb +9 -4
  95. data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
  96. data/lib/pubid/cie/identifiers/dual_published.rb +4 -4
  97. data/lib/pubid/cie/identifiers/identical.rb +7 -7
  98. data/lib/pubid/cie/identifiers/joint_published.rb +8 -8
  99. data/lib/pubid/cie/identifiers/proceedings.rb +39 -0
  100. data/lib/pubid/cie/identifiers/standard.rb +33 -7
  101. data/lib/pubid/cie/identifiers/supplement.rb +24 -22
  102. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +6 -2
  103. data/lib/pubid/cie/identifiers.rb +2 -0
  104. data/lib/pubid/cie/parser.rb +54 -5
  105. data/lib/pubid/cie/single_identifier.rb +40 -1
  106. data/lib/pubid/cie/supplement_identifier.rb +29 -16
  107. data/lib/pubid/cie/urn_generator.rb +11 -8
  108. data/lib/pubid/cie.rb +0 -1
  109. data/lib/pubid/components/date.rb +21 -5
  110. data/lib/pubid/csa/builder.rb +1 -1
  111. data/lib/pubid/csa/composite_identifier.rb +17 -1
  112. data/lib/pubid/csa/identifier.rb +48 -3
  113. data/lib/pubid/csa/identifiers/bundled.rb +6 -0
  114. data/lib/pubid/csa/identifiers/combined.rb +6 -0
  115. data/lib/pubid/csa/identifiers/package.rb +2 -2
  116. data/lib/pubid/csa/parser.rb +6 -6
  117. data/lib/pubid/csa/wrapper_identifier.rb +17 -0
  118. data/lib/pubid/doi/builder.rb +18 -0
  119. data/lib/pubid/doi/identifier.rb +46 -0
  120. data/lib/pubid/doi/identifiers/resource.rb +30 -0
  121. data/lib/pubid/doi/identifiers.rb +9 -0
  122. data/lib/pubid/doi/parser.rb +52 -0
  123. data/lib/pubid/doi/renderer.rb +13 -0
  124. data/lib/pubid/doi.rb +55 -0
  125. data/lib/pubid/easc/builder.rb +55 -0
  126. data/lib/pubid/easc/identifier.rb +61 -0
  127. data/lib/pubid/easc/identifiers/pmg.rb +20 -0
  128. data/lib/pubid/easc/identifiers/rmg.rb +19 -0
  129. data/lib/pubid/easc/identifiers.rb +10 -0
  130. data/lib/pubid/easc/parser.rb +80 -0
  131. data/lib/pubid/easc/renderer.rb +48 -0
  132. data/lib/pubid/easc/urn_generator.rb +46 -0
  133. data/lib/pubid/easc/urn_parser.rb +57 -0
  134. data/lib/pubid/easc.rb +52 -0
  135. data/lib/pubid/ecma/builder.rb +31 -0
  136. data/lib/pubid/ecma/identifier.rb +76 -0
  137. data/lib/pubid/ecma/identifiers/memento.rb +30 -0
  138. data/lib/pubid/ecma/identifiers/standard.rb +31 -0
  139. data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
  140. data/lib/pubid/ecma/identifiers.rb +11 -0
  141. data/lib/pubid/ecma/parser.rb +41 -0
  142. data/lib/pubid/ecma/renderer.rb +46 -0
  143. data/lib/pubid/ecma/urn_generator.rb +25 -0
  144. data/lib/pubid/ecma/urn_parser.rb +35 -0
  145. data/lib/pubid/ecma.rb +67 -0
  146. data/lib/pubid/etsi/builder.rb +7 -3
  147. data/lib/pubid/etsi/identifier.rb +1 -3
  148. data/lib/pubid/etsi/identifiers/base.rb +28 -10
  149. data/lib/pubid/etsi/identifiers/etsi_standard.rb +128 -4
  150. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +35 -3
  151. data/lib/pubid/etsi/identifiers.rb +0 -1
  152. data/lib/pubid/etsi/parser.rb +8 -2
  153. data/lib/pubid/etsi/renderer.rb +8 -2
  154. data/lib/pubid/etsi.rb +5 -5
  155. data/lib/pubid/export/exporter.rb +2 -1
  156. data/lib/pubid/export/flavor_exporter.rb +18 -3
  157. data/lib/pubid/gb/builder.rb +45 -0
  158. data/lib/pubid/gb/identifier.rb +64 -0
  159. data/lib/pubid/gb/identifiers/standard.rb +34 -0
  160. data/lib/pubid/gb/identifiers.rb +9 -0
  161. data/lib/pubid/gb/parser.rb +63 -0
  162. data/lib/pubid/gb/renderer.rb +35 -0
  163. data/lib/pubid/gb.rb +87 -0
  164. data/lib/pubid/gost/builder.rb +148 -0
  165. data/lib/pubid/gost/identifier.rb +49 -0
  166. data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
  167. data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
  168. data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
  169. data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
  170. data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
  171. data/lib/pubid/gost/identifiers.rb +13 -0
  172. data/lib/pubid/gost/parser.rb +97 -0
  173. data/lib/pubid/gost/renderer.rb +48 -0
  174. data/lib/pubid/gost/urn_generator.rb +46 -0
  175. data/lib/pubid/gost/urn_parser.rb +52 -0
  176. data/lib/pubid/gost.rb +49 -0
  177. data/lib/pubid/iala/builder.rb +22 -27
  178. data/lib/pubid/iala/identifier.rb +27 -2
  179. data/lib/pubid/iala/identifiers/advice.rb +1 -1
  180. data/lib/pubid/iala/identifiers/annex.rb +14 -12
  181. data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
  182. data/lib/pubid/iala/identifiers/guideline.rb +3 -1
  183. data/lib/pubid/iala/identifiers/letter.rb +1 -1
  184. data/lib/pubid/iala/identifiers/manual.rb +3 -1
  185. data/lib/pubid/iala/identifiers/model_course.rb +3 -1
  186. data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
  187. data/lib/pubid/iala/identifiers/report.rb +1 -1
  188. data/lib/pubid/iala/identifiers/resolution.rb +1 -1
  189. data/lib/pubid/iala/identifiers/standard.rb +3 -1
  190. data/lib/pubid/iala/identifiers.rb +0 -1
  191. data/lib/pubid/iala/renderer.rb +1 -1
  192. data/lib/pubid/iala/urn_generator.rb +1 -1
  193. data/lib/pubid/iala/urn_parser.rb +19 -2
  194. data/lib/pubid/iala.rb +4 -4
  195. data/lib/pubid/iana/builder.rb +20 -0
  196. data/lib/pubid/iana/identifier.rb +72 -0
  197. data/lib/pubid/iana/identifiers/registry.rb +33 -0
  198. data/lib/pubid/iana/identifiers.rb +9 -0
  199. data/lib/pubid/iana/parser.rb +38 -0
  200. data/lib/pubid/iana/renderer.rb +29 -0
  201. data/lib/pubid/iana/urn_generator.rb +15 -0
  202. data/lib/pubid/iana/urn_parser.rb +24 -0
  203. data/lib/pubid/iana.rb +69 -0
  204. data/lib/pubid/identifier.rb +210 -23
  205. data/lib/pubid/idf/builder.rb +1 -1
  206. data/lib/pubid/idf/parser.rb +2 -2
  207. data/lib/pubid/idf/renderer.rb +1 -1
  208. data/lib/pubid/idf/supplement_identifier.rb +3 -3
  209. data/lib/pubid/iec/builder.rb +35 -25
  210. data/lib/pubid/iec/identifier.rb +47 -2
  211. data/lib/pubid/iec/identifiers/base.rb +2 -2
  212. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
  213. data/lib/pubid/iec/identifiers/fragment_identifier.rb +11 -11
  214. data/lib/pubid/iec/identifiers/international_standard.rb +8 -5
  215. data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
  216. data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
  217. data/lib/pubid/iec/identifiers/technical_report.rb +1 -1
  218. data/lib/pubid/iec/identifiers/technical_specification.rb +1 -1
  219. data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
  220. data/lib/pubid/iec/identifiers.rb +1 -0
  221. data/lib/pubid/iec/parser.rb +51 -10
  222. data/lib/pubid/iec/renderer.rb +18 -8
  223. data/lib/pubid/iec/single_identifier.rb +1 -1
  224. data/lib/pubid/iec/supplement_identifier.rb +32 -19
  225. data/lib/pubid/iec.rb +1 -6
  226. data/lib/pubid/ieee/aiee/builder.rb +17 -3
  227. data/lib/pubid/ieee/aiee/identifier.rb +45 -61
  228. data/lib/pubid/ieee/builder.rb +341 -68
  229. data/lib/pubid/ieee/compaction.rb +121 -0
  230. data/lib/pubid/ieee/components/draft.rb +47 -7
  231. data/lib/pubid/ieee/identifier.rb +1 -3
  232. data/lib/pubid/ieee/identifiers/adopted_standard.rb +30 -5
  233. data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
  234. data/lib/pubid/ieee/identifiers/base.rb +106 -13
  235. data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
  236. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
  237. data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
  238. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +3 -3
  239. data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
  240. data/lib/pubid/ieee/identifiers/dual_published.rb +3 -3
  241. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
  242. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +2 -1
  243. data/lib/pubid/ieee/identifiers/joint_development.rb +56 -11
  244. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
  246. data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
  247. data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
  248. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
  249. data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
  250. data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
  251. data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
  256. data/lib/pubid/ieee/identifiers/standard.rb +4 -1
  257. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
  258. data/lib/pubid/ieee/identifiers.rb +2 -1
  259. data/lib/pubid/ieee/ire/builder.rb +7 -6
  260. data/lib/pubid/ieee/ire/identifier.rb +48 -33
  261. data/lib/pubid/ieee/nesc/builder.rb +33 -20
  262. data/lib/pubid/ieee/nesc/parser.rb +15 -14
  263. data/lib/pubid/ieee/parser.rb +461 -43
  264. data/lib/pubid/ieee/pre_parser.rb +1 -1
  265. data/lib/pubid/ieee/renderer.rb +154 -57
  266. data/lib/pubid/ieee/typed_stages.rb +12 -1
  267. data/lib/pubid/ieee/urn_generator.rb +3 -5
  268. data/lib/pubid/ieee.rb +56 -3
  269. data/lib/pubid/ietf/builder.rb +62 -0
  270. data/lib/pubid/ietf/identifier.rb +5 -0
  271. data/lib/pubid/ietf/identifiers/base.rb +75 -0
  272. data/lib/pubid/ietf/identifiers/bcp.rb +25 -0
  273. data/lib/pubid/ietf/identifiers/fyi.rb +25 -0
  274. data/lib/pubid/ietf/identifiers/internet_draft.rb +29 -0
  275. data/lib/pubid/ietf/identifiers/rfc.rb +25 -0
  276. data/lib/pubid/ietf/identifiers/std.rb +25 -0
  277. data/lib/pubid/ietf/identifiers.rb +13 -0
  278. data/lib/pubid/ietf/parser.rb +43 -0
  279. data/lib/pubid/ietf/renderer.rb +26 -0
  280. data/lib/pubid/ietf/urn_generator.rb +23 -0
  281. data/lib/pubid/ietf/urn_parser.rb +35 -0
  282. data/lib/pubid/ietf.rb +76 -0
  283. data/lib/pubid/iho/identifier.rb +1 -3
  284. data/lib/pubid/iho/identifiers/base.rb +1 -7
  285. data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
  286. data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
  287. data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
  288. data/lib/pubid/iho/identifiers/publication.rb +1 -1
  289. data/lib/pubid/iho/identifiers/standard.rb +1 -1
  290. data/lib/pubid/iho/identifiers.rb +0 -1
  291. data/lib/pubid/iho.rb +7 -7
  292. data/lib/pubid/isbn/builder.rb +44 -0
  293. data/lib/pubid/isbn/check_digit.rb +53 -0
  294. data/lib/pubid/isbn/identifier.rb +63 -0
  295. data/lib/pubid/isbn/identifiers/book.rb +30 -0
  296. data/lib/pubid/isbn/identifiers.rb +9 -0
  297. data/lib/pubid/isbn/parser.rb +45 -0
  298. data/lib/pubid/isbn/renderer.rb +16 -0
  299. data/lib/pubid/isbn.rb +52 -0
  300. data/lib/pubid/iso/builder.rb +9 -4
  301. data/lib/pubid/iso/combined_identifier.rb +2 -2
  302. data/lib/pubid/iso/identifier.rb +17 -1
  303. data/lib/pubid/iso/identifiers/directives_supplement.rb +8 -8
  304. data/lib/pubid/iso/normalizer.rb +2 -2
  305. data/lib/pubid/iso/parser.rb +16 -12
  306. data/lib/pubid/iso/supplement_identifier.rb +19 -6
  307. data/lib/pubid/iso/urn_generator.rb +4 -1
  308. data/lib/pubid/iso/urn_parser.rb +1 -1
  309. data/lib/pubid/itu/builder.rb +230 -29
  310. data/lib/pubid/itu/components/code.rb +48 -5
  311. data/lib/pubid/itu/components/designation.rb +35 -0
  312. data/lib/pubid/itu/components.rb +1 -0
  313. data/lib/pubid/itu/identifier.rb +1 -3
  314. data/lib/pubid/itu/identifiers/addendum.rb +15 -0
  315. data/lib/pubid/itu/identifiers/amendment.rb +6 -28
  316. data/lib/pubid/itu/identifiers/annex.rb +13 -2
  317. data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
  318. data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
  319. data/lib/pubid/itu/identifiers/base.rb +341 -23
  320. data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
  321. data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
  322. data/lib/pubid/itu/identifiers/errata.rb +15 -0
  323. data/lib/pubid/itu/identifiers/handbook.rb +38 -0
  324. data/lib/pubid/itu/identifiers/question.rb +63 -0
  325. data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
  326. data/lib/pubid/itu/identifiers/report.rb +39 -0
  327. data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
  328. data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
  329. data/lib/pubid/itu/identifiers/supplement.rb +119 -14
  330. data/lib/pubid/itu/identifiers.rb +10 -1
  331. data/lib/pubid/itu/model.rb +1 -1
  332. data/lib/pubid/itu/parser.rb +480 -26
  333. data/lib/pubid/itu/urn_generator.rb +36 -6
  334. data/lib/pubid/itu/urn_parser.rb +8 -0
  335. data/lib/pubid/itu.rb +11 -3
  336. data/lib/pubid/jcgm/builder.rb +23 -13
  337. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
  338. data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
  339. data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
  340. data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
  341. data/lib/pubid/jcgm/identifiers.rb +2 -0
  342. data/lib/pubid/jcgm/parser.rb +66 -6
  343. data/lib/pubid/jcgm/renderer.rb +26 -12
  344. data/lib/pubid/jcgm/single_identifier.rb +74 -5
  345. data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
  346. data/lib/pubid/jcgm/urn_generator.rb +21 -13
  347. data/lib/pubid/jcgm/urn_parser.rb +15 -3
  348. data/lib/pubid/jis/identifier.rb +52 -0
  349. data/lib/pubid/nist/builder.rb +29 -9
  350. data/lib/pubid/nist/caster.rb +7 -45
  351. data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
  352. data/lib/pubid/nist/components/supplement.rb +5 -2
  353. data/lib/pubid/nist/configuration.rb +7 -1
  354. data/lib/pubid/nist/identifier.rb +1 -3
  355. data/lib/pubid/nist/identifiers/base.rb +121 -37
  356. data/lib/pubid/nist/identifiers/circular.rb +1 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +1 -1
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +1 -1
  361. data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +1 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +1 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +1 -1
  368. data/lib/pubid/nist/identifiers/monograph.rb +1 -1
  369. data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
  370. data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
  371. data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
  372. data/lib/pubid/nist/identifiers/report.rb +1 -1
  373. data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
  374. data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
  375. data/lib/pubid/nist/identifiers.rb +0 -1
  376. data/lib/pubid/nist/parser.rb +29 -4
  377. data/lib/pubid/nist/preprocessor.rb +15 -0
  378. data/lib/pubid/nist/router.rb +3 -2
  379. data/lib/pubid/nist/series/ir.rb +0 -3
  380. data/lib/pubid/nist/supplement_identifier.rb +9 -9
  381. data/lib/pubid/nist.rb +13 -12
  382. data/lib/pubid/oasis/builder.rb +77 -0
  383. data/lib/pubid/oasis/identifier.rb +82 -0
  384. data/lib/pubid/oasis/identifiers/standard.rb +29 -0
  385. data/lib/pubid/oasis/identifiers.rb +9 -0
  386. data/lib/pubid/oasis/parser.rb +34 -0
  387. data/lib/pubid/oasis/renderer.rb +29 -0
  388. data/lib/pubid/oasis/urn_generator.rb +25 -0
  389. data/lib/pubid/oasis/urn_parser.rb +22 -0
  390. data/lib/pubid/oasis.rb +74 -0
  391. data/lib/pubid/ogc/builder.rb +33 -0
  392. data/lib/pubid/ogc/identifier.rb +77 -0
  393. data/lib/pubid/ogc/identifiers/document.rb +26 -0
  394. data/lib/pubid/ogc/identifiers.rb +10 -0
  395. data/lib/pubid/ogc/parser.rb +40 -0
  396. data/lib/pubid/ogc/renderer.rb +33 -0
  397. data/lib/pubid/ogc/urn_generator.rb +14 -0
  398. data/lib/pubid/ogc/urn_parser.rb +22 -0
  399. data/lib/pubid/ogc.rb +71 -0
  400. data/lib/pubid/oiml/builder.rb +31 -7
  401. data/lib/pubid/oiml/identifier.rb +9 -1
  402. data/lib/pubid/oiml/parser.rb +11 -12
  403. data/lib/pubid/oiml/renderer.rb +13 -13
  404. data/lib/pubid/oiml/single_identifier.rb +20 -0
  405. data/lib/pubid/oiml/supplement_identifier.rb +9 -9
  406. data/lib/pubid/oiml/urn_parser.rb +23 -6
  407. data/lib/pubid/oiml.rb +4 -0
  408. data/lib/pubid/omg/builder.rb +19 -0
  409. data/lib/pubid/omg/identifier.rb +44 -0
  410. data/lib/pubid/omg/identifiers/specification.rb +32 -0
  411. data/lib/pubid/omg/identifiers.rb +9 -0
  412. data/lib/pubid/omg/parser.rb +40 -0
  413. data/lib/pubid/omg/renderer.rb +19 -0
  414. data/lib/pubid/omg.rb +51 -0
  415. data/lib/pubid/parsers/mr_string.rb +101 -7
  416. data/lib/pubid/plateau/builder.rb +8 -4
  417. data/lib/pubid/plateau/identifier.rb +1 -3
  418. data/lib/pubid/plateau/identifiers/base.rb +1 -6
  419. data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
  420. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  421. data/lib/pubid/plateau/identifiers.rb +0 -1
  422. data/lib/pubid/plateau/parser.rb +15 -5
  423. data/lib/pubid/plateau/renderer.rb +1 -1
  424. data/lib/pubid/plateau/supplement_identifier.rb +11 -11
  425. data/lib/pubid/plateau.rb +4 -4
  426. data/lib/pubid/renderers/human_readable.rb +3 -1
  427. data/lib/pubid/renderers/mr_string.rb +46 -4
  428. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  429. data/lib/pubid/rendering/supplement.rb +4 -4
  430. data/lib/pubid/sae/builder.rb +1 -1
  431. data/lib/pubid/sae/identifier.rb +1 -3
  432. data/lib/pubid/sae/identifiers/base.rb +10 -7
  433. data/lib/pubid/sae/identifiers.rb +0 -1
  434. data/lib/pubid/sae.rb +3 -3
  435. data/lib/pubid/tgpp/builder.rb +41 -0
  436. data/lib/pubid/tgpp/identifier.rb +91 -0
  437. data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
  438. data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
  439. data/lib/pubid/tgpp/identifiers.rb +11 -0
  440. data/lib/pubid/tgpp/parser.rb +62 -0
  441. data/lib/pubid/tgpp/renderer.rb +36 -0
  442. data/lib/pubid/tgpp/urn_generator.rb +20 -0
  443. data/lib/pubid/tgpp/urn_parser.rb +28 -0
  444. data/lib/pubid/tgpp.rb +78 -0
  445. data/lib/pubid/type_resolver.rb +59 -0
  446. data/lib/pubid/un/builder.rb +42 -0
  447. data/lib/pubid/un/identifier.rb +37 -0
  448. data/lib/pubid/un/identifiers/document.rb +24 -0
  449. data/lib/pubid/un/identifiers.rb +9 -0
  450. data/lib/pubid/un/parser.rb +25 -0
  451. data/lib/pubid/un/renderer.rb +11 -0
  452. data/lib/pubid/un.rb +46 -0
  453. data/lib/pubid/version.rb +1 -1
  454. data/lib/pubid/w3c/builder.rb +55 -0
  455. data/lib/pubid/w3c/identifier.rb +101 -0
  456. data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
  457. data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
  458. data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
  459. data/lib/pubid/w3c/identifiers/note.rb +30 -0
  460. data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
  461. data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
  462. data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
  463. data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
  464. data/lib/pubid/w3c/identifiers/standard.rb +12 -0
  465. data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
  466. data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
  467. data/lib/pubid/w3c/identifiers.rb +25 -0
  468. data/lib/pubid/w3c/parser.rb +43 -0
  469. data/lib/pubid/w3c/renderer.rb +35 -0
  470. data/lib/pubid/w3c/urn_generator.rb +18 -0
  471. data/lib/pubid/w3c/urn_parser.rb +36 -0
  472. data/lib/pubid/w3c.rb +67 -0
  473. data/lib/pubid/xsf/builder.rb +17 -0
  474. data/lib/pubid/xsf/identifier.rb +62 -0
  475. data/lib/pubid/xsf/identifiers/xep.rb +31 -0
  476. data/lib/pubid/xsf/identifiers.rb +9 -0
  477. data/lib/pubid/xsf/parser.rb +25 -0
  478. data/lib/pubid/xsf/renderer.rb +23 -0
  479. data/lib/pubid/xsf/urn_generator.rb +13 -0
  480. data/lib/pubid/xsf/urn_parser.rb +18 -0
  481. data/lib/pubid/xsf.rb +76 -0
  482. data/lib/pubid.rb +25 -1
  483. metadata +205 -4
  484. data/lib/pubid/cie/components/code.rb +0 -80
  485. data/lib/pubid/iala/identifiers/base.rb +0 -14
@@ -13,8 +13,13 @@ module Pubid
13
13
  rule(:dash) { str("-") }
14
14
  rule(:dot) { str(".") }
15
15
 
16
- # ITU prefix
17
- rule(:itu_prefix) { str("ITU") >> (dash | space) }
16
+ # ITU prefix — accepts an optional leading "Recommendation " long-form
17
+ # prefix that appears in ITU's own citation style (e.g. the twin-text
18
+ # and common-text forms in issues #233 / #234).
19
+ rule(:itu_prefix) do
20
+ (str("Recommendation ") >> str("ITU") >> (dash | space)) |
21
+ (str("ITU") >> (dash | space))
22
+ end
18
23
 
19
24
  # Sector (R, T, or D)
20
25
  rule(:sector) do
@@ -31,6 +36,22 @@ module Pubid
31
36
  ).as(:series)
32
37
  end
33
38
 
39
+ # A numeric series GROUP rather than a single document — "E-100",
40
+ # "E100-300", "G-100", "Q-500". Deliberately capped at ONE leading
41
+ # letter: two or more letters before the dash is a series-code DOCUMENT
42
+ # (EMC-5, MES-2, IMPL-8, SEC-QKD), handled by series_code_body, and the
43
+ # two must never shadow each other. That split is a corpus regularity,
44
+ # not an ITU rule — see the boundary spec.
45
+ rule(:series_group) do
46
+ (letter >> digits.maybe >> dash >> digits).as(:series)
47
+ end
48
+
49
+ # The literal word "series" — "ITU-T E-300 series Suppl. 1",
50
+ # "ITU-T E.1100 series Suppl. 1". It is NOT part of the series token (it
51
+ # also follows a dotted code, where folding it in would corrupt the value
52
+ # every index row is keyed on), so it is carried as its own marker.
53
+ rule(:series_word) { space >> str("series").as(:series_word) }
54
+
34
55
  # Number
35
56
  rule(:number) do
36
57
  digits.as(:number)
@@ -40,6 +61,70 @@ module Pubid
40
61
  dot >> digits.as(:subseries)
41
62
  end
42
63
 
64
+ # Edition words. "bis" = 2nd edition, "ter" = 3rd, "quater" = 4th.
65
+ # "quarter" is a real misspelling in ITU's own data, kept verbatim so the
66
+ # two records it appears on stay distinct from their "quater" siblings.
67
+ rule(:series_suffix_word) do
68
+ str("bis") | str("ter") | str("quater") | str("quarter")
69
+ end
70
+
71
+ # Edition suffix attached directly to the recommendation number.
72
+ # Example: X.50bis, V.8bis, V.31bis.
73
+ rule(:series_suffix) { series_suffix_word.as(:series_suffix) }
74
+
75
+ # The same word separated by a space — "ITU-T E.250 bis (12/1972)",
76
+ # "ITU-T V.25 ter". The captured space IS the marker: its presence sets
77
+ # Code#series_suffix_spaced, so the glued form above still round-trips
78
+ # byte-exactly (locked by recommendation_spec.rb's issue-#231 block).
79
+ rule(:series_suffix_spaced) do
80
+ space.as(:series_suffix_spaced) >> series_suffix_word.as(:series_suffix)
81
+ end
82
+
83
+ # A single trailing letter distinguishing variants of one Recommendation:
84
+ # "ITU-T D.200 R", "ITU-T Q.2931 B", "ITU-T R.38 A", the glued
85
+ # "ITU-T D.502R" and the lowercase "ITU-T I.256.2a".
86
+ #
87
+ # TWO guards make this safe, and both are load-bearing:
88
+ # * the A-R cap keeps it clear of the "S" of " Suppl." and the "V" of a
89
+ # bare version marker (" V2");
90
+ # * the trailing absent? forbids any further letter/digit, so " Amd."
91
+ # (A then "m"), " Add.", " Annex A" (A then "n"), " App." , " Cor."
92
+ # (C then "o") and " Err." (E then "r") can never be mistaken for a
93
+ # qualifier.
94
+ # It cannot collide with `language` (dash-attached, "-F") nor with
95
+ # date_part/version_part, which both need "(" after the space.
96
+ rule(:qualifier_letter) do
97
+ (match["A-R"] | match["a-r"]).as(:qualifier) >>
98
+ match["A-Za-z0-9"].absent?
99
+ end
100
+
101
+ rule(:qualifier_glued) { qualifier_letter }
102
+ rule(:qualifier_spaced) do
103
+ space.as(:qualifier_spaced) >> qualifier_letter
104
+ end
105
+
106
+ # Print-form suffixes that may trail a code with a separating space. They
107
+ # cannot live inside `code` itself, because the space would then also be
108
+ # offered to " Suppl." / " Annex" and would have to backtrack out of a
109
+ # rule the wrappers depend on. Spliced after `code` and BEFORE
110
+ # combined_suffixes, since the corpus attaches the primary designation's
111
+ # suffix before the "/" ("ITU-T D.301 R/F.66").
112
+ rule(:code_suffixes) do
113
+ series_suffix_spaced.maybe >> qualifier_spaced.maybe
114
+ end
115
+
116
+ # "ITU-T H.350 attachment (08/2003)" — the machine-readable attachment
117
+ # published alongside a Recommendation, a distinct record in ITU's
118
+ # catalogue. A bare marker word: the flag alone reconstructs it.
119
+ rule(:attachment) { space >> str("attachment").as(:attachment) }
120
+
121
+ # A range of Recommendations published as one document —
122
+ # "ITU-T Q.120-Q.139 (11/1988)". No conflict with `parts`, which requires
123
+ # digits after the dash and so cannot match "-Q.139".
124
+ rule(:range_end) do
125
+ dash >> (letter.repeat(1, 3) >> dot >> digits).as(:range_end)
126
+ end
127
+
43
128
  # Parts
44
129
  rule(:part) do
45
130
  dash >> digits.as(:part)
@@ -47,9 +132,28 @@ module Pubid
47
132
 
48
133
  rule(:parts) { part.repeat(0).as(:parts) }
49
134
 
50
- # Code = number + subseries + parts
135
+ # Code = imp-prefixed code (Implementers' Guide) or standard code.
136
+ # The imp_code alternative is tried first because the standard code's
137
+ # number rule requires digits, which "Imp712" / "ImpOSI" would not
138
+ # satisfy.
51
139
  rule(:code) do
52
- number >> subseries.maybe >> parts
140
+ imp_code | standard_code
141
+ end
142
+
143
+ # The glued qualifier sits last, after parts, so "BO.600-1" still parses
144
+ # and "D.502R" / "I.256.2a" newly do.
145
+ rule(:standard_code) do
146
+ number >> series_suffix.maybe >> subseries.maybe >> parts >>
147
+ qualifier_glued.maybe
148
+ end
149
+
150
+ # Implementers' Guide code: "Imp" prefix followed by digits or a
151
+ # short letter string. Examples: Imp712 (G.Imp712), ImpOSI (X.ImpOSI).
152
+ rule(:imp_code) do
153
+ str("Imp").as(:imp_marker) >>
154
+ (digits | letter.repeat(1, 3)).as(:number) >>
155
+ subseries.maybe >>
156
+ parts
53
157
  end
54
158
 
55
159
  # Date
@@ -60,33 +164,100 @@ module Pubid
60
164
  str(")")
61
165
  end
62
166
 
167
+ # Version marker — "(V14)" in "ITU-T H.264 (V14) (08/2021)". Always sits
168
+ # between the code and the publication date, so it is spliced in before
169
+ # `date_part.maybe` in every document rule. `date_part` requires digits
170
+ # after "(", so it fails cleanly on "(V…)" and the two never compete.
171
+ # ITU emits four spellings of the same marker: the canonical
172
+ # parenthesised "(V14)" plus the bare "V2", "v10" and "v.1". All land in
173
+ # the same `version` attribute and re-render canonically as " (V##)" —
174
+ # the one deliberate non-byte-exact normalisation in this grammar.
175
+ #
176
+ # The bare branch requires digits immediately after V/v so it cannot fire
177
+ # on a stray word, and it is unreachable by the qualifier_letter rule
178
+ # below, whose A-R cap deliberately excludes "V".
179
+ rule(:version_part) do
180
+ space >>
181
+ (
182
+ (str("(V") >> digits.as(:version) >> str(")")) |
183
+ ((str("V") | str("v")) >> dot.maybe >> digits.as(:version))
184
+ )
185
+ end
186
+
63
187
  # Language
64
188
  rule(:language) do
65
189
  dash >> match["EFASCR"].as(:language)
66
190
  end
67
191
 
68
- # Combined identifier (Y.1351 part after slash)
69
- rule(:combined_suffix) do
192
+ # Combined (joint) recommendation — one additional "/SERIES.CODE"
193
+ # designation, e.g. the "/Y.1351" of "G.780/Y.1351". Repeatable, so
194
+ # triple-joint forms ("G.780/Y.1351/Z.1362") are captured as a list.
195
+ # Each designation is a self-contained subtree under :designation; the
196
+ # repeated list is collected under :combined.
197
+ # A designation may carry the same print-form suffixes as the primary
198
+ # code — "ITU-T D.300 R/E.282 R" (both halves qualified),
199
+ # "ITU-T D.81/F.80 bis" and "ITU-T E.211/Q.11 quater" (only the last).
200
+ # The suffix is stored on the designation it printed against; no attempt
201
+ # is made to decide whether it semantically qualifies the joint document.
202
+ #
203
+ # These slots sit INSIDE the .as(:designation) subtree, so they consume
204
+ # " bis" before the outer code_suffixes (which precedes combined_suffixes)
205
+ # can see it — that is what makes "trails the last designation" work
206
+ # without ambiguity.
207
+ rule(:combined_designation) do
70
208
  str("/") >>
71
- series.as(:combined_series) >>
72
- dot >>
73
- digits.as(:combined_number) >>
74
- subseries.maybe >>
75
- parts
209
+ (
210
+ series >> dot >> digits.as(:number) >>
211
+ subseries.maybe >> parts >>
212
+ qualifier_glued.maybe >>
213
+ series_suffix_spaced.maybe >>
214
+ qualifier_spaced.maybe
215
+ ).as(:designation)
216
+ end
217
+
218
+ rule(:combined_suffixes) do
219
+ combined_designation.repeat(1).as(:combined)
76
220
  end
77
221
 
78
- # Supplement types
222
+ # The "Technical" qualifier of a Corrigendum — "ITU-T H.222.0 (1995)
223
+ # Technical Cor. 1 (02/1998)". It is captured as its OWN marker key
224
+ # rather than folded into the supplement_type alternation, so the type
225
+ # token stays the plain "Cor." that Builder#build_supplement's case maps.
226
+ # It is bound to the Cor. branch alone, NOT to the head of
227
+ # supplement_type: only a corrigendum is ever printed "Technical", and
228
+ # only Corrigendum carries the flag. Offered before any token, the
229
+ # marker would be accepted on "Technical Err. 1" / "Technical Amd. 1"
230
+ # and then silently dropped by the builder, collapsing those onto a
231
+ # different document's identifier.
232
+ rule(:technical_marker) do
233
+ str("Technical").as(:technical) >> space
234
+ end
235
+
236
+ # Supplement types. The Cor. branch is its own alternative so the
237
+ # optional "Technical" can precede it without landing inside the
238
+ # .as(:supplement_type) capture — the builder maps that token by string
239
+ # equality. It goes last, which is free: no other branch can match a
240
+ # leading "Technical" or "Cor".
79
241
  rule(:supplement_type) do
80
242
  (
81
243
  str("Suppl.") | str("Suppl") |
82
244
  str("Amd.") | str("Amd") |
83
- str("Cor.") | str("Cor")
84
- ).as(:supplement_type)
245
+ str("Add.") | str("Add") |
246
+ str("Err.") | str("Err")
247
+ ).as(:supplement_type) |
248
+ (technical_marker.maybe >>
249
+ (str("Cor.") | str("Cor")).as(:supplement_type))
85
250
  end
86
251
 
87
- # Supplement number
252
+ # Supplement number. ITU omits the space before the ordinal on some
253
+ # listings ("ITU-T E Suppl.1", "ITU-T D.211 Suppl.1") and the ordinal is
254
+ # itself dotted on the M/O series ("ITU-T M Suppl. 1.1"). The absent
255
+ # space is captured as a marker so `to_s` reproduces it; the dotted
256
+ # ordinal lands whole in the :string `number` and cannot run into a
257
+ # following date, because (dot >> digits) stops at the space before "(".
88
258
  rule(:supplement_number) do
89
- space >> digits.as(:supplement_number)
259
+ space.as(:supplement_space).maybe >>
260
+ (digits >> (dot >> digits).repeat(0)).as(:supplement_number)
90
261
  end
91
262
 
92
263
  # Supplement date (separate from base date)
@@ -104,7 +275,12 @@ module Pubid
104
275
  space >>
105
276
  series >> dot >>
106
277
  code >>
107
- combined_suffix.maybe >>
278
+ range_end.maybe >>
279
+ code_suffixes >>
280
+ combined_suffixes.maybe >>
281
+ series_word.maybe >>
282
+ attachment.maybe >>
283
+ version_part.maybe >>
108
284
  date_part.maybe
109
285
  end
110
286
 
@@ -113,16 +289,182 @@ module Pubid
113
289
  sector >>
114
290
  space >>
115
291
  code >>
292
+ code_suffixes >>
293
+ attachment.maybe >>
294
+ version_part.maybe >>
295
+ date_part.maybe
296
+ end
297
+
298
+ # A series-code document — "EMC-5", "MES-2", "QOS-2", "IMPL-8",
299
+ # "SEC-QKD": a multi-letter mnemonic series dash-joined to a numeric or
300
+ # alphabetic document code. TWO letters minimum is the discriminator
301
+ # against series_group ("E-100", "G-100"), which has exactly one.
302
+ #
303
+ # This rule carries its own letter repeat, so the 1..3 cap on `series`
304
+ # (which stops the series token eating a following word) is untouched
305
+ # and "IMPL" still parses. It is deliberately a flat two-token shape
306
+ # (series + dash + alphanumeric number) rather than an optional middle
307
+ # segment: a greedy `letter.repeat(2)` would take "SEC", an optional
308
+ # "-QKD" would follow, and the required dash would then fail at
309
+ # end-of-input with no backtracking into the satisfied `.maybe`.
310
+ #
311
+ # The number stays in `code.number`, so `root.number` — the field
312
+ # relaton-index bsearches on — is "5" for EMC-5 and "QKD" for SEC-QKD
313
+ # rather than nil.
314
+ # The OB guard keeps "ITU-T OB-1" a clean parse failure. Without it the
315
+ # string reaches Builder#build's Recommendation fallback, whose
316
+ # validate_ob_no_sector! raises an ArgumentError that escapes
317
+ # Identifier.parse's Parslet::ParseFailed rescue — turning a rejected
318
+ # input into a crash for callers. It guards "OB" + dash specifically, so
319
+ # a genuine two-letter mnemonic starting "OB" would still parse.
320
+ rule(:series_code_body) do
321
+ (str("OB") >> dash).absent? >>
322
+ letter.repeat(2).as(:series) >> dash.as(:series_dash) >>
323
+ (digits | letter.repeat(1)).as(:number) >> parts
324
+ end
325
+
326
+ rule(:base_series_code) do
327
+ itu_prefix >>
328
+ sector >>
329
+ space >>
330
+ series_code_body >>
331
+ version_part.maybe >>
332
+ date_part.maybe
333
+ end
334
+
335
+ rule(:series_code_identifier) { base_series_code >> language.maybe }
336
+
337
+ # ITU-R Report — "Report ITU-R BT.2020-1 (2000)". Reports number
338
+ # independently of Recommendations, so the leading word is the ONLY thing
339
+ # distinguishing two real, different documents that share a
340
+ # series/number/edition. It is captured (unlike the decorative
341
+ # "Recommendation " of `itu_prefix`) so it reaches the built object.
342
+ rule(:report_word) { str("Report").as(:report_marker) }
343
+
344
+ # One body for both the with- and without-series shapes: `(series >> dot)`
345
+ # backtracks as a unit, so a numeric code ("Report ITU-R 2205") simply
346
+ # skips it.
347
+ #
348
+ # Deliberately NO combined_suffixes: a joint "Report X/Y" would reach
349
+ # Builder#build's `combined` branch, which builds a CombinedIdentifier and
350
+ # would silently drop the marker — a clean parse failure is better than a
351
+ # Report that comes back as a Recommendation. The OB guard mirrors
352
+ # series_code_body's: an Operational Bulletin is cross-bureau, and
353
+ # "Report ITU-T OB.1" would otherwise route to SpecialPublication (marker
354
+ # dropped) or hit validate_ob_no_sector!, whose ArgumentError escapes
355
+ # Identifier.parse's Parslet::ParseFailed rescue.
356
+ rule(:report_body) do
357
+ (str("OB") >> dot).absent? >>
358
+ (series >> dot).maybe >>
359
+ code >>
360
+ range_end.maybe >>
361
+ code_suffixes >>
362
+ series_word.maybe >>
363
+ attachment.maybe >>
364
+ version_part.maybe >>
116
365
  date_part.maybe
117
366
  end
118
367
 
119
- rule(:base_identifier) do
120
- base_with_series | base_without_series
368
+ # Both spellings ITU and downstream bibliographies use. `to_s` renders
369
+ # the leading (ITU's own) form for either.
370
+ rule(:base_report) do
371
+ (report_word >> space >> itu_prefix >> sector >> space >> report_body) |
372
+ (itu_prefix >> sector >> space >> report_word >> space >> report_body)
373
+ end
374
+
375
+ # Slot in `rule(:identifier)`: AFTER supplement/annex/appendix (all of
376
+ # which reach a Report through `base` and match the longer wrapped form
377
+ # "Report ITU-R BT.2020-1 Suppl. 1"), and BEFORE with_series, which would
378
+ # match the infix spelling's "ITU-R" prefix and then fail on the
379
+ # unconsumed " Report ...".
380
+ rule(:report_identifier) { base_report >> language.maybe }
381
+
382
+ # base_series_code goes LAST: it cannot shadow base_with_series (which
383
+ # needs series >> dot — "EMC" then "." fails on "-", and the greedy
384
+ # "IMP" of "IMPL" then fails on "L") nor base_without_series (whose code
385
+ # needs digits or "Imp"), so the last slot is both safe and the smallest
386
+ # blast radius.
387
+ # base_report goes FIRST and is order-free: `itu_prefix` admits only
388
+ # "Recommendation " or "ITU", and `letter` is [A-Z], so neither `series`
389
+ # (of base_with_series) nor `series_code_body` can consume the "Report"
390
+ # token of either spelling. Its presence is what lets a supplement, annex
391
+ # or appendix wrap a Report.
392
+ rule(:base) do
393
+ base_report | base_with_series | base_without_series | base_series_code
394
+ end
395
+
396
+ # Annex label — one series letter, optionally a number ("F3") and/or a
397
+ # "+" ("C+", ITU-T G.729 Annex C+).
398
+ rule(:annex_label) do
399
+ letter >> digits.maybe >> str("+").maybe
121
400
  end
122
401
 
123
- # Supplement with base identifier (has recommendation number)
402
+ # A labelled annex of a Recommendation — "ITU-T A.23 Annex A (06/2014)".
403
+ # The annexed document is wrapped in :base so its own date (the leading
404
+ # "(2002)" of "ITU-T X.692 (2002) Annex E (03/2002)") lands one level down
405
+ # and cannot collide with the annex's date — Parslet silently keeps only
406
+ # the last of two same-named keys in one flattened hash.
407
+ rule(:annex_body) do
408
+ base.as(:base) >>
409
+ space >> str("Annex") >> space >>
410
+ annex_label.as(:annex_number) >>
411
+ date_part.maybe
412
+ end
413
+
414
+ rule(:annex_identifier) { annex_body >> language.maybe }
415
+
416
+ # Appendix label — a Roman numeral ("I", "II", "IV", "VI").
417
+ rule(:roman) { match["IVX"].repeat(1) }
418
+
419
+ # A labelled appendix of a Recommendation — "ITU-T G.101 App. I
420
+ # (05/2000)", "ITU-T O.9 App.I (1998)". Structurally identical to
421
+ # annex_body, and for the same reason: the appendixed document is wrapped
422
+ # in :base so its own date (the leading "(1988)" of "ITU-T G.722 (1988)
423
+ # App. IV (11/2006)") lands one level down and cannot collide with the
424
+ # appendix's — Parslet silently keeps only the last of two same-named
425
+ # keys in one flattened hash. The space after "App." is optional in ITU's
426
+ # listings; rendering normalises it back to the spaced spelling.
427
+ rule(:appendix_body) do
428
+ base.as(:base) >>
429
+ space >> str("App.") >> space.maybe >>
430
+ roman.as(:appendix_number) >>
431
+ appendix_material.maybe >>
432
+ date_part.maybe
433
+ end
434
+
435
+ # The companion artefact of an appendix, published as its own record —
436
+ # "ITU-T G.726 App. II test vectors (03/1991)",
437
+ # "ITU-T G.728 App. I Software (07/1995)". A closed set of two literals,
438
+ # not free text, so it cannot swallow an unrelated tail.
439
+ rule(:appendix_material) do
440
+ space >> (str("test vectors") | str("Software")).as(:appendix_material)
441
+ end
442
+
443
+ rule(:appendix_identifier) { appendix_body >> language.maybe }
444
+
445
+ # Supplement with base identifier (has recommendation number).
446
+ # The base may itself be an annex ("... Annex B (1996) Cor. 3 (03/2001)");
447
+ # annex_body is tried first because it is the longer match. When it fails
448
+ # (an ordinary supplement, where " Suppl." follows the code instead of
449
+ # " Annex") the alternation falls through to the plain base.
124
450
  rule(:supplement_with_base) do
125
- base_identifier.as(:base) >>
451
+ (annex_body.as(:base) | appendix_body.as(:base) | base.as(:base)) >>
452
+ space >>
453
+ supplement_type >>
454
+ supplement_number >>
455
+ supplement_date.maybe >>
456
+ language.maybe
457
+ end
458
+
459
+ # A supplement whose base is itself a supplement — e.g. Errata on an
460
+ # Amendment ("G.9701 (2014) Amd. 3 Err. 1 (12/2017)") or Errata on a
461
+ # Corrigendum. The parse tree nests base-inside-base so the builder
462
+ # produces a Supplement whose base is another Supplement.
463
+ # The inner supplement may itself be the base-less, series-only form —
464
+ # "ITU-T G Suppl. 39 (2006) Err. 1 (08/2006)". supplement_with_base is
465
+ # tried first, being the longer match.
466
+ rule(:chained_supplement) do
467
+ (supplement_with_base | supplement_series_only).as(:base) >>
126
468
  space >>
127
469
  supplement_type >>
128
470
  supplement_number >>
@@ -131,11 +473,15 @@ module Pubid
131
473
  end
132
474
 
133
475
  # Supplement without base (series-only, like "ITU-T H Suppl. 1")
476
+ # series_group is tried FIRST: `series` is a greedy, non-backtracking
477
+ # letter.repeat(1,3), so it would match the "E" of "E-100" and then fail
478
+ # on the required space, with no retry at a shorter length.
134
479
  rule(:supplement_series_only) do
135
480
  itu_prefix >>
136
481
  sector >>
137
482
  space >>
138
- series >>
483
+ (series_group | series) >>
484
+ series_word.maybe >>
139
485
  space >>
140
486
  supplement_type >>
141
487
  supplement_number >>
@@ -143,9 +489,29 @@ module Pubid
143
489
  language.maybe
144
490
  end
145
491
 
146
- # Complete supplement identifier (try with base first, then series-only)
492
+ # A supplement joined to its predecessor by "/" rather than a space —
493
+ # "ITU-T X.680 (1994) Amd. 1/Technical Cor. 1 (12/1997)": one Technical
494
+ # Corrigendum issued against Amendment 1, sharing the trailing date.
495
+ # Modelled exactly like chained_supplement (base-inside-base) with a
496
+ # :supplement_slash marker so `to_s` reproduces the "/".
497
+ rule(:slash_chained_supplement) do
498
+ supplement_with_base.as(:base) >>
499
+ str("/").as(:supplement_slash) >>
500
+ supplement_type >>
501
+ supplement_number >>
502
+ supplement_date.maybe >>
503
+ language.maybe
504
+ end
505
+
506
+ # Complete supplement identifier. Both chained forms must precede
507
+ # supplement_with_base: it alone matches "ITU-T X.680 (1994) Amd. 1" and
508
+ # would leave "/Technical Cor. 1 (12/1997)" unconsumed, which fails the
509
+ # whole parse — PEG ordered choice never re-enters the alternation once
510
+ # an alternative succeeds. Space- and slash-joined are disjoint at that
511
+ # position, so their relative order is free.
147
512
  rule(:supplement_identifier) do
148
- supplement_with_base | supplement_series_only
513
+ chained_supplement | slash_chained_supplement |
514
+ supplement_with_base | supplement_series_only
149
515
  end
150
516
 
151
517
  # With series: ITU-R BO.600-1
@@ -155,7 +521,12 @@ module Pubid
155
521
  space >>
156
522
  series >> dot >>
157
523
  code >>
158
- combined_suffix.maybe >>
524
+ range_end.maybe >>
525
+ code_suffixes >>
526
+ combined_suffixes.maybe >>
527
+ series_word.maybe >>
528
+ attachment.maybe >>
529
+ version_part.maybe >>
159
530
  date_part.maybe >>
160
531
  language.maybe
161
532
  end
@@ -166,6 +537,9 @@ module Pubid
166
537
  sector >>
167
538
  space >>
168
539
  code >>
540
+ code_suffixes >>
541
+ attachment.maybe >>
542
+ version_part.maybe >>
169
543
  date_part.maybe >>
170
544
  language.maybe
171
545
  end
@@ -207,15 +581,95 @@ module Pubid
207
581
  str("Annex to") >> space >> special_publication.as(:annex_to)
208
582
  end
209
583
 
584
+ # Handbook — "ITU-R 42.HDB". The ".HDB" literal marks a Handbook; it does
585
+ # NOT route through subseries (which is digits-only). The :handbook_marker
586
+ # key tells the builder to build Identifiers::Handbook.
587
+ rule(:handbook) do
588
+ itu_prefix >>
589
+ sector >>
590
+ space >>
591
+ number >>
592
+ dot >> str("HDB").as(:handbook_marker) >>
593
+ date_part.maybe
594
+ end
595
+
596
+ # Numeric Question — "ITU-R 234-1/7:", "ITU-R 237/3:".
597
+ # number(-part)/study-group, always with a trailing ":".
598
+ rule(:numeric_question) do
599
+ itu_prefix >>
600
+ sector >>
601
+ space >>
602
+ number >>
603
+ parts >>
604
+ str("/") >> digits.as(:study_group) >>
605
+ str(":").as(:question_colon).maybe
606
+ end
607
+
608
+ # One "number(/BL)?/study-group" body of a letter-series Question, shared
609
+ # by the bracketed and bare forms.
610
+ rule(:question_tail) do
611
+ number >>
612
+ str("/BL").as(:has_bl).maybe >>
613
+ str("/") >> digits.as(:study_group)
614
+ end
615
+
616
+ # Letter-series Question — "ITU-R P.3/BL/7", "ITU-R SM.1/30",
617
+ # "ITU-R S.[4/BL/2]:". series.number(/BL)?/study-group, optionally
618
+ # bracketed and/or with a trailing ":".
619
+ rule(:letter_question) do
620
+ itu_prefix >>
621
+ sector >>
622
+ space >>
623
+ series >> dot >>
624
+ (
625
+ (str("[").as(:bracketed) >> question_tail >> str("]")) |
626
+ question_tail
627
+ ) >>
628
+ str(":").as(:question_colon).maybe
629
+ end
630
+
631
+ # Common-text suffix: "| ISO/IEC ..." or "| ISO ..." — the same
632
+ # document published jointly by ITU and ISO/IEC. Captured as a raw
633
+ # string; the builder parses it with the appropriate flavor.
634
+ rule(:common_text_twin) do
635
+ (space >> str("|") >> space >> match("[^|]").repeat(1)).as(:common_text_twin)
636
+ end
637
+
210
638
  rule(:identifier) do
211
639
  annex_to_identifier |
212
640
  special_publication |
213
641
  supplement_identifier |
642
+ # Both neighbours are load-bearing (PEG ordered choice never re-enters
643
+ # the alternation once an alternative succeeds): AFTER
644
+ # supplement_identifier, which matches the longer "<annex> Cor. 3"
645
+ # form, and BEFORE with_series, which would match the "ITU-T A.23"
646
+ # prefix of "ITU-T A.23 Annex A" and then fail on the unconsumed tail.
647
+ annex_identifier |
648
+ # Same slot reasoning as annex_identifier: AFTER supplement_identifier
649
+ # (an appendix can carry a trailing Amd./Err.) and BEFORE with_series
650
+ # (which would match the "ITU-T G.101" prefix and then fail on the
651
+ # unconsumed " App. I").
652
+ appendix_identifier |
653
+ # Slot reasoning at the rule itself.
654
+ report_identifier |
655
+ handbook |
656
+ numeric_question |
657
+ letter_question |
214
658
  with_series |
659
+ # Unreachable earlier: special_publication needs the literal "OB",
660
+ # handbook/numeric_question need leading digits, and letter_question
661
+ # needs series >> dot. Before without_series, whose code needs digits.
662
+ series_code_identifier |
215
663
  without_series
216
664
  end
217
665
 
218
- rule(:root) { identifier }
666
+ # Common-text form: an ITU identifier followed by "| ISO/IEC ...".
667
+ # Tried last so it doesn't shadow the simpler single-identifier forms.
668
+ rule(:common_text_identifier) do
669
+ identifier >> common_text_twin
670
+ end
671
+
672
+ rule(:root) { common_text_identifier | identifier }
219
673
 
220
674
  def self.parse(input)
221
675
  new.parse(input)