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
@@ -6,23 +6,23 @@ module Pubid
6
6
  # Supplements wrap a base identifier with additional edition information
7
7
  #
8
8
  # Architecture follows ISO pattern:
9
- # - base_identifier: The base document being supplemented
9
+ # - base: The base document being supplemented
10
10
  # - edition: Edition information for the supplement
11
11
  #
12
12
  # Examples:
13
13
  # - "NBS CIRC 101e2supp" → CircularSupplement(base: "NBS CIRC 101", edition: e2)
14
14
  # - "NBS CIRC 25supp-1924" → CircularSupplement(base: "NBS CIRC 25", edition: 1924)
15
- class SupplementIdentifier < Identifiers::Base
16
- attribute :base_identifier, Identifiers::Base, polymorphic: true
15
+ class SupplementIdentifier < Identifier
16
+ attribute :base, Identifier, polymorphic: true
17
17
 
18
- # Delegate publisher to base_identifier
18
+ # Delegate publisher to base
19
19
  def publisher
20
- base_identifier&.publisher
20
+ base&.publisher
21
21
  end
22
22
 
23
- # Delegate series to base_identifier
23
+ # Delegate series to base
24
24
  def series
25
- base_identifier&.series
25
+ base&.series
26
26
  end
27
27
 
28
28
  def to_s(format = :short)
@@ -31,9 +31,9 @@ module Pubid
31
31
  return "NBS CIRC sup#{supplement_date_range_start}-#{supplement_date_range_end}"
32
32
  end
33
33
 
34
- return super unless base_identifier
34
+ return super unless base
35
35
 
36
- result = base_identifier.to_s(format)
36
+ result = base.to_s(format)
37
37
 
38
38
  # NEW: Handle update attribute (e.g., "Upd12-1926" for supplement patterns)
39
39
  if update
data/lib/pubid/nist.rb CHANGED
@@ -13,6 +13,7 @@ module Pubid
13
13
  NIST NBS
14
14
  AMS VTS BSS BMS BH FIPS GCR HB MONO MP NCSTAR NSRDS IR SP TN CSWP
15
15
  AI CIRC CS CSM CRPL LCIRC OWMWP PC RPT SIBS TIBM TTB EAB JPCRD JRES
16
+ CHIPS NWIRP RB
16
17
  ].freeze
17
18
 
18
19
  autoload :Builder, "#{__dir__}/nist/builder"
@@ -20,7 +21,7 @@ module Pubid
20
21
  autoload :CircularSupplementBuilder, "#{__dir__}/nist/circular_supplement_builder"
21
22
  autoload :Components, "#{__dir__}/nist/components"
22
23
  autoload :Configuration, "#{__dir__}/nist/configuration"
23
- autoload :Identifier, "#{__dir__}/nist/identifier"
24
+ autoload :Identifier, "#{__dir__}/nist/identifiers/base"
24
25
  autoload :Identifiers, "#{__dir__}/nist/identifiers"
25
26
  autoload :Parser, "#{__dir__}/nist/parser"
26
27
  autoload :ParserOutputNormalizer, "#{__dir__}/nist/parser_output_normalizer"
@@ -36,7 +37,7 @@ module Pubid
36
37
  #
37
38
  # NIST identifier classes use `typed_stages` (not the `self.type` Hash
38
39
  # pattern used by CEN/JCGM/ANSI), so they cannot be auto-discovered.
39
- # Identifiers::Base is the fallback for unmapped series (e.g. AMS, VTS)
40
+ # Identifier is the fallback for unmapped series (e.g. AMS, VTS)
40
41
  # and must be excluded from typed-stage aggregation.
41
42
  IDENTIFIER_TYPES = [
42
43
  Identifiers::SpecialPublication,
@@ -59,12 +60,12 @@ module Pubid
59
60
  Identifiers::CommercialStandardEmergency,
60
61
  Identifiers::CommercialStandardsMonthly,
61
62
  Identifiers::DatedDocument,
62
- Identifiers::Base, # Fallback for unmapped series
63
+ Identifier, # Fallback for unmapped series
63
64
  ].freeze
64
65
 
65
66
  # Parse a NIST identifier string
66
67
  # @param identifier [String] the identifier string to parse
67
- # @return [Identifiers::Base] the parsed identifier
68
+ # @return [Identifier] the parsed identifier
68
69
  def self.parse(identifier)
69
70
  if identifier.length > Pubid::MAX_INPUT_LENGTH
70
71
  raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
@@ -86,36 +87,36 @@ module Pubid
86
87
  end
87
88
 
88
89
  # Per-flavor format registry: inherits global formats, overrides :human
89
- Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
90
- Identifiers::Base.format_registry.register(:human, renderer: Nist::Renderer)
90
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
91
+ Identifier.format_registry.register(:human, renderer: Nist::Renderer)
91
92
 
92
93
  # All identifier classes for external consumption (export, website).
93
- # Identifiers::Base is the fallback for unmapped series and is excluded
94
+ # Identifier is the fallback for unmapped series and is excluded
94
95
  # from external type listings.
95
96
  # @return [Array<Class>] identifier classes
96
97
  def self.identifier_types
97
- IDENTIFIER_TYPES.reject { |klass| klass == Identifiers::Base }
98
+ IDENTIFIER_TYPES.reject { |klass| klass == Identifier }
98
99
  end
99
100
 
100
101
  # Aggregate TYPED_STAGES from all identifier classes.
101
- # Identifiers::Base is excluded because it has no typed stages and acts
102
+ # Identifier is excluded because it has no typed stages and acts
102
103
  # as the fallback for unmapped series.
103
104
  # @return [Array<Pubid::Components::TypedStage>] all typed stages
104
105
  def self.all_typed_stages
105
106
  @all_typed_stages ||= identifier_types
106
- .reject { |klass| klass == Identifiers::Base }
107
+ .reject { |klass| klass == Identifier }
107
108
  .flat_map(&:typed_stages)
108
109
  .freeze
109
110
  end
110
111
 
111
112
  # Lookup: type code -> identifier class.
112
- # Identifiers::Base is excluded so it never gets selected by type code.
113
+ # Identifier is excluded so it never gets selected by type code.
113
114
  # @param code [String, Symbol] the type code to find
114
115
  # @return [Class, nil] the matching identifier class, or nil
115
116
  def self.locate_type(code)
116
117
  type_str = code.to_s
117
118
  identifier_types
118
- .reject { |klass| klass == Identifiers::Base }
119
+ .reject { |klass| klass == Identifier }
119
120
  .find { |klass| klass.typed_stages.any? { |ts| ts.type_code.to_s == type_str } }
120
121
  end
121
122
 
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ # Turns the parse tree into an `Identifiers::Standard`: stores the slug
6
+ # verbatim in `original`, then performs a best-effort, ORDER-INDEPENDENT
7
+ # decomposition into spec / version / stage / part / label.
8
+ #
9
+ # Decomposition splits `original` on "-" and classifies each *whole*
10
+ # fragment (so a stage-like substring inside a spec name — e.g. "CSDL" — is
11
+ # never mistaken for a stage). `spec` is the run of leading name fragments
12
+ # before the first recognized fragment; `version`/`stage`/`part` are the
13
+ # first fragment of each recognized kind; `label` is any name fragment
14
+ # appearing after the first recognized one. Anything the classifier cannot
15
+ # place stays only in `original`, so the printed form always round-trips.
16
+ class Builder
17
+ # A fragment is a version when it is `v?N(.N)+` (e.g. "3.0", "v1.2.1",
18
+ # "V1.0"). Bare integers are deliberately NOT versions (too ambiguous
19
+ # with spec-name tokens).
20
+ VERSION_RE = /\Av?\d+(?:\.\d+)+\z/i
21
+ # OASIS approval-stage tokens (+ optional revision digits). Longest-first
22
+ # so shared prefixes classify correctly (CSPRD/CSD before CS, COS before
23
+ # CS/OS).
24
+ STAGE_RE = /\A(?:CSPRD|CSD|COS|CS|WD|OS|PS|PRD|CD|Errata)\d*\z/
25
+ # Part tokens across the three observed spellings, plus bare "Pt"/"P".
26
+ PART_RE = /\A(?:Part|Pt|part|P)\d*\z/
27
+
28
+ def self.build(parsed_data)
29
+ new.build(parsed_data)
30
+ end
31
+
32
+ def build(data)
33
+ original = data[:original].to_s
34
+ Identifiers::Standard.new(original: original, **decompose(original))
35
+ end
36
+
37
+ private
38
+
39
+ # @return [Hash] best-effort { spec:, version:, stage:, part:, label: }.
40
+ # Each fragment is classified once into a [fragment, kind] pair. `spec` is
41
+ # the leading run of name fragments; `label` is any name fragment after
42
+ # the first recognized one; version/stage/part are the first of each kind.
43
+ def decompose(original)
44
+ pairs = original.split("-").map { |f| [f, classify(f)] }
45
+ lead = pairs.take_while { |_, kind| kind.nil? }
46
+ rest = pairs.drop(lead.length)
47
+ {
48
+ spec: names(lead),
49
+ version: first_of(rest, :version),
50
+ stage: first_of(rest, :stage),
51
+ part: first_of(rest, :part),
52
+ label: names(rest),
53
+ }
54
+ end
55
+
56
+ # @return [Symbol, nil] :version / :stage / :part, or nil for a name token
57
+ def classify(fragment)
58
+ return :version if fragment.match?(VERSION_RE)
59
+ return :stage if fragment.match?(STAGE_RE)
60
+ return :part if fragment.match?(PART_RE)
61
+
62
+ nil
63
+ end
64
+
65
+ # First fragment of the given kind among [fragment, kind] pairs, or nil.
66
+ def first_of(pairs, kind)
67
+ pairs.find { |_, k| k == kind }&.first
68
+ end
69
+
70
+ # Name (unclassified) fragments among the pairs, re-joined, or nil.
71
+ def names(pairs)
72
+ fragments = pairs.select { |_, kind| kind.nil? }.map(&:first)
73
+ fragments.empty? ? nil : fragments.join("-")
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ # Base class for every OASIS identifier AND the flavor's parse/create entry
6
+ # point. The single concrete type `Identifiers::Standard` descends from this
7
+ # class, so a parsed OASIS id is an instance of `Pubid::Oasis::Identifier`.
8
+ #
9
+ # OASIS identifiers are free-form slugs with an inconsistent internal
10
+ # structure (spec name + version + approval stage + part + label, in
11
+ # varying order). To guarantee a lossless round-trip we always keep the
12
+ # exact printed slug verbatim in `original` (which alone drives `to_s`); the
13
+ # remaining component fields are a best-effort decomposition for relaton
14
+ # querying and can be nil without ever affecting the rendered string.
15
+ class Identifier < ::Pubid::Identifier
16
+ # The exact slug printed after "OASIS " — always set. Drives `to_s`, so
17
+ # the printed form round-trips verbatim regardless of decomposition.
18
+ attribute :original, :string
19
+ # Best-effort decomposition (any may be nil). `spec`/`label` are plain
20
+ # slug fragments; `version`/`stage`/`part` carry the recognized fragment
21
+ # verbatim (e.g. "3.0", "v1.2.1", "PS01", "Errata01", "Pt8", "Part1").
22
+ attribute :spec, :string
23
+ attribute :version, :string
24
+ # `stage`/`part` intentionally override the inherited Components::Stage /
25
+ # Components::Code attributes with plain strings (same mechanism JIS uses
26
+ # for `number`, W3C for `date`): OASIS stages/parts are opaque tokens that
27
+ # must round-trip exactly and are never re-parsed as structured parts.
28
+ attribute :stage, :string
29
+ attribute :part, :string
30
+ attribute :label, :string
31
+
32
+ # Polymorphic type map for lutaml::Model key_value (de)serialization: maps
33
+ # the subclass's polymorphic_name to its class name so a stored hash
34
+ # rebuilds the correct identifier type via from_hash.
35
+ OASIS_TYPE_MAP = {
36
+ "pubid:oasis:standard" => "Pubid::Oasis::Identifiers::Standard",
37
+ }.freeze
38
+
39
+ key_value do
40
+ map "_type", to: :_type, polymorphic_map: OASIS_TYPE_MAP
41
+ map "original", to: :original
42
+ map "spec", to: :spec
43
+ map "version", to: :version
44
+ map "stage", to: :stage
45
+ map "part", to: :part
46
+ map "label", to: :label
47
+ end
48
+
49
+ # Publisher is always "OASIS". A plain constant (not a `publisher` method)
50
+ # so it doesn't shadow the inherited lutaml `publisher` attribute, which
51
+ # would otherwise fail serialization type validation.
52
+ PUBLISHER = "OASIS"
53
+
54
+ attr_reader :with_publisher
55
+
56
+ def to_s(with_publisher: true, **opts)
57
+ @with_publisher = with_publisher
58
+ render(format: :human, **opts)
59
+ end
60
+
61
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier;
62
+ # OASIS_TYPE_MAP remains as the key_value polymorphic_map.
63
+
64
+ # Parse an OASIS identifier string into an identifier object
65
+ # @param identifier [String] The OASIS identifier string to parse
66
+ # @return [Identifier] The Standard identifier object
67
+ # @raise [RuntimeError] If parsing fails
68
+ def self.parse(identifier)
69
+ # Reject pathological inputs before they reach the parser
70
+ # (CodeQL rb/polynomial-redos barrier — inline .length by design).
71
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
72
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
73
+ end
74
+
75
+ parsed = Parser.parse(identifier)
76
+ Builder.build(parsed)
77
+ rescue Parslet::ParseFailed => e
78
+ raise "Failed to parse OASIS identifier '#{identifier}': #{e.message}"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ module Identifiers
6
+ # The sole OASIS identifier type. OASIS records carry no document-type
7
+ # distinction in the printed id (every record is `type: OASIS`); the
8
+ # approval stage lives in the `stage` component field, not in the class.
9
+ # Example: "OASIS OSLC-CoreShapes-3.0-PS01-Pt8".
10
+ class Standard < Identifier
11
+ TYPED_STAGES = [
12
+ Pubid::Components::TypedStage.new(
13
+ code: :oasis,
14
+ stage_code: :published,
15
+ type_code: :oasis,
16
+ abbr: ["OASIS"],
17
+ name: "OASIS Standard",
18
+ harmonized_stages: [],
19
+ ),
20
+ ].freeze
21
+
22
+ def self.type
23
+ { key: :oasis, web: :standard, title: "OASIS Standard",
24
+ short: "OASIS" }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ module Identifiers
6
+ autoload :Standard, "#{__dir__}/identifiers/standard"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Oasis
7
+ # Parslet grammar for printed OASIS identifiers, e.g.
8
+ # "OASIS OSLC-CoreShapes-3.0-PS01-Pt8"
9
+ # "OASIS amqp-core"
10
+ #
11
+ # OASIS slugs are free-form with a highly inconsistent internal structure
12
+ # (varying fragment order, three part spellings, mixed case, a few
13
+ # malformed records with spaces or stray characters). The grammar therefore
14
+ # only strips the "OASIS " publisher prefix and captures the remainder
15
+ # verbatim; the spec/version/stage/part/label decomposition is done in the
16
+ # Builder with order-independent fragment classification. Keeping
17
+ # decomposition out of the PEG avoids brittle backtracking and guarantees a
18
+ # lossless round-trip.
19
+ class Parser < Parslet::Parser
20
+ rule(:prefix) { str("OASIS") >> str(" ") }
21
+
22
+ # The whole slug, captured verbatim (any character, incl. spaces / "]").
23
+ rule(:slug) { any.repeat(1).as(:original) }
24
+
25
+ rule(:identifier) { prefix >> slug }
26
+
27
+ rule(:root) { identifier }
28
+
29
+ def self.parse(input)
30
+ new.parse(input)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ # Human-readable renderer for OASIS identifiers.
6
+ #
7
+ # Renders the verbatim slug (`original`), prefixed with the "OASIS "
8
+ # publisher token unless `id.with_publisher == false`. Because rendering is
9
+ # a pure echo of `original`, the printed form always round-trips exactly.
10
+ #
11
+ # "OASIS OSLC-CoreShapes-3.0-PS01-Pt8" (with publisher)
12
+ # "OSLC-CoreShapes-3.0-PS01-Pt8" (without)
13
+ class Renderer < ::Pubid::Renderers::Base
14
+ PUBLISHER = "OASIS"
15
+
16
+ def render(context: nil, **opts)
17
+ id = @id
18
+ body = id.original.to_s
19
+ with_publisher?(id) ? "#{PUBLISHER} #{body}" : body
20
+ end
21
+
22
+ private
23
+
24
+ def with_publisher?(id)
25
+ id.with_publisher != false
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ # Emits `urn:oasis:<slug>`, echoing the verbatim `original` as a single URN
6
+ # segment (OASIS slugs never contain ":"). The only characters that occur in
7
+ # real records outside the URN-safe set are the space and a stray "]" (both
8
+ # only in a handful of malformed records); these are percent-encoded so the
9
+ # URN stays well-formed, and UrnParser reverses them exactly.
10
+ #
11
+ # "OASIS amqp-core" -> "urn:oasis:amqp-core"
12
+ # "OASIS OSLC-CM-v1.0-CS01" -> "urn:oasis:OSLC-CM-v1.0-CS01"
13
+ class UrnGenerator < Pubid::UrnGenerator::Base
14
+ # Character -> percent-encoding for the non-URN-safe characters that
15
+ # actually appear in OASIS slugs. Kept explicit (not a blanket URI escape)
16
+ # so clean slugs — dots, hyphens, mixed case — pass through unchanged.
17
+ ENCODE = { " " => "%20", "]" => "%5D" }.freeze
18
+
19
+ def generate
20
+ slug = identifier.original.to_s.gsub(/[ \]]/) { |c| ENCODE[c] }
21
+ "urn:oasis:#{slug}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ # Parses OASIS URNs back into identifiers by reconstructing the printed form
6
+ # and delegating to the flavor's text parser.
7
+ #
8
+ # UrnGenerator emits `urn:oasis:<slug>` (single segment) with the space and
9
+ # "]" characters percent-encoded; reverse exactly those two here.
10
+ #
11
+ # urn:oasis:OSLC-CM-v1.0-CS01 -> OASIS OSLC-CM-v1.0-CS01
12
+ # urn:oasis:amqp-core -> OASIS amqp-core
13
+ class UrnParser < Pubid::UrnParser::Base
14
+ DECODE = { "%20" => " ", "%5D" => "]" }.freeze
15
+
16
+ def parse_urn(urn)
17
+ slug = strip_namespace(urn).gsub(/%20|%5D/, DECODE)
18
+ flavor_parse("OASIS #{slug}")
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Oasis
5
+ extend Pubid::PrefixesSupport
6
+
7
+ # Sole OASIS publisher token (see the parser's `prefix` rule). Everything
8
+ # after "OASIS " is a free-form slug, so there are no leading type tokens to
9
+ # exclude.
10
+ PREFIXES = ["OASIS"].freeze
11
+
12
+ autoload :Builder, "#{__dir__}/oasis/builder"
13
+ autoload :Identifier, "#{__dir__}/oasis/identifier"
14
+ autoload :Identifiers, "#{__dir__}/oasis/identifiers"
15
+ autoload :Parser, "#{__dir__}/oasis/parser"
16
+ autoload :Renderer, "#{__dir__}/oasis/renderer"
17
+ autoload :UrnGenerator, "#{__dir__}/oasis/urn_generator"
18
+ autoload :UrnParser, "#{__dir__}/oasis/urn_parser"
19
+
20
+ # Parse an OASIS identifier string
21
+ def self.parse(identifier)
22
+ # Reject pathological inputs before they reach the parser
23
+ # (CodeQL rb/polynomial-redos barrier — inline .length by design).
24
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
25
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
26
+ end
27
+
28
+ Identifier.parse(identifier)
29
+ end
30
+
31
+ # Per-flavor format registry: inherits global formats, overrides :human
32
+ Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
33
+ Identifier.format_registry.register(:human, renderer: Oasis::Renderer)
34
+
35
+ # Auto-discover all identifier types from the Identifiers namespace
36
+ # @return [Array<Class>] identifier classes that define a self.type Hash
37
+ def self.identifier_types
38
+ @identifier_types ||= Identifiers.constants
39
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
40
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
41
+ .select { |c| c.type.is_a?(Hash) }
42
+ end
43
+
44
+ # Build typed stage index from identifier types
45
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
46
+ def self.all_typed_stages
47
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
48
+ if klass.const_defined?(:TYPED_STAGES)
49
+ klass.const_get(:TYPED_STAGES)
50
+ else
51
+ []
52
+ end
53
+ end
54
+ end
55
+
56
+ # Lookup: type code -> identifier class
57
+ # @param code [String, Symbol] the type key to find
58
+ # @return [Class, nil] the matching identifier class
59
+ def self.locate_type(code)
60
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
61
+ end
62
+
63
+ # Lookup: abbreviation -> typed stage
64
+ # @param abbr [String, Symbol] the abbreviation to find
65
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
66
+ def self.locate_stage(abbr)
67
+ abbr_str = abbr.to_s.upcase
68
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
69
+ end
70
+ end
71
+ end
72
+
73
+ # Register OASIS flavor with the registry
74
+ Pubid::Registry.register(:oasis, Pubid::Oasis)
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ogc
5
+ # Turns the parse tree into an Ogc::Identifiers::Document. OGC has a single
6
+ # document type, so there is no type dispatch.
7
+ class Builder
8
+ def self.build(parsed_data)
9
+ new.build(parsed_data)
10
+ end
11
+
12
+ def build(data)
13
+ Identifiers::Document.new(
14
+ year: data[:year].to_s,
15
+ number: data[:number].to_s,
16
+ revision: normalize_revision(data[:revision]),
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ # Normalize the revision suffix to its canonical lowercased form (the
23
+ # shape the relaton index stores, e.g. "R1" -> "r1"). nil when there is
24
+ # no revision.
25
+ def normalize_revision(revision)
26
+ return nil if revision.nil?
27
+
28
+ normalized = revision.to_s.strip.downcase
29
+ normalized.empty? ? nil : normalized
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ogc
5
+ # Base class for every OGC identifier AND the flavor's parse/create entry
6
+ # point. There is a single concrete type (Identifiers::Document), so this
7
+ # base mostly exists to hold the shared attributes and the polymorphic
8
+ # serialization mapping.
9
+ class Identifier < ::Pubid::Identifier
10
+ # OGC ids are digit-leading (`<yy>-<nnn>`) with no publisher token in the
11
+ # printed form. Everything is kept as a string to preserve zero-padding
12
+ # ("032", not 32) and the exact revision suffix.
13
+ attribute :year, :string # the "<yy>" field, e.g. "24"
14
+ attribute :number, :string # the "<nnn>" field, e.g. "032"
15
+ # Optional revision suffix, stored as the full lowercased token including
16
+ # its separator letter: "r1", "c1", "a", "r3a", "r12a". nil when absent.
17
+ attribute :revision, :string
18
+
19
+ # Polymorphic type map for lutaml::Model key_value (de)serialization: maps
20
+ # the concrete class's polymorphic_name to its class name so a stored hash
21
+ # rebuilds the correct identifier type via from_hash.
22
+ OGC_TYPE_MAP = {
23
+ "pubid:ogc:document" => "Pubid::Ogc::Identifiers::Document",
24
+ }.freeze
25
+
26
+ key_value do
27
+ map "_type", to: :_type, polymorphic_map: OGC_TYPE_MAP
28
+ map "year", to: :year
29
+ map "number", to: :number
30
+ map "revision", to: :revision
31
+ end
32
+
33
+ # Publisher is always "OGC". A plain constant (not a `publisher` method)
34
+ # so it doesn't shadow the inherited lutaml `publisher` attribute, which
35
+ # would otherwise fail serialization type validation.
36
+ PUBLISHER = "OGC"
37
+
38
+ attr_reader :with_publisher
39
+
40
+ # Basic string representation. Delegates to the human renderer. The
41
+ # printed OGC id carries no publisher token, so with_publisher defaults to
42
+ # false; pass with_publisher: true to prepend "OGC ".
43
+ def to_s(**opts)
44
+ render(format: :human, **opts)
45
+ end
46
+
47
+ # Capture the with_publisher flag on EVERY render call (default false), so
48
+ # it can never leak across calls: a bare render/to_s always renders
49
+ # without the publisher token regardless of a prior with_publisher: true.
50
+ # The base `render` only forwards `:with_edition` to the renderer, so the
51
+ # flag is threaded via this per-call instance write (the renderer reads
52
+ # `id.with_publisher`).
53
+ def render(format: :human, with_publisher: false, **opts)
54
+ @with_publisher = with_publisher
55
+ super(format: format, **opts)
56
+ end
57
+
58
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier.
59
+ # OGC_TYPE_MAP remains as the key_value polymorphic_map.
60
+
61
+ # Parse an OGC identifier string into an identifier object.
62
+ # @param identifier [String] The OGC identifier string to parse
63
+ # @return [Identifier] The document identifier object
64
+ # @raise [ArgumentError] If the input exceeds the maximum length
65
+ # @raise [RuntimeError] If parsing fails
66
+ def self.parse(identifier)
67
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
68
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
69
+ end
70
+
71
+ Builder.build(Parser.parse(identifier))
72
+ rescue Parslet::ParseFailed => e
73
+ raise "Failed to parse OGC identifier '#{identifier}': #{e.message}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ogc
5
+ module Identifiers
6
+ # The sole OGC identifier type. An OGC document is numbered
7
+ # `<yy>-<nnn>[<revision>]` with no publisher token in the printed form.
8
+ class Document < Identifier
9
+ TYPED_STAGES = [
10
+ Pubid::Components::TypedStage.new(
11
+ code: :ogc,
12
+ stage_code: :published,
13
+ type_code: :ogc,
14
+ abbr: ["OGC"],
15
+ name: "OGC Document",
16
+ harmonized_stages: [],
17
+ ),
18
+ ].freeze
19
+
20
+ def self.type
21
+ { key: :ogc, web: :document, title: "OGC Document", short: "OGC" }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ogc
5
+ # Namespace for concrete OGC identifier types.
6
+ module Identifiers
7
+ autoload :Document, "#{__dir__}/identifiers/document"
8
+ end
9
+ end
10
+ end