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
@@ -355,12 +355,12 @@ module Pubid
355
355
  end
356
356
 
357
357
  # Parse base identifier recursively
358
- base_identifier = base_input ? parse(base_input) : nil
359
- return nil unless base_identifier
358
+ base = base_input ? parse(base_input) : nil
359
+ return nil unless base
360
360
 
361
361
  # Create PackageIdentifier
362
362
  result = Identifiers::Package.new
363
- result.base_identifier = base_identifier
363
+ result.base = base
364
364
  # Set materials if present
365
365
  if package_materials && !package_materials.empty?
366
366
  result.package_materials = package_materials
@@ -458,6 +458,51 @@ module Pubid
458
458
 
459
459
  nil
460
460
  end
461
+
462
+ # CSA stores the publication year in its own plain `year` string
463
+ # attribute (not a `Components::Date`), so the base `#exclude`'s
464
+ # `:year`->`:date` remap nils the unused inherited `date` and leaves
465
+ # `year` intact. Override to nil `year` (and its formatting metadata)
466
+ # when `:year`/`:date` is excluded, so a partial (year-less) CSA
467
+ # reference is a year wildcard under `matches?(row, ignore: [:year])`.
468
+ # The metadata attrs (`year_format`, `year_prefix`,
469
+ # `original_year_4digit`, `french`) are year-derived — a year-less
470
+ # parse leaves them nil/false, so they must be reset here too or `==`
471
+ # would still differ. `french` in particular is only ever set from a
472
+ # `:F` year prefix (the French-edition form `CSA B149.1:F20`), so a
473
+ # bare `CSA B149.1` reference must wildcard it to match both the
474
+ # English and French editions of a document number. `super` preserves
475
+ # the base recursion into nested identifiers (adoption wrappers
476
+ # delegate their year to an inner id and lack a `year` accessor, hence
477
+ # the `respond_to?` guard). Mirrors BIPM.
478
+ def exclude(*args)
479
+ result = super
480
+ year_keys = args & %i[year date]
481
+ if !year_keys.empty? && result.respond_to?(:year=)
482
+ result.year = nil
483
+ result.year_format = nil
484
+ result.year_prefix = nil
485
+ result.original_year_4digit = false
486
+ result.french = nil
487
+ end
488
+ result
489
+ end
490
+
491
+ # CSA encodes its identity across many shape-specific attributes
492
+ # (`publisher_prefix`, `code`, `no_number`, `series`, `series_prefix`,
493
+ # `package`, `reaffirmation`, `year` with prefix/format/French markers,
494
+ # etc.) that the generic MrString renderer doesn't know about. The
495
+ # CSA `to_s` already round-trips losslessly through the CSA parser, so
496
+ # MR mirrors it: ` ` → `.`, `:` → `.` (so the year never looks like
497
+ # another code segment), `/` → `-` (CAN/CSA- prefix), then lowercased
498
+ # to match the all-lowercase MR convention (issue #142).
499
+ def to_mr_string
500
+ to_s.tr(" ", ".").tr(":", ".").tr("/", "-").downcase
501
+ end
502
+
503
+ def to_slug
504
+ to_mr_string
505
+ end
461
506
  end
462
507
  end
463
508
  end
@@ -14,6 +14,12 @@ module Pubid
14
14
  }
15
15
  attribute :year_format, :string # Add for compatibility with identifier.rb
16
16
 
17
+ # CSA bundles are not Pubid::Identifier objects, so they do not inherit
18
+ # #root. They are their own origin for matching purposes.
19
+ def root
20
+ self
21
+ end
22
+
17
23
  def to_s
18
24
  # For Cec identifiers, use normalized form (code instead of cec_part + NO.)
19
25
  # This is used for "normalized form" rendering in bundled identifiers
@@ -23,6 +23,12 @@ module Pubid
23
23
  attribute :year_format, :string # Dummy for compatibility
24
24
  attribute :separator, :string, default: -> { "/" } # "/" or ", "
25
25
 
26
+ # CSA combined ids are not Pubid::Identifier objects, so they do not
27
+ # inherit #root. They are their own origin for matching purposes.
28
+ def root
29
+ self
30
+ end
31
+
26
32
  def to_s
27
33
  # For comma separator, render both parts with full prefix
28
34
  # For slash separator, second/third parts without prefix
@@ -12,7 +12,7 @@ module Pubid
12
12
  # CSA C22.2 NO. 60601-1:15 PACKAGE WITH ADDENDUM
13
13
  #
14
14
  # This is a composite pattern where:
15
- # - base_identifier is the core CSA standard (recursively parsed)
15
+ # - base is the core CSA standard (recursively parsed)
16
16
  # - package_materials describes what's included in the package
17
17
  # - Package portion is metadata, not a parseable identifier
18
18
  #
@@ -34,7 +34,7 @@ module Pubid
34
34
  attribute :materials_after_keyword, :boolean, default: -> { true }
35
35
 
36
36
  def to_s
37
- result = base_identifier.to_s
37
+ result = base.to_s
38
38
 
39
39
  # Add package materials if present
40
40
  if package_materials && !package_materials.empty?
@@ -179,7 +179,7 @@ module Pubid
179
179
  # Optional series prefix (MH, RV, etc.) before SERIES keyword
180
180
  (series_prefix >> space).maybe >>
181
181
  series_keyword.as(:series_type) >>
182
- (colon_year | dash_year) >>
182
+ (colon_year | dash_year).maybe >>
183
183
  reaffirmation.maybe
184
184
  end
185
185
 
@@ -194,7 +194,7 @@ module Pubid
194
194
  ).as(:cec_part) >>
195
195
  no_notation >>
196
196
  no_number >>
197
- (colon_year | dash_year) >>
197
+ (colon_year | dash_year).maybe >>
198
198
  reaffirmation.maybe
199
199
  end
200
200
 
@@ -257,7 +257,7 @@ module Pubid
257
257
  (space >> series_keyword.as(:series) >> (colon_year | dash_year)) |
258
258
  # Option 4: just year (no series, no NO.)
259
259
  (colon_year | dash_year)
260
- ) >>
260
+ ).maybe >> # trailing year optional (partial reference)
261
261
  amendment_slash.maybe # Add amendment support here
262
262
  end
263
263
 
@@ -274,7 +274,7 @@ module Pubid
274
274
  (space >> series_keyword.as(:series) >> (colon_year | dash_year)) |
275
275
  # Option 4: just year
276
276
  (colon_year | dash_year)
277
- )
277
+ ).maybe # trailing year optional (partial reference)
278
278
  end
279
279
 
280
280
  # Continuation code (optional CSA publisher prefix, for combined identifiers)
@@ -290,7 +290,7 @@ module Pubid
290
290
  (space >> series_keyword.as(:series) >> (colon_year | dash_year)) |
291
291
  # Option 4: just year
292
292
  (colon_year | dash_year)
293
- ) >>
293
+ ).maybe >> # trailing year optional (partial reference)
294
294
  amendment_slash.maybe
295
295
  end
296
296
 
@@ -353,7 +353,7 @@ module Pubid
353
353
  (space >> series_keyword.as(:series) >> (colon_year | dash_year)) |
354
354
  # Option 3: just year
355
355
  (colon_year | dash_year)
356
- ) >>
356
+ ).maybe >> # trailing year optional (partial reference)
357
357
  (space >> str("PACKAGE")).as(:package_portion).maybe
358
358
  end
359
359
 
@@ -26,6 +26,23 @@ module Pubid
26
26
  def to_s
27
27
  raise NotImplementedError, "Subclasses must implement to_s method"
28
28
  end
29
+
30
+ # CSA wrappers serialise through `to_s` (their distinct shape is what
31
+ # makes them wrappers), so MR mirrors that with ` ` → `.`, `:` → `.`,
32
+ # `/` → `-`, then lowercased (issue #142).
33
+ def to_mr_string
34
+ to_s.tr(" ", ".").tr(":", ".").tr("/", "-").downcase
35
+ end
36
+
37
+ def to_slug
38
+ to_mr_string
39
+ end
40
+
41
+ # CSA wrappers are not Pubid::Identifier objects, so they do not inherit
42
+ # #root. They are their own origin for matching purposes.
43
+ def root
44
+ self
45
+ end
29
46
  end
30
47
  end
31
48
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ class Builder
6
+ def self.build(parsed_data)
7
+ new.build(parsed_data)
8
+ end
9
+
10
+ def build(data)
11
+ Identifiers::Resource.new(
12
+ prefix: "10.#{data[:prefix]}",
13
+ suffix: data[:suffix].to_s,
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ class Identifier < ::Pubid::Identifier
6
+ # The DOI prefix: "10." + registrar code, e.g. "10.1000", "10.6028".
7
+ attribute :prefix, :string
8
+
9
+ # The DOI suffix: arbitrary printable string with no whitespace. May
10
+ # contain slashes (e.g. "NIST.2022-04-15.001").
11
+ attribute :suffix, :string
12
+
13
+ DOI_TYPE_MAP = {
14
+ "pubid:doi:resource" => "Pubid::Doi::Identifiers::Resource",
15
+ }.freeze
16
+
17
+ key_value do
18
+ map "_type", to: :_type, polymorphic_map: DOI_TYPE_MAP
19
+ map "prefix", to: :prefix
20
+ map "suffix", to: :suffix
21
+ end
22
+
23
+ PUBLISHER = "DOI"
24
+
25
+ # The numeric registrar subcode (e.g. "1000" for prefix "10.1000").
26
+ def registrar
27
+ prefix.to_s.sub(/\A10\./, "") unless prefix.to_s.empty?
28
+ end
29
+
30
+ def to_s(**opts)
31
+ render(format: :human, **opts)
32
+ end
33
+
34
+ def self.parse(identifier)
35
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
36
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
37
+ end
38
+
39
+ parsed = Parser.parse(identifier)
40
+ Builder.build(parsed)
41
+ rescue Parslet::ParseFailed => e
42
+ raise "Failed to parse DOI '#{identifier}': #{e.message}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ module Identifiers
6
+ # Concrete DOI identifier type.
7
+ #
8
+ # Examples:
9
+ # doi:10.1000/182
10
+ # 10.6028/NIST.2022-04-15.001
11
+ # https://doi.org/10.1006/jmbi.1998.2354
12
+ class Resource < Identifier
13
+ TYPED_STAGES = [
14
+ Pubid::Components::TypedStage.new(
15
+ code: :pubdoi,
16
+ stage_code: :published,
17
+ type_code: :doi,
18
+ abbr: ["DOI"],
19
+ name: "DOI",
20
+ harmonized_stages: [],
21
+ ),
22
+ ].freeze
23
+
24
+ def self.type
25
+ { key: :doi, web: :doi, title: "DOI", short: "DOI" }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ module Identifiers
6
+ autoload :Resource, "#{__dir__}/identifiers/resource"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Doi
7
+ # Parslet grammar for Digital Object Identifiers per ISO 26324.
8
+ #
9
+ # Accepts:
10
+ # [doi:|DOI:]10.{REGISTRAR}/{SUFFIX}
11
+ # https://doi.org/10.{REGISTRAR}/{SUFFIX}
12
+ #
13
+ # SUFFIX is one-or-more chars from [A-Za-z0-9._\-/()] (printable minus
14
+ # whitespace). The grammar is intentionally permissive on suffix chars
15
+ # because real DOIs cover the full printable range.
16
+ class Parser < Parslet::Parser
17
+ rule(:dot) { str(".") }
18
+ rule(:slash) { str("/") }
19
+
20
+ # Optional URL resolver prefix.
21
+ rule(:url_prefix) { (str("https://") | str("http://")).maybe >> str("doi.org").maybe }
22
+
23
+ # Optional DOI scheme prefix.
24
+ rule(:scheme_prefix) do
25
+ (str("doi:") | str("DOI:") | str("Doi:")).maybe
26
+ end
27
+
28
+ # Prefix: "10." then 2+ registrar digits.
29
+ rule(:prefix) { str("10") >> dot >> match("[0-9]").repeat(2).as(:prefix) }
30
+
31
+ # Suffix: at least one printable non-whitespace char (DOI Handbook §2.2).
32
+ rule(:suffix) { match("[A-Za-z0-9._\\-/()]").repeat(1).as(:suffix) }
33
+
34
+ rule(:identifier) do
35
+ url_prefix.maybe >>
36
+ scheme_prefix.maybe >>
37
+ slash.maybe >>
38
+ prefix >> slash >> suffix
39
+ end
40
+
41
+ rule(:root) { identifier }
42
+
43
+ def self.parse(input)
44
+ # Normalize a URL resolver form to bare form before parsing. The
45
+ # parser's `url_prefix.maybe >> scheme_prefix.maybe >> slash.maybe`
46
+ # chain also handles this in-grammar, but pre-stripping yields a
47
+ # cleaner error message for malformed URLs.
48
+ new.parse(input)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ # Human-readable renderer for DOIs. Produces the canonical "doi:PREFIX/SUFFIX"
6
+ # form (RFC 5650 §2).
7
+ class Renderer < ::Pubid::Renderers::Base
8
+ def render(**_opts)
9
+ "doi:#{@id.prefix}/#{@id.suffix}"
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/pubid/doi.rb ADDED
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ # DOI (Digital Object Identifier) flavor.
5
+ #
6
+ # Parses the canonical DOI per ISO 26324:
7
+ # doi:10.{REGISTRAR}/{SUFFIX}
8
+ #
9
+ # The optional URL form `https://doi.org/10.X/Y` is accepted; the resolver
10
+ # host is stripped before parsing.
11
+ module Doi
12
+ extend Pubid::PrefixesSupport
13
+
14
+ # Leading tokens a DOI string can start with. The bare "10." form is the
15
+ # canonical prefix per ISO 26324 §4.1.
16
+ PREFIXES = %w[doi: DOI: 10.].freeze
17
+
18
+ autoload :Builder, "#{__dir__}/doi/builder"
19
+ autoload :Identifier, "#{__dir__}/doi/identifier"
20
+ autoload :Identifiers, "#{__dir__}/doi/identifiers"
21
+ autoload :Parser, "#{__dir__}/doi/parser"
22
+ autoload :Renderer, "#{__dir__}/doi/renderer"
23
+
24
+ def self.parse(identifier)
25
+ Identifier.parse(identifier)
26
+ end
27
+
28
+ Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
29
+ Identifier.format_registry.register(:human, renderer: Doi::Renderer)
30
+
31
+ def self.identifier_types
32
+ @identifier_types ||= Identifiers.constants
33
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
34
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
35
+ .select { |c| c.type.is_a?(Hash) }
36
+ end
37
+
38
+ def self.all_typed_stages
39
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
40
+ klass.const_defined?(:TYPED_STAGES) ? klass.const_get(:TYPED_STAGES) : []
41
+ end
42
+ end
43
+
44
+ def self.locate_type(code)
45
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
46
+ end
47
+
48
+ def self.locate_stage(abbr)
49
+ abbr_str = abbr.to_s.upcase
50
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
51
+ end
52
+ end
53
+ end
54
+
55
+ Pubid::Registry.register(:doi, Pubid::Doi)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ # Builds an EASC identifier object from the Parslet parse tree.
6
+ class Builder
7
+ def build(parsed)
8
+ series_cyr = stringify(parsed[:series])&.upcase
9
+ canonical_series = series_to_canonical(series_cyr)
10
+ klass = Easc.identifier_klass_for_series(canonical_series) ||
11
+ Identifier
12
+ attrs = {
13
+ series: canonical_series,
14
+ variant: variant_to_canonical(stringify(parsed[:variant])),
15
+ number: stringify(parsed[:number]),
16
+ year: stringify(parsed[:year]),
17
+ }.compact
18
+
19
+ klass.new(**attrs)
20
+ end
21
+
22
+ def self.build(parsed)
23
+ new.build(parsed)
24
+ end
25
+
26
+ private
27
+
28
+ # Map Cyrillic series to Latin canonical form (PMG/RMG). Latin
29
+ # input is preserved as-is (uppercased).
30
+ def series_to_canonical(series)
31
+ return nil unless series
32
+
33
+ case series
34
+ when "ПМГ", "PMG" then "PMG"
35
+ when "РМГ", "RMG" then "RMG"
36
+ else series
37
+ end
38
+ end
39
+
40
+ # Normalize variant marker to Latin "V" (regardless of script).
41
+ def variant_to_canonical(variant)
42
+ return nil unless variant
43
+
44
+ %w[В V].include?(variant.upcase) ? "V" : variant
45
+ end
46
+
47
+ def stringify(value)
48
+ return nil if value.nil?
49
+
50
+ str = value.to_s
51
+ str.empty? ? nil : str
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ # Base class for all EASC identifiers. Canonical name
6
+ # Pubid::Easc::Identifier; every concrete EASC identifier
7
+ # (Identifiers::*) descends from it.
8
+ #
9
+ # EASC identifiers have the form:
10
+ # <series> [В ]<number>[-<year>]
11
+ #
12
+ # Where:
13
+ # * <series> identifies the document class — ПМГ (Правила
14
+ # межгосударственной стандартизации) or РМГ (Рекомендации по
15
+ # межгосударственной стандартизации). Latin forms PMG/RMG are
16
+ # also parsed; canonical render is Cyrillic per mgscatalog.by.
17
+ # * the optional "В" (Cyrillic capital V) marks a defense-related
18
+ # variant (e.g. "ПМГ В 31-2001"). Stored as `variant: "V"`
19
+ # (Latin) for cross-script consistency.
20
+ # * <number> is a digit run.
21
+ # * <year> is 2 or 4 digits, separated by ASCII hyphen OR Unicode
22
+ # em-dash / en-dash (Russian typographic convention).
23
+ #
24
+ # Examples:
25
+ # ПМГ 03-2025
26
+ # ПМГ В 31-2001
27
+ # РМГ 151-2025
28
+ # РМГ 29-2013
29
+ class Identifier < ::Pubid::Identifier
30
+ def self.parse(identifier)
31
+ parsed = Parser.parse(identifier)
32
+ Builder.build(parsed)
33
+ rescue Parslet::ParseFailed => e
34
+ raise "Failed to parse EASC identifier '#{identifier}': #{e.message}"
35
+ end
36
+
37
+ attribute :publisher, :string, default: "EASC"
38
+ attribute :series, :string # "PMG" | "RMG" — Latin canonical
39
+ attribute :variant, :string # "V" | nil
40
+ attribute :number, :string # "151", "03", "31"
41
+ attribute :year, :string # "2025", "13", nil
42
+
43
+ EASC_TYPE_MAP = {
44
+ "pubid:easc:pmg" => "Pubid::Easc::Identifiers::Pmg",
45
+ "pubid:easc:rmg" => "Pubid::Easc::Identifiers::Rmg",
46
+ }.freeze
47
+
48
+ key_value do
49
+ map "_type", to: :_type, polymorphic_map: EASC_TYPE_MAP
50
+ map "series", to: :series
51
+ map "variant", to: :variant
52
+ map "number", to: :number
53
+ map "year", to: :year
54
+ end
55
+
56
+ def to_urn
57
+ UrnGenerator.new(self).generate
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ module Identifiers
6
+ # ПМГ — Правила по межгосударственной стандартизации
7
+ # (Rules on interstate standardization). Issued by EASC.
8
+ #
9
+ # Examples:
10
+ # ПМГ 03-2025
11
+ # ПМГ 126-2013
12
+ # ПМГ В 31-2001 (defense variant)
13
+ class Pmg < Identifier
14
+ def self.type
15
+ { key: :pmg, title: "Interstate Rules", series: "PMG" }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ module Identifiers
6
+ # РМГ — Рекомендации по межгосударственной стандартизации
7
+ # (Recommendations on interstate standardization). Issued by EASC.
8
+ #
9
+ # Examples:
10
+ # РМГ 151-2025
11
+ # РМГ 29-2013
12
+ class Rmg < Identifier
13
+ def self.type
14
+ { key: :rmg, title: "Interstate Recommendations", series: "RMG" }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ module Identifiers
6
+ autoload :Pmg, "#{__dir__}/identifiers/pmg"
7
+ autoload :Rmg, "#{__dir__}/identifiers/rmg"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Easc
7
+ # Parslet grammar for EASC identifiers.
8
+ #
9
+ # Accepts the Cyrillic surface forms observed in mgscatalog.by:
10
+ #
11
+ # ПМГ 03-2025
12
+ # ПМГ В 31-2001 (defense variant)
13
+ # РМГ 151-2025
14
+ # РМГ 29-2013
15
+ #
16
+ # Also accepts Latin transliterations (PMG, RMG, V) for
17
+ # round-tripping with English-language tooling. The renderer
18
+ # emits Cyrillic as the canonical form.
19
+ class Parser < Parslet::Parser
20
+ include ::Pubid::Parser::CommonParseRules
21
+
22
+ root :identifier
23
+
24
+ rule(:space) { str(" ") }
25
+ rule(:space?) { space.maybe }
26
+ rule(:dot) { str(".") }
27
+
28
+ # Year separator: ASCII hyphen OR Unicode em-dash / en-dash,
29
+ # optionally surrounded by whitespace.
30
+ rule(:year_sep) do
31
+ space?.maybe >> (str("-") | str("—") | str("–")) >> space?.maybe
32
+ end
33
+
34
+ # Series prefix. Captured to route to the right Identifiers::*
35
+ # subclass (Pmg vs Rmg). Both Cyrillic and Latin forms.
36
+ rule(:series_word) do
37
+ (str("ПМГ") | str("РМГ") | str("PMG") | str("RMG")).as(:series) >> space
38
+ end
39
+
40
+ # Defense variant marker — Cyrillic "В" or Latin "V".
41
+ rule(:variant_word) do
42
+ (str("В") | str("V")).as(:variant) >> space
43
+ end
44
+
45
+ rule(:prefix) do
46
+ series_word >> variant_word.maybe
47
+ end
48
+
49
+ rule(:digits) do
50
+ match("[0-9]").repeat(1)
51
+ end
52
+
53
+ rule(:number) do
54
+ (digits >> (dot >> digits).repeat).as(:number)
55
+ end
56
+
57
+ rule(:year_2digit) do
58
+ match("[0-9]").repeat(2, 2)
59
+ end
60
+
61
+ rule(:year_4digit) do
62
+ match("[0-9]").repeat(4, 4)
63
+ end
64
+
65
+ rule(:year) do
66
+ (year_4digit | year_2digit).as(:year)
67
+ end
68
+
69
+ rule(:identifier) do
70
+ prefix >> number >> (year_sep >> year).maybe
71
+ end
72
+
73
+ def self.parse(string)
74
+ raise ArgumentError, ::Pubid::INPUT_TOO_LONG_MESSAGE if string.length > ::Pubid::MAX_INPUT_LENGTH
75
+
76
+ new.parse(string.strip)
77
+ end
78
+ end
79
+ end
80
+ end