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,15 +13,59 @@ module Pubid
13
13
  return build_annex(data[:annex_to])
14
14
  end
15
15
 
16
+ # Common-text twin ("| ISO/IEC ..." suffix) — extract before building
17
+ # the base ITU identifier, then attach to whichever class the base
18
+ # resolves to.
19
+ twin = parse_common_text_twin(data.delete(:common_text_twin))
20
+
21
+ # Labelled annex of a Recommendation — "ITU-T A.23 Annex A (06/2014)".
22
+ # The annexed document is the :base subtree; :year/:month at this level
23
+ # are the annex's own date, not the base's.
24
+ if data[:annex_number]
25
+ annex = build_annex_of_recommendation(data)
26
+ annex.common_text_twin = twin if twin
27
+ return annex
28
+ end
29
+
30
+ # Labelled appendix of a Recommendation — "ITU-T G.101 App. I
31
+ # (05/2000)". Same shape as the annex above.
32
+ if data[:appendix_number]
33
+ appendix = build_appendix_of_recommendation(data)
34
+ appendix.common_text_twin = twin if twin
35
+ return appendix
36
+ end
37
+
16
38
  # Operational Bulletin (Special Publication) — series == "OB" or
17
39
  # legacy long form ("Operational Bulletin No. ...").
18
- if data[:series].to_s == "OB" || data[:_op_bull]
19
- return build_special_publication(data)
40
+ # The series_dash guard keeps a series-code "ITU-T OB-1" out of this
41
+ # branch, which would drop the dash and render it "ITU OB No. 1".
42
+ # Belt-and-braces: `series_code_body` already refuses "OB" + dash, so
43
+ # nothing reaches here with both set — the guard documents that coupling
44
+ # so removing the parser's `absent?` fails loudly rather than silently
45
+ # rerouting.
46
+ if (data[:series].to_s == "OB" && data[:series_dash].nil?) ||
47
+ data[:_op_bull]
48
+ sp = build_special_publication(data)
49
+ sp.common_text_twin = twin if twin && sp
50
+ return sp
20
51
  end
21
52
 
22
53
  # Check if this is a supplement identifier
23
54
  if data[:supplement_type]
24
- return build_supplement(data)
55
+ supp = build_supplement(data)
56
+ supp.common_text_twin = twin if twin && supp
57
+ return supp
58
+ end
59
+
60
+ # Handbook — "ITU-R 42.HDB"
61
+ if data[:handbook_marker]
62
+ return build_handbook(data)
63
+ end
64
+
65
+ # Question — numeric ("ITU-R 234-1/7:") or letter-series
66
+ # ("ITU-R P.3/BL/7"). Both carry a :study_group marker.
67
+ if data[:study_group]
68
+ return build_question(data)
25
69
  end
26
70
 
27
71
  # Build basic recommendation or combined identifier
@@ -30,44 +74,77 @@ module Pubid
30
74
  code = build_code(data) if data[:number]
31
75
  date = build_date(data) if data[:year]
32
76
 
33
- # Check if this is a combined identifier (has combined_series and combined_number)
34
- if data[:combined_series] || data[:combined_number]
35
- if data[:combined_series]
36
- combined_series = Components::Series.new(
37
- series: data[:combined_series][:series].to_s,
38
- )
39
- end
40
-
41
- if data[:combined_number]
42
- combined_code = Components::Code.new(
43
- number: data[:combined_number].to_s,
44
- subseries: data[:combined_subseries]&.to_s,
45
- parts: extract_parts(data[:combined_parts]),
46
- )
47
- end
48
-
77
+ # Combined (joint) recommendation — one or more additional
78
+ # "/SERIES.CODE" designations after the primary (e.g. "G.780/Y.1351",
79
+ # "G.780/Y.1351/Z.1362"). The primary stays on the base series/code.
80
+ if data[:combined]
49
81
  return Identifiers::CombinedIdentifier.new(
50
82
  sector: sector,
51
83
  series: series,
52
84
  code: code,
53
- combined_series: combined_series,
54
- combined_code: combined_code,
85
+ combined: build_designations(data[:combined]),
55
86
  date: date,
87
+ version: data[:version]&.to_s,
88
+ # with_series offers these slots on either side of
89
+ # combined_suffixes, so a joint id can carry them too; not
90
+ # forwarding them let "ITU-T H.350/X.1 attachment" compare equal to
91
+ # the un-attached document.
92
+ series_word: !data[:series_word].nil?,
93
+ series_dash: !data[:series_dash].nil?,
94
+ attachment: !data[:attachment].nil?,
95
+ range_end: data[:range_end]&.to_s,
56
96
  language: data[:language]&.to_s,
97
+ common_text_twin: twin,
57
98
  )
58
99
  end
59
100
 
60
- Identifiers::Recommendation.new(
101
+ # A Report ("Report ITU-R BT.2020-1") is shaped exactly like a
102
+ # Recommendation — only the leading word, captured as :report_marker,
103
+ # tells the two apart, and it has to, because the two series number
104
+ # independently and the same series/number is two real documents.
105
+ klass = data[:report_marker] ? Identifiers::Report : Identifiers::Recommendation
106
+
107
+ klass.new(
61
108
  sector: sector,
62
109
  series: series,
63
110
  code: code,
64
111
  date: date,
112
+ version: data[:version]&.to_s,
113
+ series_word: !data[:series_word].nil?,
114
+ series_dash: !data[:series_dash].nil?,
115
+ attachment: !data[:attachment].nil?,
116
+ range_end: data[:range_end]&.to_s,
65
117
  language: data[:language]&.to_s,
118
+ common_text_twin: twin,
66
119
  )
67
120
  end
68
121
 
122
+ # Parse the common-text twin string ("| ISO/IEC 13818-1:2022") into
123
+ # the appropriate flavor's identifier object. Returns nil if the twin
124
+ # is empty or unparseable.
125
+ def parse_common_text_twin(twin_raw)
126
+ return nil if twin_raw.nil?
127
+
128
+ twin_str = twin_raw.to_s.strip
129
+ # Strip a leading pipe if the parser captured it
130
+ twin_str = twin_str.sub(/\A\s*\|\s*/, "")
131
+ return nil if twin_str.empty?
132
+
133
+ case twin_str
134
+ when /\AISO\/IEC\b/, /\AISO\b/
135
+ Pubid::Iso.parse(twin_str)
136
+ when /\AIEC\b/
137
+ Pubid::Iec.parse(twin_str)
138
+ end
139
+ rescue StandardError
140
+ # If the twin doesn't parse as a known flavor, leave it as nil
141
+ # rather than blowing up the whole parse — the ITU half is still
142
+ # usable on its own.
143
+ nil
144
+ end
145
+
69
146
  # Build Special Publication (OB). Sector is silently dropped — OB is a
70
- # cross-bureau publication and `Identifiers::Base` rejects sector+OB
147
+ # cross-bureau publication and `Identifier` rejects sector+OB
71
148
  # in its constructor.
72
149
  def build_special_publication(data)
73
150
  Identifiers::SpecialPublication.new(
@@ -88,6 +165,59 @@ module Pubid
88
165
  )
89
166
  end
90
167
 
168
+ # Build a labelled annex of a Recommendation. sector/series/code are
169
+ # deliberately NOT copied from the base: they are not serialized on the
170
+ # wrapper, so copies would make a from_hash-rebuilt annex differ from the
171
+ # parsed one.
172
+ def build_annex_of_recommendation(data)
173
+ Identifiers::AnnexOfRecommendation.new(
174
+ base: build(data[:base]),
175
+ number: data[:annex_number].to_s,
176
+ date: data[:year] ? build_date(data) : nil,
177
+ language: data[:language]&.to_s,
178
+ )
179
+ end
180
+
181
+ # Build a labelled appendix of a Recommendation. Like the annex above,
182
+ # sector/series/code are deliberately NOT copied from the base — they are
183
+ # not serialized on the wrapper, so copies would make a from_hash-rebuilt
184
+ # appendix differ from the parsed one.
185
+ def build_appendix_of_recommendation(data)
186
+ Identifiers::AppendixOfRecommendation.new(
187
+ base: build(data[:base]),
188
+ number: data[:appendix_number].to_s,
189
+ material: data[:appendix_material]&.to_s,
190
+ date: data[:year] ? build_date(data) : nil,
191
+ language: data[:language]&.to_s,
192
+ )
193
+ end
194
+
195
+ # Build Handbook ("ITU-R 42.HDB").
196
+ def build_handbook(data)
197
+ Identifiers::Handbook.new(
198
+ sector: Components::Sector.new(sector: data[:sector].to_s),
199
+ code: build_code(data),
200
+ date: data[:year] ? build_date(data) : nil,
201
+ )
202
+ end
203
+
204
+ # Build Question (numeric or letter-series).
205
+ def build_question(data)
206
+ series = if data[:series]
207
+ Components::Series.new(series: data[:series].to_s)
208
+ end
209
+
210
+ Identifiers::Question.new(
211
+ sector: Components::Sector.new(sector: data[:sector].to_s),
212
+ series: series,
213
+ code: build_code(data),
214
+ study_group: data[:study_group].to_s,
215
+ has_bl: !data[:has_bl].nil?,
216
+ bracketed: !data[:bracketed].nil?,
217
+ has_colon: !data[:question_colon].nil?,
218
+ )
219
+ end
220
+
91
221
  def build_supplement(data)
92
222
  # Build the base identifier first
93
223
  base = build(data[:base]) if data[:base]
@@ -97,10 +227,22 @@ module Pubid
97
227
  klass = case supplement_type
98
228
  when "Amd"
99
229
  Identifiers::Amendment
230
+ when "Add"
231
+ Identifiers::Addendum
100
232
  when "Cor"
101
233
  Identifiers::Corrigendum
234
+ when "Err"
235
+ Identifiers::Errata
102
236
  when "Suppl"
103
237
  Identifiers::Supplement
238
+ else
239
+ # Previously fell through to a nil class and died with
240
+ # "undefined method 'new' for nil" one frame later. Any token
241
+ # added to Parser#supplement_type without a class here should
242
+ # say so.
243
+ raise ArgumentError,
244
+ "Unknown ITU supplement type: " \
245
+ "#{data[:supplement_type].inspect}"
104
246
  end
105
247
 
106
248
  # Build supplement date (separate from base date)
@@ -111,25 +253,84 @@ module Pubid
111
253
  )
112
254
  end
113
255
 
114
- # Build supplement with extracted components
115
- klass.new(
116
- sector: base&.sector || Components::Sector.new(sector: data[:sector].to_s),
117
- series: base&.series || (data[:series] ? Components::Series.new(series: data[:series].to_s) : nil),
118
- code: base&.code,
256
+ # Sector/series are copied from the base when it has them; the fallback
257
+ # to this level's own tokens is guarded because an annex base keeps
258
+ # sector/series/code on *its* base, leaving all three nil here while the
259
+ # supplement level carries no sector token of its own.
260
+ # An annex base keeps sector/series/code on *its* base, so reach through
261
+ # it via #root; otherwise a supplement of an annex would carry none of
262
+ # them and its MR string would collapse to a bare "itu.<date>".
263
+ base_identity = base&.sector ? base : base&.root
264
+ sector = base_identity&.sector ||
265
+ (Components::Sector.new(sector: data[:sector].to_s) if data[:sector])
266
+ series = base_identity&.series ||
267
+ (Components::Series.new(series: data[:series].to_s) if data[:series])
268
+
269
+ attrs = {
270
+ sector: sector,
271
+ series: series,
272
+ code: base_identity&.code,
119
273
  base: base,
120
274
  number: data[:supplement_number].to_s,
275
+ # The marker is the captured space, so its ABSENCE is the flag.
276
+ number_glued: data[:supplement_space].nil?,
277
+ slash_joined: !data[:supplement_slash].nil?,
121
278
  date: supplement_date,
122
279
  language: data[:language]&.to_s,
123
- )
280
+ }
281
+ # The "series" word rides on the supplement for the base-less,
282
+ # series-only form; with a base it is the base's, and renders from
283
+ # there. It is copied up anyway (like sector/series/code above) so the
284
+ # supplement's own MR slug stays distinct — `render_supplement` and the
285
+ # base-nil-guarded key_value/== only consult it when base is nil, so
286
+ # the copy is render- and serialization-neutral.
287
+ attrs[:series_word] = if base
288
+ !!base_identity&.series_word
289
+ else
290
+ !data[:series_word].nil?
291
+ end
292
+ attrs[:technical] = true if data[:technical] &&
293
+ klass == Identifiers::Corrigendum
294
+
295
+ klass.new(**attrs)
124
296
  end
125
297
 
126
298
  private
127
299
 
300
+ # Build the additional designations of a combined recommendation from the
301
+ # repeated parse subtrees (each `{ designation: { series:, number:, … } }`).
302
+ def build_designations(combined_data)
303
+ Array(combined_data).map do |element|
304
+ d = element[:designation] || element
305
+ Components::Designation.new(
306
+ series: Components::Series.new(series: d[:series].to_s),
307
+ code: Components::Code.new(
308
+ number: d[:number].to_s,
309
+ series_suffix: d[:series_suffix]&.to_s,
310
+ series_suffix_spaced: !d[:series_suffix_spaced].nil?,
311
+ subseries: d[:subseries]&.to_s,
312
+ parts: extract_parts(d[:parts]),
313
+ qualifier: d[:qualifier]&.to_s,
314
+ qualifier_glued: !d[:qualifier].nil? && d[:qualifier_spaced].nil?,
315
+ ),
316
+ )
317
+ end
318
+ end
319
+
128
320
  def build_code(data)
129
321
  Components::Code.new(
322
+ imp_marker: data[:imp_marker]&.to_s,
130
323
  number: data[:number].to_s,
324
+ series_suffix: data[:series_suffix]&.to_s,
325
+ # The marker is the captured separating space, so its presence is
326
+ # the flag for the edition word and its ABSENCE is the flag for the
327
+ # qualifier letter (whose majority spelling is spaced).
328
+ series_suffix_spaced: !data[:series_suffix_spaced].nil?,
131
329
  subseries: data[:subseries]&.to_s,
132
330
  parts: extract_parts(data[:parts]),
331
+ qualifier: data[:qualifier]&.to_s,
332
+ qualifier_glued: !data[:qualifier].nil? &&
333
+ data[:qualifier_spaced].nil?,
133
334
  )
134
335
  end
135
336
 
@@ -6,24 +6,64 @@ module Pubid
6
6
  module Itu
7
7
  module Components
8
8
  # ITU Code component
9
- # Format: NUMBER[.SUBSERIES][-PART]
10
- # Examples: 1234, 1234.5, 1234-1, 1234.5-2
9
+ # Format: [Imp]NUMBER[SUFFIX][.SUBSERIES][-PART]
10
+ # Examples: 1234, 1234.5, 1234-1, 1234.5-2, 50bis, 8bis, Imp712, ImpOSI
11
+ #
12
+ # The optional "Imp" marker identifies an Implementers' Guide for the
13
+ # series (e.g. G.Imp712, X.ImpOSI); the NUMBER that follows may be
14
+ # digits or a short letter string.
15
+ #
16
+ # SUFFIX is the edition marker "bis" / "ter" / "quater" attached
17
+ # directly to the number (e.g. X.50bis, V.8bis).
11
18
  #
12
19
  # Stays independent of Pubid::Components::Code because ITU uses
13
20
  # +subseries+ (dot-separated, flavor-specific) and +parts+
14
21
  # (dash-separated).
15
22
  class Code < Lutaml::Model::Serializable
23
+ attribute :imp_marker, :string
16
24
  attribute :number, :string
25
+ attribute :series_suffix, :string
26
+ # ITU prints the edition word both glued ("X.50bis") and space-
27
+ # separated ("E.250 bis"). The word itself is stored without the space,
28
+ # so `series_suffix` stays a clean, whitespace-free value to compare and
29
+ # index on; the spacing is this rendering-only flag. Named for the
30
+ # rarer-in-code form so the `false` default stays out of `to_hash`.
31
+ attribute :series_suffix_spaced, :boolean, default: -> { false }
17
32
  attribute :subseries, :string
18
33
  attribute :parts, :string, collection: true, default: []
34
+ # A single trailing letter distinguishing variants of one
35
+ # Recommendation: "D.200 R" (old D-series tariff recommendations),
36
+ # "Q.2931 B", "R.38 A", the glued "D.502R" and the lowercase
37
+ # "I.256.2a". Spaced is the majority spelling, so the glued one is the
38
+ # flag.
39
+ attribute :qualifier, :string
40
+ attribute :qualifier_glued, :boolean, default: -> { false }
19
41
 
42
+ # Segment order mirrors the grammar exactly — a GLUED suffix is
43
+ # captured inside `standard_code` (the edition word before the
44
+ # subseries, the qualifier after the parts), while a SPACED one is
45
+ # captured afterwards by `code_suffixes`. Rendering the edition word
46
+ # unconditionally first would print "Q.11a bis" back as "Q.11 bisa".
20
47
  def to_s
21
- result = number.to_s
48
+ result = "#{imp_marker}#{number}"
49
+ result += series_suffix.to_s if series_suffix && !series_suffix_spaced
22
50
  result += ".#{subseries}" if subseries
23
51
  result += parts.map { |p| "-#{p}" }.join if parts&.any?
52
+ result += qualifier.to_s if qualifier && qualifier_glued
53
+ result += " #{series_suffix}" if series_suffix && series_suffix_spaced
54
+ result += " #{qualifier}" if qualifier && !qualifier_glued
24
55
  result
25
56
  end
26
57
 
58
+ # Space-free rendering for URN and MR use: the print form may separate
59
+ # the edition word or the qualifier letter with a space ("E.250 bis",
60
+ # "D.200 R"), which is not admissible inside a URN segment. Removing
61
+ # the space keeps "D.200" and "D.200 R" on distinct URNs, which
62
+ # dropping the suffix would not.
63
+ def compact_s
64
+ to_s.delete(" ")
65
+ end
66
+
27
67
  def render(context: nil)
28
68
  to_s
29
69
  end
@@ -31,9 +71,12 @@ module Pubid
31
71
  def ==(other)
32
72
  return false unless other.is_a?(Code)
33
73
 
34
- number == other.number &&
74
+ imp_marker == other.imp_marker &&
75
+ number == other.number &&
76
+ series_suffix == other.series_suffix &&
35
77
  subseries == other.subseries &&
36
- parts == other.parts
78
+ parts == other.parts &&
79
+ qualifier == other.qualifier
37
80
  end
38
81
  end
39
82
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Pubid
6
+ module Itu
7
+ module Components
8
+ # One series+number designation of a combined (joint) recommendation.
9
+ # A combined recommendation such as "ITU-T G.780/Y.1351" keeps its primary
10
+ # designation on the base identifier (series "G", code "780") and carries
11
+ # each *additional* designation ("Y.1351", and any further "/Z.1362" …) as
12
+ # a Designation in Identifiers::CombinedIdentifier#combined.
13
+ #
14
+ # Format: SERIES.CODE (e.g. "Y.1351", "Y.1362-2")
15
+ class Designation < Lutaml::Model::Serializable
16
+ attribute :series, Pubid::Itu::Components::Series
17
+ attribute :code, Pubid::Itu::Components::Code
18
+
19
+ def to_s
20
+ "#{series}.#{code}"
21
+ end
22
+
23
+ def render(context: nil)
24
+ to_s
25
+ end
26
+
27
+ def ==(other)
28
+ return false unless other.is_a?(Designation)
29
+
30
+ series == other.series && code == other.code
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -6,6 +6,7 @@ module Pubid
6
6
  autoload :Sector, "#{__dir__}/components/sector"
7
7
  autoload :Series, "#{__dir__}/components/series"
8
8
  autoload :Code, "#{__dir__}/components/code"
9
+ autoload :Designation, "#{__dir__}/components/designation"
9
10
  end
10
11
  end
11
12
  end
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Pubid::Itu::Identifier is the ITU base class (a real Pubid::Identifier
4
- # subclass); its body, `.parse`, and the Identifiers::Base back-compat alias
5
- # live in identifiers/base.rb. This file just ensures it is loaded.
6
- require_relative "identifiers/base"
4
+ # subclass); its body and `.parse` live in identifiers/base.rb. This file just ensures it is loaded.
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Itu
5
+ module Identifiers
6
+ # Addendum identifier (Add.)
7
+ # Pattern: "ITU-T I.363 (1993) Add. 1 (11/1993)"
8
+ class Addendum < Supplement
9
+ def to_s
10
+ render_supplement("Add.")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,36 +4,14 @@ module Pubid
4
4
  module Itu
5
5
  module Identifiers
6
6
  # Amendment identifier (Amd)
7
- # Pattern: "ITU-T G.989 Amd 1", "ITU-T G.780/Y.1351 Amd 1 (2004)"
7
+ # Pattern: "ITU-T G.989 Amd. 1", "ITU-T G.780/Y.1351 Amd. 1 (2004)"
8
8
  class Amendment < Supplement
9
+ # "Amd." with the period, matching ITU's own rendering and the sibling
10
+ # supplement types (Cor./Err./Suppl./Add.). The parser accepts both
11
+ # spellings (see Parser#supplement_type), so the period-less input form
12
+ # still round-trips through parse — it just normalizes here.
9
13
  def to_s
10
- result = base ? base.to_s : "#{publisher}-#{sector}"
11
-
12
- # Add series if no base
13
- if !base && series
14
- result += " #{series}"
15
- end
16
-
17
- result += " Amd #{number}"
18
-
19
- # Add date if present
20
- if date
21
- result += if date.month
22
- " (#{date.month}/#{date.year})"
23
- else
24
- " (#{date.year})"
25
- end
26
- end
27
-
28
- result
29
- end
30
-
31
- def ==(other)
32
- return false unless other.is_a?(Amendment)
33
-
34
- base == other.base &&
35
- number == other.number &&
36
- date == other.date
14
+ render_supplement("Amd.")
37
15
  end
38
16
  end
39
17
  end
@@ -12,8 +12,19 @@ module Pubid
12
12
  # * long with i18n_lang + format: :long: per-language `annex_long` template
13
13
  # Languages without an `annex_to` entry (fr/es/ru/zh) use the long
14
14
  # template for the short form too.
15
- class Annex < Base
16
- attribute :base, Base, polymorphic: true
15
+ class Annex < Identifier
16
+ attribute :base, Identifier, polymorphic: true
17
+
18
+ # Compact serialization: an Annex is just the nested (itself-flat) base
19
+ # plus its own language; everything else is delegated to `base`.
20
+ key_value do
21
+ map "_type", to: :_type
22
+ map "base", with: { to: :base_to_kv, from: :base_from_kv }
23
+ map "language", to: :language
24
+ map "common_text_twin",
25
+ with: { to: :common_text_twin_to_kv,
26
+ from: :common_text_twin_from_kv }
27
+ end
17
28
 
18
29
  def to_urn
19
30
  # Annex URN: append :annex to the inner identifier's URN.
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Itu
5
+ module Identifiers
6
+ # A labelled annex of a Recommendation — "ITU-T A.23 Annex A (06/2014)",
7
+ # "ITU-T Z.100 Annex F3 (10/2019)", "ITU-T G.729 Annex C+ (02/2000)".
8
+ #
9
+ # The annex is a document in its own right: it is published (and dated)
10
+ # separately from the Recommendation it annexes, and may itself carry a
11
+ # corrigendum/errata/amendment ("ITU-T G.729 Annex B (1996) Cor. 3
12
+ # (03/2001)").
13
+ #
14
+ # Distinct from Identifiers::Annex, which models the label-less
15
+ # "Annex to ITU OB No. 1000" form (a prefix rendering with its own i18n
16
+ # templates). Keeping them apart keeps each `_type` — already persisted in
17
+ # relaton index rows — unambiguous.
18
+ class AnnexOfRecommendation < Identifier
19
+ attribute :base, Identifier, polymorphic: true
20
+ # The annex label ("A", "F3", "C+"). Named `number` for symmetry with
21
+ # Supplement's ordinal; it shadows Identifier#number (code&.number),
22
+ # which is nil here anyway — the document number is reached via #root.
23
+ attribute :number, :string
24
+
25
+ # Compact serialization: the annex is the nested (itself-flat) base plus
26
+ # its own label, date and language. sector/series/code are the base's
27
+ # and are deliberately not re-emitted (the wrapper lesson).
28
+ key_value do
29
+ map "_type", to: :_type
30
+ map "number", to: :number
31
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
32
+ map "month", with: { to: :month_to_kv, from: :month_from_kv }
33
+ map "base", with: { to: :base_to_kv, from: :base_from_kv }
34
+ map "language", to: :language
35
+ map "common_text_twin",
36
+ with: { to: :common_text_twin_to_kv,
37
+ from: :common_text_twin_from_kv }
38
+ end
39
+
40
+ # "<base urn>:annex:<label>[:<date>]" — the annex's own date must be
41
+ # there, or two editions of one annex share a URN (the base's date
42
+ # rides inside base_urn, so omitting the annex's would be asymmetric).
43
+ def to_urn
44
+ segments = [base&.to_urn || "urn:itu", "annex", number&.downcase]
45
+ segments << urn_date_segment
46
+ segments.compact.join(":")
47
+ end
48
+
49
+ def render_base(**opts)
50
+ result = base ? base.render_base(**opts) : "#{publisher}-#{sector}"
51
+
52
+ "#{result} Annex #{number}#{render_date_suffix}"
53
+ end
54
+
55
+ # MR: recurse into the annexed document and append "annex.<label>[.year]"
56
+ # (the documented supplement-suffix hook), so the slug stays distinct
57
+ # per annex. Without it the wrapper's own nil sector/series/code would
58
+ # collapse every annex onto a bare "itu.<year>".
59
+ def mr_supplement_suffix
60
+ # "C+" -> "cplus", not "c" — the MR charset excludes "+", and
61
+ # dropping it would collide with the sibling "Annex C".
62
+ label = number.to_s.downcase.gsub("+", "plus").gsub(/[^a-z0-9]/, "")
63
+
64
+ ["annex", label.empty? ? nil : label, date&.year].compact.join(".")
65
+ end
66
+
67
+ def ==(other)
68
+ return false unless other.instance_of?(self.class)
69
+
70
+ base == other.base &&
71
+ number == other.number &&
72
+ date == other.date &&
73
+ language == other.language &&
74
+ common_text_twin == other.common_text_twin
75
+ end
76
+
77
+ private
78
+
79
+ def urn_date_segment
80
+ return nil unless date
81
+
82
+ date.month ? "#{date.month}/#{date.year}" : date.year.to_s
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end