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
@@ -2,15 +2,15 @@
2
2
 
3
3
  module Pubid
4
4
  module Etsi
5
- # Base class for all ETSI identifiers. Canonical name Pubid::Etsi::Identifier
6
- # (Identifiers::Base is a back-compat alias); every concrete ETSI identifier
7
- # descends from it.
5
+ # Base class for all ETSI identifiers. Canonical name Pubid::Etsi::Identifier;
6
+ # every concrete ETSI identifier descends from it.
8
7
  class Identifier < ::Pubid::Identifier
8
+ # Let Parslet::ParseFailed propagate on a bad reference (matching ISO), so
9
+ # relaton-cli's `rescue Parslet::ParseFailed` fetch handler catches it
10
+ # instead of a bare RuntimeError.
9
11
  def self.parse(identifier)
10
12
  parsed = Parser.parse(identifier)
11
13
  Builder.build(parsed)
12
- rescue Parslet::ParseFailed => e
13
- raise "Failed to parse ETSI identifier '#{identifier}': #{e.message}"
14
14
  end
15
15
 
16
16
  attribute :type, :string
@@ -31,12 +31,30 @@ module Pubid
31
31
  version == other.version &&
32
32
  date == other.date
33
33
  end
34
- end
35
34
 
36
- module Identifiers
37
- # Backward-compatible alias: ETSI's base class used to be
38
- # Pubid::Etsi::Identifiers::Base. It is now Pubid::Etsi::Identifier.
39
- Base = Pubid::Etsi::Identifier
35
+ private
36
+
37
+ # ETSI keeps the number and part together inside one Code component
38
+ # (unlike ISO's separate `part` attribute), so a top-level exclude(:part)
39
+ # can't reach the part. Handle it during the nested-exclusion pass: when
40
+ # :part/:parts is excluded, return a copy of the Code with its parts
41
+ # cleared while keeping the number/minor. This propagates into supplement
42
+ # wrappers too, because the base #exclude recurses through here with the
43
+ # original args. It lets a part-less reference match all parts via
44
+ # matches?(ignore: [..., :part]).
45
+ def exclude_from_nested(value, args)
46
+ part_keys = args & %i[part parts]
47
+ if value.is_a?(Pubid::Etsi::Components::Code) && !part_keys.empty?
48
+ return Pubid::Etsi::Components::Code.new(
49
+ number: value.number,
50
+ minor: value.minor,
51
+ parts: [],
52
+ )
53
+ end
54
+
55
+ super
56
+ end
40
57
  end
58
+
41
59
  end
42
60
  end
@@ -4,15 +4,139 @@ module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
6
  # Single class for all ETSI standard types
7
- # Type is passed as parameter: EN, ES, EG, TS, ETR, ETS, I-ETS, TBR, TCRTR, NET, GR, GS, SR, TR, GTS
7
+ # Type is passed as parameter: EN, ES, EG, TS, ETR, ETS, I-ETS, TBR,
8
+ # TCRTR, NET, GR, GS, SR, TR, GTS
8
9
  # Format: ETSI TYPE CODE VERSION (DATE)
9
10
  # Examples:
10
11
  # ETSI GS ZSM 012 V1.1.1 (2022-12)
11
12
  # ETSI GR ZSM 009-3 V1.1.1 (2023-08)
12
13
  # ETSI GTS GSM 02.01 V5.5.0 (1999-01)
13
- class EtsiStandard < Base
14
- # Type is stored in @type attribute from Base
15
- # All rendering handled by Base class
14
+ class EtsiStandard < Identifier
15
+ # Type is stored in @type attribute from Identifier
16
+ # All rendering handled by Identifier class
17
+
18
+ # Compact serialization (mirrors ISO/JCGM/OIML): the Code component
19
+ # collapses to a bare `number` scalar (plus a `parts` array and, rarely,
20
+ # a `minor` scalar); Version flattens to a scalar `version` string with
21
+ # an `is_edition` boolean flag (omitted when false); Date flattens to
22
+ # top-level year/month/day. The constant `publisher` ("ETSI") is
23
+ # intentionally NOT mapped — it is reconstructed on load from its
24
+ # attribute default, keeping the hash compact.
25
+ #
26
+ # This block lives on EtsiStandard (a leaf) rather than the shared Identifier:
27
+ # SupplementIdentifier is a sibling that DELEGATES type/code/version and
28
+ # date to its inner `base`, so a block on Identifier would be inherited-and-
29
+ # merged by the supplement and re-emit every delegated field at the top.
30
+ key_value do
31
+ map "_type", to: :_type
32
+ map "type", to: :type
33
+ map "number", with: { to: :number_to_kv, from: :number_from_kv }
34
+ map "parts", with: { to: :parts_to_kv, from: :parts_from_kv }
35
+ map "minor", with: { to: :minor_to_kv, from: :minor_from_kv }
36
+ map "version", with: { to: :version_to_kv, from: :version_from_kv }
37
+ map "is_edition", with: { to: :edition_to_kv, from: :edition_from_kv }
38
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
39
+ map "month", with: { to: :month_to_kv, from: :month_from_kv }
40
+ map "day", with: { to: :day_to_kv, from: :day_from_kv }
41
+ end
42
+
43
+ # --- Code component flattened to bare number / parts / minor ---
44
+ def number_to_kv(model, doc)
45
+ emit_kv(doc, "number", model.code&.number)
46
+ end
47
+
48
+ def number_from_kv(model, value)
49
+ code_for(model).number = value.to_s
50
+ end
51
+
52
+ def minor_to_kv(model, doc)
53
+ emit_kv(doc, "minor", model.code&.minor)
54
+ end
55
+
56
+ def minor_from_kv(model, value)
57
+ code_for(model).minor = value.to_s
58
+ end
59
+
60
+ def parts_to_kv(model, doc)
61
+ parts = model.code&.parts
62
+ return if parts.nil? || parts.empty?
63
+
64
+ doc.add_child(
65
+ Lutaml::KeyValue::DataModel::Element.new(
66
+ "parts", parts.map(&:to_s)
67
+ ),
68
+ )
69
+ end
70
+
71
+ def parts_from_kv(model, value)
72
+ code_for(model).parts = Array(value).map(&:to_s)
73
+ end
74
+
75
+ # --- Version flattened to scalar version + is_edition flag ---
76
+ def version_to_kv(model, doc)
77
+ emit_kv(doc, "version", model.version&.version)
78
+ end
79
+
80
+ def version_from_kv(model, value)
81
+ version_for(model).version = value.to_s
82
+ end
83
+
84
+ def edition_to_kv(model, doc)
85
+ return unless model.version&.is_edition
86
+
87
+ doc.add_child(
88
+ Lutaml::KeyValue::DataModel::Element.new("is_edition", true),
89
+ )
90
+ end
91
+
92
+ def edition_from_kv(model, value)
93
+ version_for(model).is_edition = value
94
+ end
95
+
96
+ # --- Date flattened to top-level year/month/day scalars ---
97
+ def year_to_kv(model, doc)
98
+ emit_kv(doc, "year", model.date&.year)
99
+ end
100
+
101
+ def month_to_kv(model, doc)
102
+ emit_kv(doc, "month", model.date&.month)
103
+ end
104
+
105
+ def day_to_kv(model, doc)
106
+ emit_kv(doc, "day", model.date&.day)
107
+ end
108
+
109
+ def year_from_kv(model, value)
110
+ date_for(model).year = value.to_s
111
+ end
112
+
113
+ def month_from_kv(model, value)
114
+ date_for(model).month = value.to_s
115
+ end
116
+
117
+ def day_from_kv(model, value)
118
+ date_for(model).day = value.to_s
119
+ end
120
+
121
+ def emit_kv(doc, key, value)
122
+ return if value.nil? || value.to_s.empty?
123
+
124
+ doc.add_child(
125
+ Lutaml::KeyValue::DataModel::Element.new(key, value.to_s),
126
+ )
127
+ end
128
+
129
+ def code_for(model)
130
+ model.code ||= Pubid::Etsi::Components::Code.new
131
+ end
132
+
133
+ def version_for(model)
134
+ model.version ||= Pubid::Etsi::Components::Version.new
135
+ end
136
+
137
+ def date_for(model)
138
+ model.date ||= Pubid::Components::Date.new
139
+ end
16
140
  end
17
141
  end
18
142
  end
@@ -3,11 +3,43 @@
3
3
  module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
- # Base class for ETSI supplements (Amendment, Corrigendum)
7
- class SupplementIdentifier < Base
8
- attribute :base, Pubid::Etsi::Identifiers::Base
6
+ # Identifier class for ETSI supplements (Amendment, Corrigendum)
7
+ class SupplementIdentifier < Identifier
8
+ attribute :base, Pubid::Etsi::Identifier
9
9
  attribute :number, :integer
10
10
 
11
+ # Compact serialization: a supplement carries only its own ordinal
12
+ # `number` (A1 -> 1) and the nested base standard under the compact key
13
+ # `base`. type/code/version/date are delegated to `base` (methods below)
14
+ # and NOT re-emitted here, so the old redundant duplication is gone.
15
+ # This block is inherited unchanged by Amendment/Corrigendum.
16
+ key_value do
17
+ map "_type", to: :_type
18
+ map "number", to: :number
19
+ map "base", with: { to: :base_to_kv, from: :base_from_kv }
20
+ end
21
+
22
+ # Serialize the base via its own to_hash so it collapses to the compact
23
+ # EtsiStandard shape.
24
+ def base_to_kv(model, doc)
25
+ return unless model.base
26
+
27
+ doc.add_child(
28
+ Lutaml::KeyValue::DataModel::Element.new(
29
+ "base", model.base.to_hash
30
+ ),
31
+ )
32
+ end
33
+
34
+ # Re-dispatch through the flavor base so `_type` resolves to the
35
+ # concrete EtsiStandard; a bare polymorphic cast would rebuild a plain
36
+ # Identifier and lose the subclass (and its custom mappings). Mirrors JCGM.
37
+ def base_from_kv(model, value)
38
+ return unless value
39
+
40
+ model.base = Pubid::Etsi::Identifier.from_hash(value)
41
+ end
42
+
11
43
  # Inherit attributes from base
12
44
  def type
13
45
  base.type
@@ -4,7 +4,6 @@ module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
6
  autoload :Amendment, "#{__dir__}/identifiers/amendment"
7
- autoload :Base, "#{__dir__}/identifiers/base"
8
7
  autoload :Corrigendum, "#{__dir__}/identifiers/corrigendum"
9
8
  autoload :EtsiStandard, "#{__dir__}/identifiers/etsi_standard"
10
9
  autoload :SupplementIdentifier,
@@ -114,13 +114,19 @@ module Pubid
114
114
  end
115
115
 
116
116
  # Main identifier
117
+ #
118
+ # The mandatory core is `etsi_prefix type number` (+ optional
119
+ # minor/parts/supplements), mirroring ISO. The version/edition and date
120
+ # suffixes are optional so a partial reference (e.g. "ETSI GS ZSM 012")
121
+ # parses with version/date left nil. Each `.maybe` guards its own leading
122
+ # space so no trailing space is demanded when the suffix is absent.
117
123
  rule(:identifier) do
118
124
  etsi_prefix >>
119
125
  type >> space >>
120
126
  number >> minor.maybe >> parts >>
121
127
  supplements.maybe >>
122
- space >> version_or_edition >>
123
- space >> date_part
128
+ (space >> version_or_edition).maybe >>
129
+ (space >> date_part).maybe
124
130
  end
125
131
 
126
132
  rule(:root) { identifier }
@@ -27,7 +27,10 @@ module Pubid
27
27
 
28
28
  def render_base(id)
29
29
  result = "#{id.publisher} #{id.type} #{id.code}"
30
- result += " #{id.version} (#{id.date.render})"
30
+ # version/date are optional on partial references; append each only when
31
+ # present so a partial id renders without a stray " V… ()" suffix.
32
+ result += " #{id.version}" if id.version
33
+ result += " (#{id.date.render})" if id.date
31
34
  result
32
35
  end
33
36
 
@@ -35,7 +38,10 @@ module Pubid
35
38
  supplement_notations = id.collect_supplement_notations(id, [])
36
39
  actual_base = id.find_actual_base(id.base)
37
40
  code_with_supplements = "#{actual_base.code}#{supplement_notations.join}"
38
- "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements} #{actual_base.version} (#{actual_base.date.render})"
41
+ result = "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements}"
42
+ result += " #{actual_base.version}" if actual_base.version
43
+ result += " (#{actual_base.date.render})" if actual_base.date
44
+ result
39
45
  end
40
46
  end
41
47
  end
data/lib/pubid/etsi.rb CHANGED
@@ -13,7 +13,7 @@ module Pubid
13
13
 
14
14
  autoload :Builder, "#{__dir__}/etsi/builder"
15
15
  autoload :Components, "#{__dir__}/etsi/components"
16
- autoload :Identifier, "#{__dir__}/etsi/identifier"
16
+ autoload :Identifier, "#{__dir__}/etsi/identifiers/base"
17
17
  autoload :Identifiers, "#{__dir__}/etsi/identifiers"
18
18
  autoload :Parser, "#{__dir__}/etsi/parser"
19
19
  autoload :Renderer, "#{__dir__}/etsi/renderer"
@@ -25,8 +25,8 @@ module Pubid
25
25
  end
26
26
 
27
27
  # Per-flavor format registry: inherits global formats, overrides :human
28
- Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
29
- Identifiers::Base.format_registry.register(:human, renderer: Etsi::Renderer)
28
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
29
+ Identifier.format_registry.register(:human, renderer: Etsi::Renderer)
30
30
 
31
31
  # Auto-discover all identifier types from the Identifiers namespace
32
32
  # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
@@ -34,9 +34,9 @@ module Pubid
34
34
  @identifier_types ||= Identifiers.constants
35
35
  .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
36
36
  .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
37
- # Exclude the flavor base itself by identity (Identifiers::Base is now an
37
+ # Exclude the flavor base itself by identity (Identifier is now an
38
38
  # alias for Pubid::Etsi::Identifier, so name-based matching misses it).
39
- .reject { |c| c == Identifiers::Base }
39
+ .reject { |c| c == Identifier }
40
40
  end
41
41
 
42
42
  # Build typed stage index from identifier types
@@ -9,7 +9,8 @@ module Pubid
9
9
  class Exporter
10
10
  FLAVORS = %i[
11
11
  iso iec ieee nist bsi itu cen_cenelec etsi ansi astm ashrae asme
12
- ccsds cie csa jis jcgm oiml idf api amca plateau sae
12
+ ccsds cie csa ecma jis jcgm oiml idf api amca plateau sae ogc ietf tgpp w3c xsf
13
+ bipm iana oasis calconnect
13
14
  ].freeze
14
15
 
15
16
  # Export all flavors to a hash suitable for JSON serialization.
@@ -78,10 +78,25 @@ module Pubid
78
78
  # Scan Identifiers namespace for all Pubid::Identifier subclasses,
79
79
  # excluding structural base classes.
80
80
  def discover_from_namespace(mod)
81
- return [] unless mod.const_defined?(:Identifiers)
81
+ if mod.const_defined?(:Identifiers)
82
+ classes = collect_identifier_classes(mod.const_get(:Identifiers))
83
+ return classes unless classes.empty?
84
+ end
85
+
86
+ # Single-class flavors (e.g. SAE) expose no concrete types under
87
+ # Identifiers — the flavor's own Identifier class IS the sole document
88
+ # type (previously discovered via the removed Identifiers::Base alias).
89
+ Array(single_class_flavor_type(mod))
90
+ end
91
+
92
+ # The flavor's own `Identifier` class when it is a concrete
93
+ # Pubid::Identifier subclass, else nil (used as the sole type for
94
+ # single-class flavors with an empty Identifiers namespace).
95
+ def single_class_flavor_type(mod)
96
+ return unless mod.const_defined?(:Identifier)
82
97
 
83
- idents_mod = mod.const_get(:Identifiers)
84
- collect_identifier_classes(idents_mod)
98
+ ident = mod.const_get(:Identifier)
99
+ ident if ident.is_a?(Class) && ident < Pubid::Identifier
85
100
  end
86
101
 
87
102
  # Recursively collect all Pubid::Identifier subclasses from a module,
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ # Builds a Pubid::Gb::Identifier from a parse tree.
6
+ #
7
+ # The parser captures the publisher code verbatim (which may already
8
+ # include the "/T" or "/Z" suffix). The builder normalizes: if the
9
+ # suffix is in the publisher_code string, it's split out into the
10
+ # separate +mandate+ attribute so the renderer can recompose either
11
+ # the inline or split form.
12
+ class Builder
13
+ def self.build(parsed_data)
14
+ new.build(parsed_data)
15
+ end
16
+
17
+ def build(data)
18
+ publisher_code, mandate = split_mandate(data[:publisher_code].to_s)
19
+
20
+ mandate ||= data[:mandate]&.to_s
21
+
22
+ Identifiers::Standard.new(
23
+ publisher_code: publisher_code,
24
+ mandate: mandate,
25
+ number: data[:number].to_s,
26
+ part: data[:part]&.to_s,
27
+ date: data[:year] ? ::Pubid::Components::Date.new(year: data[:year].to_s) : nil,
28
+ all_parts: !data[:all_parts].to_s.empty?,
29
+ )
30
+ end
31
+
32
+ private
33
+
34
+ # If the publisher code carries an inline /T or /Z suffix, split it off
35
+ # and return the cleaned code + extracted mandate.
36
+ def split_mandate(code)
37
+ if code =~ %r{\A(.*?)/(T|Z)\z}
38
+ [Regexp.last_match(1), Regexp.last_match(2)]
39
+ else
40
+ [code, nil]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ # Base class for every Chinese Standard identifier AND the flavor's
6
+ # parse/create entry point. Concrete types under Pubid::Gb::Identifiers
7
+ # descend from this class, so a parsed GB id is always an instance of
8
+ # Pubid::Gb::Identifier.
9
+ class Identifier < ::Pubid::Identifier
10
+ # The issuing body code as printed, e.g. "GB", "JB", "T/GZAEPI".
11
+ # Always non-empty for a valid identifier.
12
+ attribute :publisher_code, :string
13
+
14
+ # Mandate category: "T" (recommended), "Z" (guideline), or nil
15
+ # (mandatory). Carried after the "/" in the printed form.
16
+ attribute :mandate, :string
17
+
18
+ # Document number (digits, possibly dotted with part). Required.
19
+ # Examples: "20223", "5606.1", "001".
20
+ attribute :number, :string
21
+
22
+ # Optional part. Captured separately from #number when the input
23
+ # uses the dotted form (e.g. "5606.1" => number "5606", part "1").
24
+ attribute :part, :string
25
+
26
+ # All-parts flag — true for "GB/T 5606 (all parts)" forms.
27
+ attribute :all_parts, :boolean, default: -> { false }
28
+
29
+ # Polymorphic type map for lutaml key_value (de)serialization.
30
+ GB_TYPE_MAP = {
31
+ "pubid:gb:standard" => "Pubid::Gb::Identifiers::Standard",
32
+ }.freeze
33
+
34
+ key_value do
35
+ map "_type", to: :_type, polymorphic_map: GB_TYPE_MAP
36
+ map "publisher_code", to: :publisher_code
37
+ map "mandate", to: :mandate
38
+ map "number", to: :number
39
+ map "part", to: :part
40
+ map "all_parts", to: :all_parts, render_default: false
41
+ end
42
+
43
+ PUBLISHER = "CN"
44
+
45
+ def to_s(**opts)
46
+ render(format: :human, **opts)
47
+ end
48
+
49
+ # Parse a Chinese Standard identifier string.
50
+ # @param identifier [String]
51
+ # @return [Pubid::Gb::Identifier]
52
+ def self.parse(identifier)
53
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
54
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
55
+ end
56
+
57
+ parsed = Parser.parse(identifier)
58
+ Builder.build(parsed)
59
+ rescue Parslet::ParseFailed => e
60
+ raise "Failed to parse Chinese Standard identifier '#{identifier}': #{e.message}"
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ module Identifiers
6
+ # The default Chinese Standard identifier type. The class name yields
7
+ # the polymorphic _type tag "pubid:gb:standard".
8
+ #
9
+ # Examples:
10
+ # GB/T 20223-2006
11
+ # GB/T 5606.1-2004
12
+ # GB/T 5606 (all parts)
13
+ # JB/T 13368-2018
14
+ # T/GZAEPI 001—2018
15
+ class Standard < Identifier
16
+ TYPED_STAGES = [
17
+ Pubid::Components::TypedStage.new(
18
+ code: :pubgb,
19
+ stage_code: :published,
20
+ type_code: :gb,
21
+ abbr: ["GB"],
22
+ name: "Chinese Standard",
23
+ harmonized_stages: %w[60.00 60.60],
24
+ ),
25
+ ].freeze
26
+
27
+ def self.type
28
+ { key: :gb, web: :chinese_standard, title: "Chinese Standard",
29
+ short: "GB" }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ module Identifiers
6
+ autoload :Standard, "#{__dir__}/identifiers/standard"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Gb
7
+ # Parslet grammar for Chinese Standard identifiers.
8
+ #
9
+ # Accepts the canonical printed form
10
+ #
11
+ # {PUBLISHER}[/{TYPE}] {NUMBER}[.{PART}][-|—{YEAR}] [(all parts)]
12
+ #
13
+ # PUBLISHER is one of the leading tokens from PREFIXES (GB, GB/T, JB,
14
+ # T/GZAEPI, ...). TYPE is T (recommended), Z (guideline), or omitted.
15
+ # YEAR is 4 digits, separated by either ASCII dash or em-dash (Chinese
16
+ # typography uses the em-dash form).
17
+ class Parser < Parslet::Parser
18
+ rule(:space) { str(" ") }
19
+ rule(:dot) { str(".") }
20
+ rule(:dash) { str("-") | str("—") }
21
+ rule(:digits) { match("[0-9]").repeat(1) }
22
+
23
+ # Publisher token: national/industry codes (1-3 letters, optionally
24
+ # followed by /T or /Z) OR social-group form "T/{ACRONYM}".
25
+ rule(:publisher_code) do
26
+ # Social-group form: "T/" then 2+ uppercase letters/digits.
27
+ (str("T/") >> match("[A-Z0-9]").repeat(1)).as(:publisher_code) |
28
+ # Standard form: 1-3 letters, optional slash-T-or-Z.
29
+ (match("[A-Z]").repeat(1, 3) >>
30
+ (str("/T") | str("/Z")).maybe).as(:publisher_code)
31
+ end
32
+
33
+ # Mandate category captured separately when the publisher token didn't
34
+ # already include it. Allows "GB/T" (inline) and "GB" + " T" (separate)
35
+ # to both parse.
36
+ rule(:mandate_suffix) do
37
+ (str("/") >> (str("T") | str("Z")).as(:mandate)).maybe
38
+ end
39
+
40
+ rule(:number) { digits.as(:number) }
41
+ rule(:part) { dot >> digits.as(:part) }
42
+ rule(:year) { (dash >> match("[0-9]").repeat(4, 4).as(:year)).maybe }
43
+ rule(:all_parts_flag) do
44
+ (space >> str("(") >> str("all parts") >> str(")")).as(:all_parts)
45
+ end
46
+
47
+ rule(:identifier) do
48
+ publisher_code >>
49
+ space >>
50
+ number >>
51
+ part.maybe >>
52
+ year >>
53
+ all_parts_flag.maybe
54
+ end
55
+
56
+ rule(:root) { identifier }
57
+
58
+ def self.parse(input)
59
+ new.parse(input)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ # Human-readable renderer for Chinese Standard identifiers.
6
+ #
7
+ # Produces the canonical printed form:
8
+ # "GB/T 20223-2006"
9
+ # "GB/T 5606.1-2004"
10
+ # "GB/T 5606 (all parts)"
11
+ # "T/GZAEPI 001—2018" (social-group form, em-dash year)
12
+ class Renderer < ::Pubid::Renderers::Base
13
+ def render(**_opts)
14
+ parts = [publisher_portion, " #{number_portion}"]
15
+ parts << " (all parts)" if @id.all_parts
16
+ parts.join
17
+ end
18
+
19
+ private
20
+
21
+ def publisher_portion
22
+ code = @id.publisher_code.to_s
23
+ code += "/#{@id.mandate}" if @id.mandate && !@id.publisher_code.include?("/")
24
+ code
25
+ end
26
+
27
+ def number_portion
28
+ result = @id.number.to_s
29
+ result += ".#{@id.part}" if @id.part
30
+ result += "-#{@id.year}" if @id.year
31
+ result
32
+ end
33
+ end
34
+ end
35
+ end