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
@@ -23,19 +23,37 @@ module Pubid
23
23
  parts << "itu"
24
24
  end
25
25
 
26
+ # An ITU-R Report numbers independently of the Recommendation series,
27
+ # so "BT.2020-1" alone is ambiguous — the type has to reach the URN as
28
+ # well as `to_s` and the MR slug, or the two documents share an
29
+ # identifier on that surface.
30
+ parts << "report" if identifier.is_a?(Identifiers::Report)
31
+
26
32
  if identifier.series
27
33
  series = identifier.series.to_s
28
34
  if identifier.code
29
- code = identifier.code.to_s
30
- parts << "#{series}.#{code}"
35
+ # A series-code document joins with a dash, not a dot; rendering it
36
+ # "EMC.5" would be ambiguous with a hypothetical "ITU-T EMC.5" and
37
+ # would not parse back.
38
+ join = identifier.series_dash ? "-" : "."
39
+ parts << "#{series}#{join}#{identifier.code.compact_s}"
31
40
  else
32
41
  parts << series
33
42
  end
34
43
  elsif identifier.code
35
- code = identifier.code.to_s
44
+ code = identifier.code.compact_s
36
45
  parts << code
37
46
  end
38
47
 
48
+ # Identity-bearing markers that are not part of sector/series/code.
49
+ # Without them "ITU-T H.350 attachment", "ITU-T Q.120-Q.139" and
50
+ # "ITU-T E-100 series Suppl. 2" would each share a URN with the
51
+ # document they are distinct from — the same collision Code#compact_s
52
+ # exists to prevent for the code suffixes.
53
+ parts << "series" if identifier.series_word
54
+ parts << "attachment" if identifier.attachment
55
+ parts << "to-#{identifier.range_end}" if identifier.range_end
56
+
39
57
  if identifier.date
40
58
  date = identifier.date
41
59
  if date&.year && date.month
@@ -57,8 +75,16 @@ module Pubid
57
75
 
58
76
  base = maybe(:base)
59
77
  if base
60
- base_gen = self.class.new(base)
61
- base_urn = base_gen.generate_base_urn
78
+ # An annex or appendix base holds its identity in its OWN base (its
79
+ # sector/series/code are nil), so generate_base_urn would emit
80
+ # "urn:itu:itu" for it — go through its own to_urn instead.
81
+ nested_wrapper = base.is_a?(Identifiers::AnnexOfRecommendation) ||
82
+ base.is_a?(Identifiers::AppendixOfRecommendation)
83
+ base_urn = if nested_wrapper
84
+ base.to_urn
85
+ else
86
+ self.class.new(base).generate_base_urn
87
+ end
62
88
 
63
89
  base_part = base_urn.sub(/^urn:itu:/, "")
64
90
  base_parts = base_part.split(":")
@@ -72,12 +98,16 @@ module Pubid
72
98
  if identifier.series
73
99
  series = identifier.series.to_s
74
100
  if identifier.code
75
- code = identifier.code.to_s
101
+ code = identifier.code.compact_s
76
102
  parts << "#{series}.#{code}"
77
103
  else
78
104
  parts << series
79
105
  end
80
106
  end
107
+ # A base-less supplement's whole identity is sector + series, so the
108
+ # series-group word belongs in the URN too — without it
109
+ # "ITU-T E-100 series Suppl. 2" and "ITU-T E-100 Suppl. 2" collide.
110
+ parts << "series" if identifier.series_word
81
111
  end
82
112
 
83
113
  supplement_notation = maybe(:supplement_notation)
@@ -16,6 +16,14 @@ module Pubid
16
16
  body = strip_namespace(urn)
17
17
  parts = split_parts(body)
18
18
  sector, code = parts
19
+
20
+ # UrnGenerator emits a "report" segment between the sector and the code
21
+ # for an ITU-R Report, which numbers independently of the
22
+ # Recommendation series (urn:itu:r:report:BT.2020-1).
23
+ if parts[1] == "report"
24
+ return flavor_parse("Report ITU-#{sector.upcase} #{parts[2]}")
25
+ end
26
+
19
27
  flavor_parse("ITU-#{sector.upcase} #{code}")
20
28
  end
21
29
  end
data/lib/pubid/itu.rb CHANGED
@@ -7,11 +7,19 @@ module Pubid
7
7
  extend Pubid::PrefixesSupport
8
8
 
9
9
  # Sole ITU publisher token (see the parser's `itu_prefix` rule).
10
+ #
11
+ # The leading "Report" of an ITU-R Report's canonical form
12
+ # ("Report ITU-R BT.2020-1") is deliberately NOT listed: prefix routing
13
+ # claims every reference beginning with the token, and "Report" is a
14
+ # generic English word that other SDOs' references start with — the
15
+ # mixin's documented exclusion for ambiguous tokens. Report references
16
+ # route by their "ITU" token in the infix spelling
17
+ # ("ITU-R Report BT.2020-1"), and `Pubid::Itu.parse` accepts both.
10
18
  PREFIXES = ["ITU"].freeze
11
19
 
12
20
  autoload :Builder, "#{__dir__}/itu/builder"
13
21
  autoload :Components, "#{__dir__}/itu/components"
14
- autoload :Identifier, "#{__dir__}/itu/identifier"
22
+ autoload :Identifier, "#{__dir__}/itu/identifiers/base"
15
23
  autoload :Identifiers, "#{__dir__}/itu/identifiers"
16
24
  autoload :Parser, "#{__dir__}/itu/parser"
17
25
  autoload :UrnGenerator, "#{__dir__}/itu/urn_generator"
@@ -32,9 +40,9 @@ module Pubid
32
40
  @identifier_types ||= Identifiers.constants
33
41
  .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
34
42
  .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
35
- # Exclude the flavor base itself by identity (Identifiers::Base is now an
43
+ # Exclude the flavor base itself by identity (Identifier is now an
36
44
  # alias for Pubid::Itu::Identifier, so name-based matching misses it).
37
- .reject { |c| c == Identifiers::Base }
45
+ .reject { |c| c == Identifier }
38
46
  end
39
47
 
40
48
  # Build typed stage index from identifier types
@@ -4,8 +4,11 @@ module Pubid
4
4
  module Jcgm
5
5
  class Builder < Pubid::Builder::Base
6
6
  def locate_identifier_klass(parsed_hash)
7
- if parsed_hash[:base_identifier]
8
- return Jcgm.locate_type(:amendment)
7
+ if parsed_hash[:base]
8
+ type_with_stage = parsed_hash[:type_with_stage]
9
+ return Jcgm.locate_type(:amendment) unless type_with_stage
10
+
11
+ return Jcgm.locate_type(locate_typed_stage(type_with_stage).type_code)
9
12
  end
10
13
 
11
14
  if parsed_hash[:gum_number]
@@ -22,15 +25,26 @@ module Pubid
22
25
  end
23
26
 
24
27
  def build(parsed_hash)
25
- identifier = locate_identifier_klass(parsed_hash).new
28
+ klass = locate_identifier_klass(parsed_hash)
29
+
30
+ # GUM guides store their part number in the shared `number` attribute
31
+ # ("JCGM GUM-6" -> number "6"); the parser tags it :gum_number only to
32
+ # pick this class. Fold it back onto :number before assigning.
33
+ if parsed_hash[:gum_number] && klass == Identifiers::GumGuide
34
+ parsed_hash = parsed_hash.merge(number: parsed_hash[:gum_number])
35
+ parsed_hash.delete(:gum_number)
36
+ end
37
+
38
+ identifier = klass.new
26
39
  assign_attributes(identifier, parsed_hash)
27
40
 
41
+ # Bare guides/gum-guides carry no parsed stage; derive the (single,
42
+ # published) typed_stage from the concrete class so parse and from_hash
43
+ # agree. Avoids the ambiguous locate_stage("") lookup (Guide and
44
+ # GumGuide both register abbr: [""]).
28
45
  if identifier.class.attributes.key?(:typed_stage) && identifier.typed_stage.nil?
29
- default_typed_stage = Jcgm.locate_stage("") ||
30
- raise(ArgumentError, "Unknown type abbreviation: ''")
31
- identifier.typed_stage = default_typed_stage
32
- identifier.stage = default_typed_stage.to_stage if identifier.class.attributes.key?(:stage)
33
- identifier.type = default_typed_stage.to_type if identifier.class.attributes.key?(:type)
46
+ identifier.typed_stage = identifier.class.published_typed_stage ||
47
+ raise(ArgumentError, "No published typed_stage for #{identifier.class}")
34
48
  end
35
49
 
36
50
  identifier
@@ -50,14 +64,12 @@ module Pubid
50
64
 
51
65
  def cast(type, value)
52
66
  case type
53
- when :base_identifier
67
+ when :base
54
68
  build(value)
55
69
  when :publisher
56
70
  Jcgm::Components::Publisher.new(publisher: value.to_s)
57
71
  when :number
58
72
  Pubid::Components::Code.new(value: value.to_s)
59
- when :gum_number
60
- Pubid::Components::Code.new(value: value.to_s)
61
73
  when :date
62
74
  date_str = value.to_s
63
75
  if date_str.include?("-")
@@ -70,8 +82,6 @@ module Pubid
70
82
  else
71
83
  Pubid::Components::Date.new(year: date_str)
72
84
  end
73
- when :iteration
74
- Pubid::Components::Code.new(value: value.to_s)
75
85
  when :type_with_stage
76
86
  typed_stage = locate_typed_stage(value.to_s)
77
87
  {
@@ -4,8 +4,6 @@ module Pubid
4
4
  module Jcgm
5
5
  module Identifiers
6
6
  class Amendment < SupplementIdentifier
7
- attribute :type, Pubid::Components::Type, default: -> { self.class.type[:key] }
8
-
9
7
  TYPED_STAGES = [
10
8
  Pubid::Components::TypedStage.new(
11
9
  code: :pubamd,
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Jcgm
5
+ module Identifiers
6
+ # A JCGM corrigendum. Two surface forms are supported:
7
+ #
8
+ # "JCGM 200:2008 Corrigendum" — base guide + trailing " Corrigendum"
9
+ # word, no iteration number
10
+ # "JCGM 101:2008/Cor 1:2009" — base guide + slash-separated
11
+ # numbered corrigendum with date
12
+ #
13
+ # The first form is the JCGM-native convention. The second mirrors the
14
+ # ISO/IEC supplement syntax and is needed to round-trip identifiers like
15
+ # "JCGM 101:2008/Cor 1:2009" (corrigendum to GUM Supplement 1).
16
+ class Corrigendum < SupplementIdentifier
17
+ TYPED_STAGES = [
18
+ Pubid::Components::TypedStage.new(
19
+ code: :pubcorr,
20
+ stage_code: :published,
21
+ type_code: :corrigendum,
22
+ abbr: %w[Corrigendum Cor],
23
+ name: "Corrigendum",
24
+ harmonized_stages: %w[60.00 60.60],
25
+ ),
26
+ ].freeze
27
+
28
+ def self.type
29
+ { key: :corrigendum, title: "Corrigendum", short: "Corr" }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -3,10 +3,10 @@
3
3
  module Pubid
4
4
  module Jcgm
5
5
  module Identifiers
6
+ # A GUM guide, e.g. "JCGM GUM-6:2020". The GUM-series part number ("6")
7
+ # lives in the inherited `number` attribute (serialized as `number: "6"`);
8
+ # `_type: pubid:jcgm:gum-guide` disambiguates it from a plain guide.
6
9
  class GumGuide < SingleIdentifier
7
- attribute :gum_number, Pubid::Components::Code
8
- attribute :type, Pubid::Components::Type, default: -> { self.class.type[:key] }
9
-
10
10
  TYPED_STAGES = [
11
11
  Pubid::Components::TypedStage.new(
12
12
  code: :pubgumguide,
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Jcgm
5
+ module Identifiers
6
+ # A JCGM committee/meeting record, e.g. "JCGM 17th Meeting (2012)".
7
+ #
8
+ # `number` (Components::Code) holds the meeting ordinal as a clean integer
9
+ # value ("17"); `date` (Components::Date, year-only) holds the year.
10
+ class Meeting < SingleIdentifier
11
+ TYPED_STAGES = [
12
+ Pubid::Components::TypedStage.new(
13
+ code: :pubmeeting,
14
+ stage_code: :published,
15
+ type_code: :jcgm_meeting,
16
+ abbr: ["Meeting"],
17
+ name: "Meeting",
18
+ harmonized_stages: %w[60.00 60.60],
19
+ ),
20
+ ].freeze
21
+
22
+ def self.type
23
+ { key: :jcgm_meeting, title: "Meeting" }
24
+ end
25
+
26
+ # Ordinal suffix as printed by the JCGM/BIPM data generator: a naive
27
+ # last-digit rule (1->st, 2->nd, 3->rd, else th) with NO 11/12/13 teens
28
+ # exception. The real records print "11st", "12nd", "13rd", so applying
29
+ # the standard-English teens exception would break round-trip.
30
+ def self.ordinal(number)
31
+ n = number.to_i
32
+ suffix = case n % 10
33
+ when 1 then "st"
34
+ when 2 then "nd"
35
+ when 3 then "rd"
36
+ else "th"
37
+ end
38
+ "#{n}#{suffix}"
39
+ end
40
+
41
+ def ordinal
42
+ self.class.ordinal(number&.value)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -4,8 +4,10 @@ module Pubid
4
4
  module Jcgm
5
5
  module Identifiers
6
6
  autoload :Amendment, "#{__dir__}/identifiers/amendment"
7
+ autoload :Corrigendum, "#{__dir__}/identifiers/corrigendum"
7
8
  autoload :Guide, "#{__dir__}/identifiers/guide"
8
9
  autoload :GumGuide, "#{__dir__}/identifiers/gum_guide"
10
+ autoload :Meeting, "#{__dir__}/identifiers/meeting"
9
11
  end
10
12
  end
11
13
  end
@@ -11,17 +11,72 @@ module Pubid
11
11
  root :identifier
12
12
 
13
13
  rule(:identifier) do
14
- amendment_identifier | base_identifier
14
+ meeting_identifier | amendment_identifier | corrigendum_identifier |
15
+ numbered_corrigendum_identifier | base | named_guide_identifier
15
16
  end
16
17
 
17
- rule(:base_identifier) do
18
- publisher >> space >> number_portion >> date_portion >> language_portion.maybe
18
+ # "JCGM 200:2008 Corrigendum" — a base guide plus a trailing
19
+ # " Corrigendum" word (no number). Must precede base: Parslet
20
+ # is an ordered PEG that commits to the first matching alternative, so if
21
+ # base ran first it would consume "JCGM 200:2008" and root
22
+ # would fail on the leftover " Corrigendum". Emits type_with_stage so the
23
+ # builder routes it to Corrigendum.
24
+ rule(:corrigendum_identifier) do
25
+ base.as(:base) >> space >>
26
+ str("Corrigendum").as(:type_with_stage)
27
+ end
28
+
29
+ # "JCGM 101:2008/Cor 1:2009" — a base guide plus a slash-separated
30
+ # numbered corrigendum (mirrors the ISO/IEC supplement form). The
31
+ # trailing :YYYY is optional so "JCGM 101:2008/Cor 1" also parses.
32
+ # Must precede base for the same PEG-commit reason as corrigendum_identifier.
33
+ rule(:numbered_corrigendum_identifier) do
34
+ base.as(:base) >>
35
+ str("/") >> str("Cor").as(:type_with_stage) >>
36
+ space >> digits.as(:number) >>
37
+ corrigendum_date.maybe
38
+ end
39
+
40
+ # Dateless "named" guides: "JCGM GUM", "JCGM VIM-3" (and future "VIM-N").
41
+ # Last in the alternation — only reached when base fully fails
42
+ # (these have no date, so number_portion/date_portion never match).
43
+ rule(:named_guide_identifier) do
44
+ publisher >> space >> named_number
45
+ end
46
+
47
+ rule(:named_number) do
48
+ (str("GUM") | (str("VIM") >> (str("-") >> digits).maybe)).as(:number)
49
+ end
50
+
51
+ # Committee/meeting record, e.g. "JCGM 17th Meeting (2012)". Diverges
52
+ # from base right after the digits (base wants ":", meeting
53
+ # wants the ordinal suffix), so ordered choice is unambiguous. Emits the
54
+ # same tokens as a guide plus type_with_stage "Meeting", so the generic
55
+ # builder path resolves it to Identifiers::Meeting (like "Amd").
56
+ rule(:meeting_identifier) do
57
+ publisher >> space >> digits.as(:number) >> ordinal_suffix >>
58
+ space >> str("Meeting").as(:type_with_stage) >> space >>
59
+ str("(") >> year_digits.as(:date) >> str(")")
60
+ end
61
+
62
+ rule(:ordinal_suffix) do
63
+ str("st") | str("nd") | str("rd") | str("th")
64
+ end
65
+
66
+ # `date_portion` is optional so a partial reference that omits the
67
+ # trailing `:YYYY` date (e.g. "JCGM 100") parses with `date` left nil,
68
+ # letting relaton match a collection via `matches?(row, ignore: [:date])`.
69
+ # The whole sub-rule is `.maybe` (not the year inside it) so a dangling
70
+ # ":" still fails. Mirrors ETSI (lib/pubid/etsi/parser.rb).
71
+ rule(:base) do
72
+ publisher >> space >> number_portion >>
73
+ date_portion.maybe >> language_portion.maybe
19
74
  end
20
75
 
21
76
  rule(:amendment_identifier) do
22
- base_identifier.as(:base_identifier) >>
77
+ base.as(:base) >>
23
78
  str("/") >> amendment_type >>
24
- space >> amendment_number >>
79
+ space >> digits.as(:number) >>
25
80
  amendment_date.maybe
26
81
  end
27
82
 
@@ -73,12 +128,17 @@ module Pubid
73
128
  end
74
129
 
75
130
  rule(:amendment_number) do
76
- digits.as(:iteration)
131
+ digits.as(:number)
77
132
  end
78
133
 
79
134
  rule(:amendment_date) do
80
135
  str(":") >> (full_date | year_only)
81
136
  end
137
+
138
+ # Numbered corrigendum date: same shape as amendment_date.
139
+ rule(:corrigendum_date) do
140
+ str(":") >> (full_date | year_only)
141
+ end
82
142
  end
83
143
  end
84
144
  end
@@ -13,20 +13,34 @@ module Pubid
13
13
  # registry and invoked via `render(format: :human)`.
14
14
  class Renderer < ::Pubid::Renderers::Base
15
15
  def render(context: nil, **opts)
16
- id = @id
17
-
18
- case id
19
- when Identifiers::Amendment
20
- render_amendment(id, context)
21
- when Identifiers::GumGuide
22
- render_gum_guide(id, context)
23
- else
24
- render_single(id)
16
+ case @id
17
+ when Identifiers::Amendment then render_amendment(@id, context)
18
+ when Identifiers::Corrigendum then render_corrigendum(@id)
19
+ when Identifiers::GumGuide then render_gum_guide(@id, context)
20
+ when Identifiers::Meeting then render_meeting(@id)
21
+ else render_single(@id)
25
22
  end
26
23
  end
27
24
 
28
25
  private
29
26
 
27
+ def render_corrigendum(id)
28
+ # Two surface forms:
29
+ # "JCGM 200:2008 Corrigendum" — number absent (word form)
30
+ # "JCGM 101:2008/Cor 1:2009" — number present (numbered form)
31
+ return "#{id.base}/Cor #{id.number}#{corrigendum_date_suffix(id)}" if id.number
32
+
33
+ "#{id.base} Corrigendum"
34
+ end
35
+
36
+ def corrigendum_date_suffix(id)
37
+ id.date ? ":#{id.date}" : ""
38
+ end
39
+
40
+ def render_meeting(id)
41
+ "JCGM #{id.ordinal} Meeting (#{id.date.year})"
42
+ end
43
+
30
44
  def render_single(id)
31
45
  parts = [id.publisher_portion]
32
46
  parts << id.number_portion unless id.number_portion.empty?
@@ -36,9 +50,9 @@ module Pubid
36
50
  end
37
51
 
38
52
  def render_amendment(id, context)
39
- result = id.base_identifier.to_s if id.base_identifier
53
+ result = id.base.to_s if id.base
40
54
  result += "/Amd"
41
- result += " #{id.iteration.render(context:)}" if id.iteration
55
+ result += " #{id.number.render(context:)}" if id.number
42
56
  result += ":#{id.date}" if id.date
43
57
  result
44
58
  end
@@ -46,7 +60,7 @@ module Pubid
46
60
  def render_gum_guide(id, context)
47
61
  parts = []
48
62
  parts << id.publisher.publisher if id.publisher
49
- parts << "GUM-#{id.gum_number.render(context:)}" if id.gum_number
63
+ parts << "GUM-#{id.number.render(context:)}" if id.number
50
64
 
51
65
  result = parts.join(" ")
52
66
  result += ":#{id.date}" if id.date
@@ -3,17 +3,86 @@
3
3
  module Pubid
4
4
  module Jcgm
5
5
  class SingleIdentifier < Identifier
6
- attribute :publisher, Jcgm::Components::Publisher
7
- attribute :typed_stage, Pubid::Components::TypedStage
6
+ attribute :publisher, Jcgm::Components::Publisher,
7
+ default: -> { self.class.default_publisher }
8
+ attribute :typed_stage, Pubid::Components::TypedStage,
9
+ default: -> { self.class.published_typed_stage }
8
10
  attribute :number, Pubid::Components::Code
9
11
  attribute :date, Pubid::Components::Date
10
12
  attribute :languages, Pubid::Components::Language, collection: true
11
13
  attribute :stage, Pubid::Components::Stage
12
14
  attribute :type, Pubid::Components::Type
13
15
 
14
- # Generate URN for this identifier
15
- #
16
- # @return [String] URN representation
16
+ # Compact serialization: only per-instance information is mapped. The
17
+ # publisher (always "JCGM") and the derived type / stage / typed_stage
18
+ # (fully determined by the class, i.e. `_type`) are intentionally NOT
19
+ # mapped — they are reconstructed from the class on load via the
20
+ # attribute defaults above. Components collapse to bare scalars:
21
+ # number -> "100" (not {value: "100"}); date -> year/month/day scalars.
22
+ # Mirrors ISO (lib/pubid/iso/identifier.rb) and OIML.
23
+ key_value do
24
+ map "_type", to: :_type
25
+ map "number", with: { to: :number_to_kv, from: :number_from_kv }
26
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
27
+ map "month", with: { to: :month_to_kv, from: :month_from_kv }
28
+ map "day", with: { to: :day_to_kv, from: :day_from_kv }
29
+ map "languages", to: :languages
30
+ end
31
+
32
+ # The publisher implied when none is serialized — always JCGM.
33
+ def self.default_publisher
34
+ Jcgm::Components::Publisher.new(publisher: Jcgm::PREFIXES.first)
35
+ end
36
+
37
+ # The class's published typed_stage (canonical surface form). Each JCGM
38
+ # class registers exactly one, all :published; `_type` fixes the class,
39
+ # so an omitted typed_stage reconstructs deterministically on from_hash.
40
+ def self.published_typed_stage
41
+ return nil unless const_defined?(:TYPED_STAGES)
42
+
43
+ ts = self::TYPED_STAGES.find { |t| t.stage_code.to_s == "published" }
44
+ return nil unless ts
45
+
46
+ ts = ts.dup
47
+ ts.original_abbr = ts.canonical_abbreviation
48
+ ts
49
+ end
50
+
51
+ # type and stage are derived from typed_stage, never stored — so the
52
+ # doctype (fixed by the class / _type) is not carried in the hash.
53
+ def type
54
+ typed_stage&.to_type
55
+ end
56
+
57
+ def stage
58
+ typed_stage&.to_stage
59
+ end
60
+
61
+ # --- number (Code) flattened to a bare string ---
62
+ def number_to_kv(model, doc) = emit_kv(doc, "number", model.number&.value)
63
+ def number_from_kv(model, value) = model.number = build_code(value)
64
+
65
+ def build_code(value)
66
+ Pubid::Components::Code.new(value: value.to_s)
67
+ end
68
+
69
+ # --- date flattened to top-level year/month/day scalars ---
70
+ def year_to_kv(model, doc) = emit_kv(doc, "year", model.date&.year)
71
+ def month_to_kv(model, doc) = emit_kv(doc, "month", model.date&.month)
72
+ def day_to_kv(model, doc) = emit_kv(doc, "day", model.date&.day)
73
+ def year_from_kv(model, value) = date_for(model).year = value.to_s
74
+ def month_from_kv(model, value) = date_for(model).month = value.to_s
75
+ def day_from_kv(model, value) = date_for(model).day = value.to_s
76
+
77
+ def emit_kv(doc, key, value)
78
+ return if value.nil? || value.to_s.empty?
79
+
80
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, value.to_s))
81
+ end
82
+
83
+ def date_for(model)
84
+ model.date ||= Pubid::Components::Date.new
85
+ end
17
86
 
18
87
  def publisher_portion
19
88
  publisher.to_s
@@ -3,13 +3,48 @@
3
3
  module Pubid
4
4
  module Jcgm
5
5
  # Base class for JCGM supplement identifiers (amendments, corrigenda, etc.)
6
+ #
7
+ # The supplement's OWN number (the "1" in "/Cor 1", the "2" in "/Amd 2")
8
+ # is stored in the inherited `number` attribute — NOT a separate
9
+ # `iteration` attribute. Each supplement is itself a numbered document,
10
+ # just like the base. The base document's number is accessed via
11
+ # `base.number`. This mirrors how pubid-Iso models supplements.
6
12
  class SupplementIdentifier < SingleIdentifier
7
- attribute :base_identifier, Identifier, polymorphic: true
8
- attribute :iteration, Pubid::Components::Code
13
+ attribute :base, Identifier, polymorphic: true
9
14
 
10
- # Delegate publisher to base_identifier
15
+ # The base document nests under the compact key "base" (mirrors ISO/JIS),
16
+ # serialized via its own to_hash so it collapses to {_type, number, year}.
17
+ # On load the sub-hash is re-dispatched through Jcgm::Identifier.from_hash,
18
+ # which resolves `_type` to the concrete Guide/GumGuide — a bare
19
+ # polymorphic cast would rebuild it as a plain Identifier and later fail
20
+ # on publisher_portion. This custom mapping replaces the former
21
+ # self.from_hash override.
22
+ #
23
+ # `number` (the supplement's own number) is mapped by SingleIdentifier's
24
+ # key_value block via number_to_kv / number_from_kv — no override needed.
25
+ key_value do
26
+ map "base", with: { to: :base_to_kv, from: :base_from_kv }
27
+ end
28
+
29
+ def base_to_kv(model, doc)
30
+ return unless model.base
31
+
32
+ doc.add_child(
33
+ Lutaml::KeyValue::DataModel::Element.new(
34
+ "base", model.base.to_hash
35
+ ),
36
+ )
37
+ end
38
+
39
+ def base_from_kv(model, value)
40
+ return unless value
41
+
42
+ model.base = ::Pubid::Jcgm::Identifier.from_hash(value)
43
+ end
44
+
45
+ # Delegate publisher to base
11
46
  def publisher
12
- base_identifier&.publisher
47
+ base&.publisher
13
48
  end
14
49
  end
15
50
  end