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
@@ -4,7 +4,7 @@ module Pubid
4
4
  module Ieee
5
5
  # Pre-parser for IEEE identifiers.
6
6
  #
7
- # Owns all regex/scan/dispatch logic that used to live on Identifiers::Base.parse.
7
+ # Owns all regex/scan/dispatch logic that used to live on Identifier.parse.
8
8
  # Base.parse becomes a thin orchestrator that asks PreParser for a decision
9
9
  # and then routes to the right builder.
10
10
  module PreParser
@@ -17,8 +17,52 @@ module Pubid
17
17
  # identifier's own publisher/code/relationship helpers.
18
18
  class Renderer < ::Pubid::Renderers::Base
19
19
  def render(context: nil, **opts)
20
- id = @id
20
+ # IEEE attaches the trademark mark to the document number, before the
21
+ # year and every suffix ("IEEE Std 802.3®-2018"), so the mark is
22
+ # emitted by whichever method renders the number rather than appended
23
+ # to the finished string. A renderer instance is built per render call
24
+ # (Pubid::Identifier#render), so the flag is safe as instance state.
25
+ @trademark = opts[:trademark]
26
+
27
+ render_id(@id)
28
+ end
29
+
30
+ private
31
+
32
+ # Trademark mark for a document number, or "" when the flag is off.
33
+ # @param number [String, nil] bare document number
34
+ # @param prefix [String, nil] letter series of the code
35
+ # @param publishers [Array<String>] printed publisher tokens — the ®
36
+ # series belongs to IEEE, not to another body numbering a document 802
37
+ def mark(number, prefix = nil, publishers: nil)
38
+ return "" unless @trademark
21
39
 
40
+ Pubid::Ieee.trademark_symbol_for(number, prefix, publishers: publishers)
41
+ end
42
+
43
+ # The publisher tokens an identifier prints, for the ® decision.
44
+ def publishers_of(id)
45
+ return id.publishers if id.respond_to?(:publishers) && id.publishers
46
+
47
+ copublishers = id.copublisher if id.respond_to?(:copublisher)
48
+ [id.publisher, *copublishers].compact
49
+ end
50
+
51
+ # Compose a child identifier, propagating the trademark flag only when it
52
+ # is safe. A foreign (non-IEEE) leaf may not accept the `trademark:`
53
+ # keyword at all — Pubid::Nist's `to_s(format = :short)` would silently
54
+ # swallow it as a positional Hash, and Pubid::Iso's would raise — and an
55
+ # adopted or parenthetical child is not the IEEE document being marked.
56
+ def child_to_s(child, **opts)
57
+ return child.to_s(**opts) unless @trademark &&
58
+ child.is_a?(Pubid::Ieee::Identifier)
59
+
60
+ child.to_s(**opts, trademark: true)
61
+ end
62
+
63
+ # Dispatch to the type-specific renderer, returning the composed string
64
+ # (each branch inserts the trademark mark at its own number boundary).
65
+ def render_id(id)
22
66
  case id
23
67
  when Identifiers::DualPublished
24
68
  render_dual_published(id)
@@ -28,6 +72,8 @@ module Pubid
28
72
  render_adopted_standard(id)
29
73
  when Identifiers::RedlinedStandard
30
74
  render_redlined_standard(id)
75
+ when Identifiers::Amendment
76
+ render_amendment(id)
31
77
  when Identifiers::Corrigendum
32
78
  render_corrigendum(id)
33
79
  when Identifiers::InterpretationIdentifier
@@ -45,14 +91,12 @@ module Pubid
45
91
  when Identifiers::SiStandard
46
92
  render_si_standard(id)
47
93
  when Identifiers::JointDevelopment
48
- id.to_s
94
+ child_to_s(id)
49
95
  else
50
96
  render_base(id)
51
97
  end
52
98
  end
53
99
 
54
- private
55
-
56
100
  # ------------------------------------------------------------------
57
101
  # Base IEEE identifier rendering
58
102
  # ------------------------------------------------------------------
@@ -70,12 +114,18 @@ module Pubid
70
114
  # Draft status
71
115
  parts << id.draft_status if id.draft_status
72
116
 
73
- # Type - only render for IEEE/AIEE publishers, and only for non-projects
117
+ # Type - only render for IEEE/AIEE publishers, and only for non-projects.
118
+ # An unapproved draft is not yet a standard, so per IEEE guidance the
119
+ # "Std" token is dropped from the type when draft_status is "Unapproved"
120
+ # (e.g. "Draft Std" -> "Draft", "Std" -> "").
74
121
  should_render_type = id.publisher&.match?(/^(IEEE|AIEE)/)
75
122
 
76
123
  if should_render_type && !id.typed_stage&.project_status && id.type && !id.type.to_s.strip.empty? && id.type != "P"
77
124
  type_str = id.type.dup
78
125
  type_str = type_str.sub(/^P/, "") if type_str.start_with?("P")
126
+ if id.draft_status.to_s.match?(/unapproved/i)
127
+ type_str = type_str.gsub(/\bStd\b/i, "").squeeze(" ").strip
128
+ end
79
129
  parts << type_str unless type_str.strip.empty?
80
130
  end
81
131
 
@@ -88,9 +138,19 @@ module Pubid
88
138
  result = "P#{result}"
89
139
  end
90
140
 
141
+ # Trademark mark — right after the number and its parts, before the
142
+ # year, the revision, the draft and every other suffix.
143
+ result += mark(id.code_obj.number, id.code_obj.prefix,
144
+ publishers: publishers_of(id))
145
+
91
146
  # Only attach year to code if there's no edition, no month, and no draft
92
147
  result += "-#{id.year}" if id.year && !id.draft_obj && !id.edition && !id.month
93
148
 
149
+ # Append the numbered/lettered revision inline, in IEEE's native
150
+ # position — right after the code number and before the draft
151
+ # ("P802.16Rev2/D3"). Keeps a revision distinct from its base standard.
152
+ result += "Rev#{id.revision}" if id.revision
153
+
94
154
  # Append draft to code - with or without space based on original format
95
155
  if id.draft_obj
96
156
  result += id.space_before_draft ? " #{id.draft_obj}" : id.draft_obj.to_s
@@ -99,11 +159,9 @@ module Pubid
99
159
  # Append interpretation notation (/INT)
100
160
  result += "/INT" if id.interpretation
101
161
 
102
- # Append conformance notation (/ConformanceNN-YYYY)
103
- if id.conf_number
104
- result += "/Conformance#{id.conf_number}"
105
- result += "-#{id.conf_year}" if id.conf_year
106
- end
162
+ # Conformance is always built as a ConformanceIdentifier wrapper
163
+ # (render_conformance), never inline on a base standard — the base no
164
+ # longer carries a conf_number attribute.
107
165
 
108
166
  # Append ASHRAE joint publication (/ASHRAE Guideline NN-YYYY)
109
167
  if id.ashrae_number
@@ -138,31 +196,30 @@ module Pubid
138
196
  result += ", #{id.month}"
139
197
  result += " #{id.day}" if id.day
140
198
  if id.year && !id.edition
141
- result += ", #{id.year}"
199
+ result += " #{id.year}"
142
200
  end
143
201
  end
144
202
 
145
- # Add parenthetical content if present
203
+ # Bounded parenthetical markers only. The unbounded relationship/
204
+ # amendment narrative (relationships, revision_of, amendment_to,
205
+ # adoption, note) is deliberately NOT rendered here: an
206
+ # "as amended by …" list can run 300+ chars, and an identifier's to_s
207
+ # is used by consumers (relaton) as a document number and filename. The
208
+ # narrative is preserved on the runtime accessors (id.relationships
209
+ # etc.), just not embedded in the identifier string.
146
210
  parentheticals = []
147
211
 
212
+ # Reaffirmation year — a bounded status marker.
148
213
  reaff = id.reaffirmed
149
- if reaff && !reaff.to_s.strip.empty?
150
- parentheticals << "(R#{reaff})"
151
- end
214
+ parentheticals << "(R#{reaff})" if reaff && !reaff.to_s.strip.empty?
152
215
 
216
+ # The catch-all parenthetical is a bounded, printed identity token, not
217
+ # relationship prose (e.g. the "S-135 (IPCEA P46-426)" co-designation).
218
+ # Long amendment narratives match the structural relationship grammar
219
+ # and land in `relationships`, never in this catch-all, so it stays
220
+ # bounded.
153
221
  if id.parenthetical_content
154
222
  parentheticals << "(#{id.parenthetical_content})"
155
- elsif id.relationships && !id.relationships.empty?
156
- relationship_str = id.relationships.join(" / ")
157
- parentheticals << "(#{relationship_str})"
158
- elsif id.revision_of
159
- parentheticals << "(Revision of IEEE Std #{id.revision_of})"
160
- elsif id.amendment_to
161
- parentheticals << "(Amendment to IEEE Std #{id.amendment_to})"
162
- elsif id.adoption
163
- parentheticals << "(Adoption of #{id.adoption})"
164
- elsif id.note && !id.note.to_s.strip.empty?
165
- parentheticals << "(#{id.note})"
166
223
  end
167
224
 
168
225
  result += " #{parentheticals.join(' ')}" unless parentheticals.empty?
@@ -181,15 +238,19 @@ module Pubid
181
238
  # ------------------------------------------------------------------
182
239
 
183
240
  def render_dual_published(id)
184
- "#{id.first_identifier} and #{id.second_identifier}"
241
+ "#{child_to_s(id.first_identifier)} and " \
242
+ "#{child_to_s(id.second_identifier)}"
185
243
  end
186
244
 
187
245
  def render_dual_identifier(id)
188
- "#{id.first_identifier} and #{id.second_identifier}"
246
+ "#{child_to_s(id.first_identifier)} and " \
247
+ "#{child_to_s(id.second_identifier)}"
189
248
  end
190
249
 
191
250
  def render_adopted_standard(id)
192
- result = id.ieee_identifier.to_s
251
+ # Only the IEEE designation is marked; the adopted identifiers are
252
+ # other bodies' documents (and may be foreign pubid objects).
253
+ result = child_to_s(id.ieee_identifier)
193
254
  if id.adopted_identifiers && !id.adopted_identifiers.empty?
194
255
  adopted_strs = id.adopted_identifiers.map(&:to_s)
195
256
  result += " (#{adopted_strs.join(' and ')})"
@@ -198,68 +259,97 @@ module Pubid
198
259
  end
199
260
 
200
261
  def render_redlined_standard(id)
201
- result = id.base_identifier.to_s
262
+ result = child_to_s(id.base)
263
+ # NOTE: currently unreachable — a redline is built as a flat
264
+ # `redline: true` on a plain Standard (see the redline invariant in
265
+ # CLAUDE.md), so determine_identifier_class never routes here. Kept for
266
+ # completeness; if this path is ever revived, note `revision_of` is a
267
+ # bounded single-id reference, unlike the unbounded relationship
268
+ # narrative that render_base deliberately drops.
202
269
  result += " (Revision of #{id.revision_of})" if id.revision_of
203
270
  result += " - Redline" if id.redline
204
271
  result
205
272
  end
206
273
 
207
274
  def render_corrigendum(id)
208
- return render_base(id) unless id.base_identifier
275
+ return render_base(id) unless id.base
209
276
 
210
- result = id.base_identifier.to_s
277
+ result = child_to_s(id.base)
211
278
  result += "/Cor"
212
- result += ". " if id.cor_number # Add period and space for formal format
213
- result += id.cor_number if id.cor_number
214
- result += "-#{id.cor_year}" if id.cor_year
279
+ result += ". " if id.number # Add period and space for formal format
280
+ result += id.number if id.number
281
+ result += "-#{id.year}" if id.year
282
+ result
283
+ end
284
+
285
+ def render_amendment(id)
286
+ return render_base(id) unless id.base
287
+
288
+ result = child_to_s(id.base)
289
+ result += "/Amd"
290
+ result += " #{id.number}" if id.number # canonical "/Amd 4-2020"
291
+ result += "-#{id.year}" if id.year
215
292
  result
216
293
  end
217
294
 
218
295
  def render_interpretation(id)
219
- return render_base(id) unless id.base_identifier
296
+ return render_base(id) unless id.base
220
297
 
221
- result = id.base_identifier.to_s
298
+ result = child_to_s(id.base)
222
299
  result += "/INT"
223
- result += "-#{id.int_year}" if id.int_year
300
+ result += "-#{id.year}" if id.year
224
301
  result
225
302
  end
226
303
 
227
304
  def render_conformance(id)
228
- return render_base(id) unless id.base_identifier
305
+ return render_base(id) unless id.base
229
306
 
230
- result = id.base_identifier.to_s
231
- result += "/Conformance#{id.conf_number}" if id.conf_number
232
- result += "-#{id.conf_year}" if id.conf_year
307
+ result = child_to_s(id.base)
308
+ result += "/Conformance#{id.number}" if id.number
309
+ result += "-#{id.year}" if id.year
233
310
  result
234
311
  end
235
312
 
236
313
  def render_multi_numbered(id)
237
- return id.primary_identifier.to_s unless id.secondary_identifier
314
+ return child_to_s(id.primary_identifier) unless id.secondary_identifier
315
+
316
+ # Co-equal designations: each carries its own mark, before its own
317
+ # suffixes, as IEEE prints them.
318
+ primary = child_to_s(id.primary_identifier)
319
+ secondary = child_to_s(id.secondary_identifier)
238
320
 
239
321
  secondary_code = id.secondary_identifier.code.to_s
240
322
  if secondary_code.start_with?("C") && secondary_code.match?(/^C\d+\./)
241
- "#{id.primary_identifier}/#{id.secondary_identifier}"
323
+ "#{primary}/#{secondary}"
242
324
  else
243
- "#{id.primary_identifier} and #{id.secondary_identifier}"
325
+ "#{primary} and #{secondary}"
244
326
  end
245
327
  end
246
328
 
247
329
  def render_parenthetical(id)
248
- result = id.base_identifier.to_s
330
+ # The mark belongs on the base; the parenthetical is a separate token.
331
+ result = child_to_s(id.base)
249
332
  result += " (#{id.parenthetical_identifier})" if id.parenthetical_identifier
250
333
  result
251
334
  end
252
335
 
253
336
  def render_csa_dual_published(id)
337
+ # csa_identifier is a Pubid::Csa object — never marked.
254
338
  csa_str = id.csa_identifier.to_s
255
339
  csa_str = "CSA #{csa_str}" unless csa_str.start_with?("CSA", "CAN/")
256
340
 
257
- "#{id.ieee_identifier}/#{csa_str}"
341
+ "#{child_to_s(id.ieee_identifier)}/#{csa_str}"
258
342
  end
259
343
 
260
344
  def render_iec_ieee_copublished(id)
261
345
  result = "IEC/IEEE"
262
- result += " #{id.copublished_number}" if id.copublished_number
346
+ # copublished_number glues the parts and the publication year onto the
347
+ # number, so the mark is spliced in by that single implementation
348
+ # rather than rebuilt here; with the flag off it is passed "".
349
+ if id.copublished_number
350
+ result += " #{id.copublished_number(mark(id.number,
351
+ publishers: %w[IEC IEEE]))}"
352
+ end
263
353
  result += id.draft_info if id.draft_info
264
354
  result += " IEC:#{id.iec_year}" if id.iec_year
265
355
  result += " #{id.date_info}" if id.date_info
@@ -279,8 +369,11 @@ module Pubid
279
369
  "SI"
280
370
  end
281
371
 
282
- # Code (number) with draft version for PSI
372
+ # Code (number) with draft version for PSI — the mark goes after the
373
+ # code, before the draft and the date.
283
374
  code_part = id.code.to_s
375
+ code_part += mark(id.code_obj&.number, id.code_obj&.prefix,
376
+ publishers: publishers_of(id))
284
377
  if id.draft_obj
285
378
  code_part += "/D#{id.draft_obj.version}"
286
379
  end
@@ -293,14 +386,18 @@ module Pubid
293
386
  parts << "-#{id.year}"
294
387
  end
295
388
 
296
- # Relationships (if present)
297
- result = parts.join(" ")
298
- if id.relationships && !id.relationships.empty?
299
- rel_strs = id.relationships.map(&:to_s)
300
- result += " (#{rel_strs.join(' / ')})"
301
- end
302
-
303
- result
389
+ # Join parts with spaces, but don't insert a space before parts
390
+ # that start with "-" or "," (e.g., "-2010", ", July 2014") so the
391
+ # SI form renders as "SI 10-2010" not "SI 10 -2010". The descriptive
392
+ # relationships narrative is deliberately kept out of to_s (see
393
+ # render_base); it stays reachable on id.relationships.
394
+ parts.each_with_object([]) do |part, acc|
395
+ if acc.empty? || part.to_s.start_with?("-", ",")
396
+ acc << part.to_s
397
+ else
398
+ acc << " " << part.to_s
399
+ end
400
+ end.join
304
401
  end
305
402
  end
306
403
  end
@@ -101,7 +101,7 @@ module Pubid
101
101
  ),
102
102
 
103
103
  Components::TypedStage.new(
104
- abbr: ["CD", "CD2", "CD3"],
104
+ abbr: ["CD", "CD1", "CD2", "CD3", "CD4"],
105
105
  stage_code: "committee_draft",
106
106
  type_code: "draft",
107
107
  ieee_draft_equivalent: "D2-D3",
@@ -110,6 +110,17 @@ module Pubid
110
110
  project_status: true,
111
111
  ),
112
112
 
113
+ # Committee Draft for Vote (IEC/ISO-led historical stage)
114
+ Components::TypedStage.new(
115
+ abbr: ["CDV"],
116
+ stage_code: "committee_draft_for_vote",
117
+ type_code: "draft",
118
+ ieee_draft_equivalent: "D2-D3",
119
+ iso_stage_equivalent: "CDV",
120
+ approval_status: "unapproved",
121
+ project_status: true,
122
+ ),
123
+
113
124
  Components::TypedStage.new(
114
125
  abbr: ["DIS"],
115
126
  stage_code: "draft_international_standard",
@@ -39,11 +39,9 @@ module Pubid
39
39
  parts << "int"
40
40
  end
41
41
 
42
- if special_type != "conformance" && identifier.conf_number
43
- conf = "conf.#{identifier.conf_number}"
44
- conf += "-#{identifier.conf_year}" if identifier.conf_year
45
- parts << conf
46
- end
42
+ # Conformance is always a ConformanceIdentifier wrapper (special_type
43
+ # "conformance"), never inline on a base standard — the base no longer
44
+ # carries a conf_number attribute, so there is no inline conf part.
47
45
 
48
46
  if identifier.ashrae_number
49
47
  ashrae = "ashrae.#{identifier.ashrae_number}"
data/lib/pubid/ieee.rb CHANGED
@@ -12,12 +12,13 @@ module Pubid
12
12
 
13
13
  autoload :Aiee, "#{__dir__}/ieee/aiee"
14
14
  autoload :Builder, "#{__dir__}/ieee/builder"
15
- autoload :Identifier, "#{__dir__}/ieee/identifier"
15
+ autoload :Identifier, "#{__dir__}/ieee/identifiers/base"
16
16
  autoload :Identifiers, "#{__dir__}/ieee/identifiers"
17
17
  autoload :Ire, "#{__dir__}/ieee/ire"
18
18
  autoload :Nesc, "#{__dir__}/ieee/nesc"
19
19
  autoload :Parser, "#{__dir__}/ieee/parser"
20
20
  autoload :PreParser, "#{__dir__}/ieee/pre_parser"
21
+ autoload :Compaction, "#{__dir__}/ieee/compaction"
21
22
  autoload :Renderer, "#{__dir__}/ieee/renderer"
22
23
  autoload :TypedStages, "#{__dir__}/ieee/typed_stages"
23
24
  autoload :UrnGenerator, "#{__dir__}/ieee/urn_generator"
@@ -31,6 +32,14 @@ module Pubid
31
32
  autoload :TypedStage, "#{__dir__}/ieee/components/typed_stage"
32
33
  end
33
34
 
35
+ # Document-number series carrying an IEEE registered trademark ("®").
36
+ # 8802 is the ISO/IEC co-published form of the 802 series.
37
+ REGISTERED_SERIES = %w[802 8802 2030].freeze
38
+
39
+ # The ISO/IEC adoption of IEEE 802: the number alone identifies the series,
40
+ # whatever publishers are printed.
41
+ ISO_ADOPTED_SERIES = "8802"
42
+
34
43
  class << self
35
44
  def parse(input)
36
45
  if input.length > Pubid::MAX_INPUT_LENGTH
@@ -40,6 +49,50 @@ module Pubid
40
49
  Identifier.parse(input)
41
50
  end
42
51
 
52
+ # True when the document number belongs to a registered-trademark series.
53
+ # A project number keeps its series identity, so a leading "P" is
54
+ # stripped. `prefix` is the code's letter series, which must be absent
55
+ # (or the bare project "P") — "C802.1" is a different series that merely
56
+ # starts with the same digits. `publishers` guards against claiming an
57
+ # IEEE registered mark for another body that happens to have numbered a
58
+ # document 802 or 2030 — "AIEE Std No. 802" predates the IEEE 802 series
59
+ # by two decades. It is optional: with no publishers given the number
60
+ # decides, which keeps the plain number lookup usable on its own.
61
+ # @param number [String, nil] bare document number ("802", "P802")
62
+ # @param prefix [String, nil] letter series of the code ("C" for C37.09)
63
+ # @param publishers [Array<String>, String, nil] printed publisher tokens
64
+ def registered_series?(number, prefix = nil, publishers: nil)
65
+ return false unless prefix.nil? || prefix.to_s.empty? ||
66
+ prefix.to_s == "P"
67
+
68
+ bare = number.to_s.delete_prefix("P")
69
+ return false unless REGISTERED_SERIES.include?(bare)
70
+ return true if bare == ISO_ADOPTED_SERIES || publishers.nil?
71
+
72
+ Array(publishers).any? { |p| p.to_s.split("/").include?("IEEE") }
73
+ end
74
+
75
+ # IEEE trademark symbol for a document number: ® for the registered
76
+ # series, ™ for everything else. This is the entry point render sites
77
+ # use, because they hold the identifier and so know its number — the
78
+ # symbol must not depend on where in the rendered string the mark lands.
79
+ def trademark_symbol_for(number, prefix = nil, publishers: nil)
80
+ if registered_series?(number, prefix, publishers: publishers)
81
+ "®"
82
+ else
83
+ "™"
84
+ end
85
+ end
86
+
87
+ # IEEE trademark symbol for a rendered identifier string. Kept for
88
+ # external callers only — every render site inside pubid passes the
89
+ # document number to #trademark_symbol_for instead, because the first
90
+ # numeric token of a rendered string is not reliably the document number
91
+ # (a NESC or IRE string starts with the publication year).
92
+ def trademark_symbol(rendered)
93
+ trademark_symbol_for(rendered.to_s[/(?<![0-9A-Za-z])P?(\d+)/, 1])
94
+ end
95
+
43
96
  # Auto-discover all identifier types from the Identifiers namespace
44
97
  # @return [Array<Class>] identifier classes that define a self.type Hash
45
98
  def identifier_types
@@ -101,5 +154,5 @@ end
101
154
  Pubid::Registry.register(:ieee, Pubid::Ieee)
102
155
 
103
156
  # Per-flavor format registry: inherits global formats, overrides :human
104
- Pubid::Ieee::Identifiers::Base.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
105
- Pubid::Ieee::Identifiers::Base.format_registry.register(:human, renderer: Pubid::Ieee::Renderer)
157
+ Pubid::Ieee::Identifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
158
+ Pubid::Ieee::Identifier.format_registry.register(:human, renderer: Pubid::Ieee::Renderer)
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ # Turns the Parser's parse tree into a concrete identifier object, choosing
6
+ # the class from which fields are present.
7
+ class Builder
8
+ SUBSERIES_CLASSES = {
9
+ "BCP" => "Bcp",
10
+ "STD" => "Std",
11
+ "FYI" => "Fyi",
12
+ }.freeze
13
+
14
+ def self.build(parsed_data)
15
+ new.build(parsed_data)
16
+ end
17
+
18
+ def build(data)
19
+ if data.key?(:draft_rest)
20
+ build_draft(data)
21
+ elsif data[:series]
22
+ build_subseries(data)
23
+ else
24
+ build_rfc(data)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def build_rfc(data)
31
+ Identifiers::Rfc.new(number: data[:number].to_s)
32
+ end
33
+
34
+ def build_subseries(data)
35
+ series = data[:series].to_s
36
+ klass = Identifiers.const_get(SUBSERIES_CLASSES.fetch(series))
37
+ klass.new(series: series, number: data[:number].to_s)
38
+ end
39
+
40
+ def build_draft(data)
41
+ full = "draft-#{data[:draft_rest]}"
42
+ name, version = split_draft_version(full)
43
+ Identifiers::InternetDraft.new(name: name, version: version)
44
+ end
45
+
46
+ # An Internet-Draft version is a trailing "-NN" of *exactly* two digits at
47
+ # the very end of the slug. A three-digit topic tail (e.g. "...-256") is
48
+ # NOT a version: there the char before the last two digits is itself a
49
+ # digit, not "-", so the guard below leaves it in the name. This also
50
+ # means a (non-existent in practice) revision >= 100 would be read as part
51
+ # of the name — IETF drafts are always two-digit-versioned, so that case
52
+ # never arises. Either way the printed string round-trips exactly.
53
+ def split_draft_version(full)
54
+ if full.length > 3 && full[-3] == "-" && full[-2..].match?(/\A\d\d\z/)
55
+ [full[0...-3], full[-2..]]
56
+ else
57
+ [full, nil]
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Pubid::Ietf::Identifier is the IETF base class and the flavor's parse entry
4
+ # point; its body lives in
5
+ # identifiers/base.rb (mirrors the AMCA layout).
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ # Base class for every IETF identifier AND the flavor's parse/create entry
6
+ # point (mirrors Pubid::Jis::Identifier). Concrete identifiers under
7
+ # Pubid::Ietf::Identifiers descend from this class, so a parsed IETF id is
8
+ # an instance of Pubid::Ietf::Identifier.
9
+ #
10
+ # All families are flat, supplement-free, and use plain string attributes:
11
+ # * Rfc -> number ("2119")
12
+ # * Bcp/Std/Fyi -> series ("BCP"/"STD"/"FYI") + number ("3")
13
+ # * InternetDraft -> name ("draft-giuliano-treedn") + optional version
14
+ class Identifier < ::Pubid::Identifier
15
+ # Numeric part of an RFC or sub-series id, kept as a string (no zero-pad
16
+ # in the printed form, so "2119" not "02119").
17
+ attribute :number, :string
18
+ # Sub-series token for BCP/STD/FYI ("BCP"/"STD"/"FYI"); nil otherwise.
19
+ attribute :series, :string
20
+ # Full Internet-Draft slug including the leading "draft-"; nil otherwise.
21
+ attribute :name, :string
22
+ # Internet-Draft version, a two-digit string preserving zero-pad ("02");
23
+ # nil for the unversioned "latest" sibling.
24
+ attribute :version, :string
25
+
26
+ # Polymorphic type map for lutaml::Model key_value (de)serialization: maps
27
+ # each subclass's polymorphic_name to its class name so a stored hash
28
+ # rebuilds the correct identifier type via the shared from_hash dispatch.
29
+ IETF_TYPE_MAP = {
30
+ "pubid:ietf:rfc" => "Pubid::Ietf::Identifiers::Rfc",
31
+ "pubid:ietf:bcp" => "Pubid::Ietf::Identifiers::Bcp",
32
+ "pubid:ietf:std" => "Pubid::Ietf::Identifiers::Std",
33
+ "pubid:ietf:fyi" => "Pubid::Ietf::Identifiers::Fyi",
34
+ "pubid:ietf:internet-draft" =>
35
+ "Pubid::Ietf::Identifiers::InternetDraft",
36
+ }.freeze
37
+
38
+ # Only these keys serialize; the inherited Pubid::Identifier attributes
39
+ # are intentionally dropped. nil-valued attributes are stripped by the
40
+ # base canonicalizer, so each family serializes just the keys it uses.
41
+ key_value do
42
+ map "_type", to: :_type, polymorphic_map: IETF_TYPE_MAP
43
+ map "number", to: :number
44
+ map "series", to: :series
45
+ map "name", to: :name
46
+ map "version", to: :version
47
+ end
48
+
49
+ # Publisher is always "IETF". 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 = "IETF"
53
+
54
+ # Basic string representation. Delegates to the flavor renderer.
55
+ def to_s(**opts)
56
+ render(format: :human, **opts)
57
+ end
58
+
59
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier; the
60
+ # IETF_TYPE_MAP above serves as its key_value polymorphic_map.
61
+
62
+ # Parse an IETF identifier string into the appropriate identifier object.
63
+ # @param identifier [String] the IETF identifier string to parse
64
+ # @return [Identifier] the concrete identifier object
65
+ # @raise [RuntimeError] if parsing fails
66
+ def self.parse(identifier)
67
+ parsed = Parser.parse(identifier)
68
+ Builder.build(parsed)
69
+ rescue Parslet::ParseFailed => e
70
+ raise "Failed to parse IETF identifier '#{identifier}': #{e.message}"
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ # A BCP (Best Current Practice) sub-series id, e.g. "BCP 3".
7
+ class Bcp < Identifier
8
+ TYPED_STAGES = [
9
+ Pubid::Components::TypedStage.new(
10
+ code: :bcp,
11
+ stage_code: :published,
12
+ type_code: :bcp,
13
+ abbr: ["BCP"],
14
+ name: "Best Current Practice",
15
+ harmonized_stages: [],
16
+ ),
17
+ ].freeze
18
+
19
+ def self.type
20
+ { key: :bcp, web: :bcp, title: "Best Current Practice", short: "BCP" }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end