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
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ # Human-readable renderer for EASC identifiers.
6
+ #
7
+ # Produces strings like:
8
+ # "ПМГ 03-2025"
9
+ # "ПМГ В 31-2001" (defense variant)
10
+ # "РМГ 151-2025"
11
+ #
12
+ # Always renders in Cyrillic — the canonical form used on
13
+ # mgscatalog.by. Latin transliterations (PMG, RMG, V) parse but
14
+ # render to Cyrillic.
15
+ class Renderer < ::Pubid::Renderers::Base
16
+ CYRILLIC_SERIES = {
17
+ "PMG" => "ПМГ",
18
+ "RMG" => "РМГ",
19
+ }.freeze
20
+
21
+ CYRILLIC_VARIANT = "В".freeze
22
+
23
+ def render(context: nil, **_opts)
24
+ id = @id
25
+
26
+ if id.is_a?(Identifiers::Pmg) || id.is_a?(Identifiers::Rmg)
27
+ return render_standard(id)
28
+ end
29
+
30
+ raise ArgumentError, "Unknown EASC identifier class: #{id.class}"
31
+ end
32
+
33
+ private
34
+
35
+ def render_standard(id)
36
+ rendered = +"#{cyrillic_series(id.series)}"
37
+ rendered << " #{CYRILLIC_VARIANT}" if id.variant == "V"
38
+ rendered << " #{id.number}"
39
+ rendered << "-#{id.year}" if id.year
40
+ rendered
41
+ end
42
+
43
+ def cyrillic_series(series)
44
+ CYRILLIC_SERIES.fetch(series, series)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ # Generates URN strings for EASC identifiers.
6
+ #
7
+ # Format:
8
+ # urn:easc:<series>[:<variant>]:<number>[:<year>]
9
+ #
10
+ # Examples:
11
+ # urn:easc:pmg:3:2025
12
+ # urn:easc:pmg:v:31:2001
13
+ # urn:easc:rmg:151:2025
14
+ class UrnGenerator
15
+ attr_reader :identifier
16
+
17
+ def initialize(identifier)
18
+ @identifier = identifier
19
+ end
20
+
21
+ def generate
22
+ unless identifier.is_a?(Identifiers::Pmg) ||
23
+ identifier.is_a?(Identifiers::Rmg)
24
+ raise ArgumentError,
25
+ "Unknown EASC identifier class: #{identifier.class}"
26
+ end
27
+
28
+ parts = ["urn:easc", series_lower]
29
+ parts << variant_lower if identifier.variant
30
+ parts << identifier.number.to_s
31
+ parts << identifier.year.to_s if identifier.year
32
+ parts.join(":")
33
+ end
34
+
35
+ private
36
+
37
+ def series_lower
38
+ identifier.series.to_s.downcase
39
+ end
40
+
41
+ def variant_lower
42
+ identifier.variant.to_s.downcase
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ # Parses EASC URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:easc:<series>[:<variant>]:<number>[:<year>]
9
+ #
10
+ # Examples:
11
+ # urn:easc:pmg:3:2025 → ПМГ 3-2025
12
+ # urn:easc:pmg:v:31:2001 → ПМГ В 31-2001
13
+ # urn:easc:rmg:151:2025 → РМГ 151-2025
14
+ class UrnParser < Pubid::UrnParser::Base
15
+ PREFIX = "urn:easc:".freeze
16
+ VARIANT_SEGMENT = /\Av\z/i.freeze
17
+
18
+ def parse_urn(urn)
19
+ body = strip_namespace(urn)
20
+ parts = split_parts(body)
21
+ series = parts.fetch(0)
22
+ rest = parts.drop(1)
23
+
24
+ variant = nil
25
+ if rest.first&.match?(VARIANT_SEGMENT)
26
+ variant = "V"
27
+ rest = rest.drop(1)
28
+ end
29
+ number = rest[0]
30
+ year = rest[1]
31
+
32
+ klass = Easc.identifier_klass_for_series(series) || Identifier
33
+ klass.new(series: series.upcase, variant: variant,
34
+ number: number, year: year)
35
+ end
36
+
37
+ private
38
+
39
+ def strip_namespace(urn)
40
+ unless urn.downcase.start_with?(PREFIX)
41
+ raise Pubid::UrnParser::Errors::ParseError,
42
+ "Invalid EASC URN: #{urn.inspect}"
43
+ end
44
+
45
+ urn[PREFIX.length..]
46
+ end
47
+
48
+ def split_parts(body)
49
+ parts = body.split(":")
50
+ raise Pubid::UrnParser::Errors::ParseError,
51
+ "EASC URN missing series: #{body.inspect}" if parts.empty?
52
+
53
+ parts
54
+ end
55
+ end
56
+ end
57
+ end
data/lib/pubid/easc.rb ADDED
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Easc
5
+ extend Pubid::PrefixesSupport
6
+
7
+ # Leading identifier tokens that an EASC document id can start with.
8
+ # Both Cyrillic (canonical — ПМГ, РМГ) and Latin transliterations
9
+ # (PMG, RMG) are accepted; the canonical render is Cyrillic per
10
+ # mgscatalog.by convention.
11
+ PREFIXES = ["ПМГ", "РМГ", "PMG", "RMG"].freeze
12
+
13
+ autoload :Builder, "#{__dir__}/easc/builder"
14
+ autoload :Identifier, "#{__dir__}/easc/identifier"
15
+ autoload :Identifiers, "#{__dir__}/easc/identifiers"
16
+ autoload :Parser, "#{__dir__}/easc/parser"
17
+ autoload :Renderer, "#{__dir__}/easc/renderer"
18
+ autoload :UrnGenerator, "#{__dir__}/easc/urn_generator"
19
+ autoload :UrnParser, "#{__dir__}/easc/urn_parser"
20
+
21
+ # @param identifier [String]
22
+ # @return [Pubid::Easc::Identifier]
23
+ def self.parse(identifier)
24
+ Identifier.parse(identifier)
25
+ end
26
+
27
+ # Per-flavor format registry.
28
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
29
+ Identifier.format_registry.register(:human, renderer: Easc::Renderer)
30
+
31
+ # Auto-discover identifier types from the Identifiers namespace.
32
+ # @return [Array<Class>]
33
+ def self.identifier_types
34
+ @identifier_types ||= Identifiers.constants
35
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
36
+ .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
37
+ .reject { |c| c == Identifier }
38
+ end
39
+
40
+ # Lookup: series (ПМГ / РМГ / PMG / RMG) → identifier class
41
+ # @param series [String, Symbol]
42
+ # @return [Class<Identifier>, nil]
43
+ def self.identifier_klass_for_series(series)
44
+ @by_series ||= identifier_types.to_h do |klass|
45
+ [klass.type[:series].to_s, klass]
46
+ end
47
+ @by_series[series.to_s] || @by_series[series.to_s.upcase]
48
+ end
49
+ end
50
+ end
51
+
52
+ Pubid::Registry.register(:easc, Pubid::Easc)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ # Turns the Parslet parse tree into a concrete identifier object. The class
6
+ # is chosen by which number key the parser captured.
7
+ class Builder
8
+ def self.build(parsed_data)
9
+ new.build(parsed_data)
10
+ end
11
+
12
+ def build(data)
13
+ if data[:tr_number]
14
+ Identifiers::TechnicalReport.new(number: data[:tr_number].to_s)
15
+ elsif data[:mem_number]
16
+ Identifiers::Memento.new(number: data[:mem_number].to_s)
17
+ else
18
+ build_standard(data)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def build_standard(data)
25
+ attrs = { number: data[:number].to_s }
26
+ attrs[:part] = data[:part].to_s if data[:part]
27
+ Identifiers::Standard.new(**attrs)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ # Base class for every ECMA identifier AND the flavor's parse entry point —
6
+ # mirrors Pubid::Jis::Identifier. Concrete identifiers under
7
+ # Pubid::Ecma::Identifiers descend from this class, so a parsed ECMA id is
8
+ # an instance of Pubid::Ecma::Identifier. ECMA has no supplement layer.
9
+ class Identifier < ::Pubid::Identifier
10
+ # The document number as a string (preserves any leading zeros). `part`
11
+ # is only present for standards that split into parts (e.g. ECMA-418-1).
12
+ attribute :number, :string
13
+ attribute :part, :string
14
+ # Edition is separate metadata (the index stores {:id, :ed} and the YAML
15
+ # has edition.content); it is NOT part of the printed identifier string.
16
+ # Modelled as an optional string (decimal editions like "5.1" occur) that
17
+ # serializes in `to_hash` — so relaton preserves `:ed:` — but is omitted
18
+ # from `to_s`. No default, so it drops from the hash when unset.
19
+ attribute :edition, :string
20
+
21
+ # Polymorphic type map for lutaml::Model key_value (de)serialization:
22
+ # maps each subclass's polymorphic_name to its class name so a stored
23
+ # hash rebuilds the correct identifier type via from_hash.
24
+ ECMA_TYPE_MAP = {
25
+ "pubid:ecma:standard" => "Pubid::Ecma::Identifiers::Standard",
26
+ "pubid:ecma:technical-report" =>
27
+ "Pubid::Ecma::Identifiers::TechnicalReport",
28
+ "pubid:ecma:memento" => "Pubid::Ecma::Identifiers::Memento",
29
+ }.freeze
30
+
31
+ key_value do
32
+ map "_type", to: :_type, polymorphic_map: ECMA_TYPE_MAP
33
+ map "number", to: :number
34
+ map "part", to: :part
35
+ map "edition", to: :edition
36
+ end
37
+
38
+ # Publisher is always "ECMA". A plain constant (not a `publisher` method)
39
+ # so it doesn't shadow the inherited lutaml `publisher` attribute, which
40
+ # would otherwise fail serialization type validation.
41
+ PUBLISHER = "ECMA"
42
+
43
+ # Whether the last `to_s` should include the "ECMA" publisher token.
44
+ attr_reader :with_publisher
45
+
46
+ # Basic string representation. Delegates to renderer. `with_publisher:
47
+ # false` drops the ECMA token (e.g. "-411", "TR/84").
48
+ def to_s(with_publisher: true, **opts)
49
+ @with_publisher = with_publisher
50
+ render(format: :human, **opts)
51
+ end
52
+
53
+ # Type token that precedes the number ("TR"/"MEM"), or nil for standards.
54
+ # Overridden by each concrete identifier class.
55
+ def type_prefix
56
+ nil
57
+ end
58
+
59
+ # Parse an ECMA identifier string into an identifier object.
60
+ # @param identifier [String] The ECMA identifier string to parse
61
+ # @return [Identifier] The appropriate identifier object
62
+ # @raise [ArgumentError] If the input exceeds MAX_INPUT_LENGTH
63
+ # @raise [RuntimeError] If parsing fails
64
+ def self.parse(identifier)
65
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
66
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
67
+ end
68
+
69
+ parsed = Parser.parse(identifier)
70
+ Builder.build(parsed)
71
+ rescue Parslet::ParseFailed => e
72
+ raise "Failed to parse ECMA identifier '#{identifier}': #{e.message}"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ module Identifiers
6
+ # Memento identifier type.
7
+ # Format: ECMA MEM/<year>. Example: ECMA MEM/1970
8
+ class Memento < Identifier
9
+ TYPED_STAGES = [
10
+ Pubid::Components::TypedStage.new(
11
+ code: :mem,
12
+ stage_code: :published,
13
+ type_code: :ecma,
14
+ abbr: ["MEM"],
15
+ name: "Memento",
16
+ harmonized_stages: [],
17
+ ),
18
+ ].freeze
19
+
20
+ def self.type
21
+ { key: :mem, web: :memento, title: "Memento", short: "MEM" }
22
+ end
23
+
24
+ def type_prefix
25
+ "MEM"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ module Identifiers
6
+ # Default ECMA identifier type (no type token).
7
+ # Examples: ECMA-411, ECMA-418-1
8
+ class Standard < Identifier
9
+ TYPED_STAGES = [
10
+ Pubid::Components::TypedStage.new(
11
+ code: :standard,
12
+ stage_code: :published,
13
+ type_code: :ecma,
14
+ abbr: ["ECMA"],
15
+ name: "Standard",
16
+ harmonized_stages: [],
17
+ ),
18
+ ].freeze
19
+
20
+ def self.type
21
+ { key: :standard, web: :standard, title: "Standard", short: "ECMA" }
22
+ end
23
+
24
+ # No type token for standards.
25
+ def type_prefix
26
+ nil
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ module Identifiers
6
+ # Technical Report identifier type.
7
+ # Format: ECMA TR/<number>. Example: ECMA TR/101
8
+ class TechnicalReport < Identifier
9
+ TYPED_STAGES = [
10
+ Pubid::Components::TypedStage.new(
11
+ code: :tr,
12
+ stage_code: :published,
13
+ type_code: :ecma,
14
+ abbr: ["TR"],
15
+ name: "Technical Report",
16
+ harmonized_stages: [],
17
+ ),
18
+ ].freeze
19
+
20
+ def self.type
21
+ { key: :tr, web: :technical_report, title: "Technical Report",
22
+ short: "TR" }
23
+ end
24
+
25
+ def type_prefix
26
+ "TR"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ module Identifiers
6
+ autoload :Standard, "#{__dir__}/identifiers/standard"
7
+ autoload :TechnicalReport, "#{__dir__}/identifiers/technical_report"
8
+ autoload :Memento, "#{__dir__}/identifiers/memento"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Ecma
7
+ # Parslet grammar for ECMA identifiers.
8
+ #
9
+ # Four printed forms (see HANDOFFS/ecma.md):
10
+ # ECMA-411 standard
11
+ # ECMA-418-1 standard with part
12
+ # ECMA TR/101 technical report
13
+ # ECMA MEM/1970 memento
14
+ #
15
+ # Each branch captures its number under a distinct key so the builder can
16
+ # pick the identifier class without a separate type token. Numbers are kept
17
+ # as strings to preserve any leading zeros.
18
+ class Parser < Parslet::Parser
19
+ rule(:digits) { match["0-9"].repeat(1) }
20
+
21
+ rule(:prefix) { str("ECMA") }
22
+
23
+ rule(:tr) { str(" TR/") >> digits.as(:tr_number) }
24
+
25
+ rule(:mem) { str(" MEM/") >> digits.as(:mem_number) }
26
+
27
+ rule(:standard) do
28
+ str("-") >> digits.as(:number) >>
29
+ (str("-") >> digits.as(:part)).maybe
30
+ end
31
+
32
+ rule(:identifier) { prefix >> (tr | mem | standard) }
33
+
34
+ rule(:root) { identifier }
35
+
36
+ def self.parse(input)
37
+ new.parse(input)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ # Human-readable renderer for ECMA identifiers.
6
+ #
7
+ # Produces strings like:
8
+ # "ECMA-411" standard
9
+ # "ECMA-418-1" standard with part
10
+ # "ECMA TR/101" technical report
11
+ # "ECMA MEM/1970" memento
12
+ #
13
+ # With `with_publisher: false` the leading ECMA token is dropped, yielding
14
+ # "-411" / "TR/101" / "MEM/1970". The edition is never rendered — it is
15
+ # separate metadata carried only in `to_hash`.
16
+ class Renderer < ::Pubid::Renderers::Base
17
+ PUBLISHER = "ECMA"
18
+
19
+ def render(context: nil, **opts)
20
+ id = @id
21
+ # Standard joins the publisher directly ("ECMA-411"); TR/MEM separate it
22
+ # with a space ("ECMA TR/101"). type_prefix is nil only for standards.
23
+ sep = id.type_prefix.nil? ? "" : " "
24
+ core = id.type_prefix.nil? ? standard_core(id) : typed_core(id)
25
+ with_publisher?(id) ? "#{PUBLISHER}#{sep}#{core}" : core
26
+ end
27
+
28
+ private
29
+
30
+ # Standard: "-<number>[-<part>]".
31
+ def standard_core(id)
32
+ core = "-#{id.number}"
33
+ id.part ? "#{core}-#{id.part}" : core
34
+ end
35
+
36
+ # Technical Report / Memento: "<TYPE>/<number>".
37
+ def typed_core(id)
38
+ "#{id.type_prefix}/#{id.number}"
39
+ end
40
+
41
+ def with_publisher?(id)
42
+ id.with_publisher != false
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ # Emits `urn:ecma:<tag>:<number>[:part-<part>]` where the tag is bare for
6
+ # standards, "tr" for technical reports and "mem" for mementos:
7
+ # ECMA-411 -> urn:ecma:411
8
+ # ECMA-418-1 -> urn:ecma:418:part-1
9
+ # ECMA TR/101 -> urn:ecma:tr:101
10
+ # ECMA MEM/1970 -> urn:ecma:mem:1970
11
+ class UrnGenerator < Pubid::UrnGenerator::Base
12
+ def generate
13
+ parts = ["urn", "ecma"]
14
+
15
+ tag = identifier.type_prefix&.downcase
16
+ parts << tag if tag
17
+
18
+ parts << identifier.number.to_s
19
+ parts << "part-#{identifier.part}" if identifier.part
20
+
21
+ parts.join(":")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ # Parses ECMA URNs back into identifiers, inverting {UrnGenerator}.
6
+ #
7
+ # Examples:
8
+ # urn:ecma:411 -> ECMA-411
9
+ # urn:ecma:418:part-1 -> ECMA-418-1
10
+ # urn:ecma:tr:101 -> ECMA TR/101
11
+ # urn:ecma:mem:1970 -> ECMA MEM/1970
12
+ class UrnParser < Pubid::UrnParser::Base
13
+ def parse_urn(urn)
14
+ parts = split_parts(strip_namespace(urn))
15
+ tag = %w[tr mem].include?(parts.first) ? parts.shift : nil
16
+ number = parts.shift
17
+ part = if parts.first&.start_with?("part-")
18
+ parts.shift.sub("part-", "")
19
+ end
20
+ flavor_parse(reconstruct(tag, number, part))
21
+ end
22
+
23
+ private
24
+
25
+ # Rebuild the printed identifier string from the URN fields.
26
+ def reconstruct(tag, number, part)
27
+ case tag
28
+ when "tr" then "ECMA TR/#{number}"
29
+ when "mem" then "ECMA MEM/#{number}"
30
+ else part ? "ECMA-#{number}-#{part}" : "ECMA-#{number}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/pubid/ecma.rb ADDED
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ecma
5
+ extend Pubid::PrefixesSupport
6
+
7
+ # Sole ECMA publisher token (see the parser's `prefix` rule). Document types
8
+ # (TR/MEM) follow the ECMA prefix as type tokens and are excluded.
9
+ PREFIXES = ["ECMA"].freeze
10
+
11
+ autoload :Builder, "#{__dir__}/ecma/builder"
12
+ autoload :Identifier, "#{__dir__}/ecma/identifier"
13
+ autoload :Identifiers, "#{__dir__}/ecma/identifiers"
14
+ autoload :Parser, "#{__dir__}/ecma/parser"
15
+ autoload :Renderer, "#{__dir__}/ecma/renderer"
16
+ autoload :UrnGenerator, "#{__dir__}/ecma/urn_generator"
17
+ autoload :UrnParser, "#{__dir__}/ecma/urn_parser"
18
+
19
+ # Parse an ECMA identifier string
20
+ def self.parse(identifier)
21
+ Identifier.parse(identifier)
22
+ end
23
+
24
+ # Per-flavor format registry: inherits global formats, overrides :human
25
+ Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
26
+ Identifier.format_registry.register(:human, renderer: Ecma::Renderer)
27
+
28
+ # Auto-discover all identifier types from the Identifiers namespace
29
+ # @return [Array<Class>] identifier classes that define a self.type Hash
30
+ def self.identifier_types
31
+ @identifier_types ||= Identifiers.constants
32
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
33
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
34
+ .select { |c| c.type.is_a?(Hash) }
35
+ end
36
+
37
+ # Build typed stage index from identifier types
38
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
39
+ def self.all_typed_stages
40
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
41
+ if klass.const_defined?(:TYPED_STAGES)
42
+ klass.const_get(:TYPED_STAGES)
43
+ else
44
+ []
45
+ end
46
+ end
47
+ end
48
+
49
+ # Lookup: type code -> identifier class
50
+ # @param code [String, Symbol] the type key to find
51
+ # @return [Class, nil] the matching identifier class
52
+ def self.locate_type(code)
53
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
54
+ end
55
+
56
+ # Lookup: abbreviation -> typed stage
57
+ # @param abbr [String, Symbol] the abbreviation to find
58
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
59
+ def self.locate_stage(abbr)
60
+ abbr_str = abbr.to_s.upcase
61
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
62
+ end
63
+ end
64
+ end
65
+
66
+ # Register ECMA flavor with the registry
67
+ Pubid::Registry.register(:ecma, Pubid::Ecma)
@@ -95,19 +95,23 @@ module Pubid
95
95
  end
96
96
 
97
97
  def build_version(data)
98
- # Handle both version and edition
98
+ # Handle both version and edition. A partial reference omits both, in
99
+ # which case version is left nil (not defaulted) so exclude/matches?
100
+ # treat it as a wildcard.
99
101
  if data[:version]
100
102
  Components::Version.new(version: data[:version].to_s,
101
103
  is_edition: false)
102
104
  elsif data[:edition]
103
105
  Components::Version.new(version: data[:edition].to_s,
104
106
  is_edition: true)
105
- else
106
- Components::Version.new(version: "1.0.0", is_edition: false)
107
107
  end
108
108
  end
109
109
 
110
110
  def build_date(data)
111
+ # A partial reference omits the date; leave it nil rather than building
112
+ # an empty Date, so the canonical to_hash drops it entirely.
113
+ return nil unless data[:year]
114
+
111
115
  Pubid::Components::Date.new(
112
116
  year: data[:year].to_s,
113
117
  month: data[:month].to_s,
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Pubid::Etsi::Identifier is the ETSI 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.