pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.11

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 (432) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +33 -11
  3. data/conformance/pending.yaml +4 -0
  4. data/lib/pubid/adobe/identifier.rb +1 -3
  5. data/lib/pubid/adobe/parser.rb +10 -2
  6. data/lib/pubid/adobe.rb +1 -0
  7. data/lib/pubid/amca/builder.rb +2 -2
  8. data/lib/pubid/amca/identifiers/base.rb +49 -27
  9. data/lib/pubid/amca/identifiers/interpretation.rb +17 -9
  10. data/lib/pubid/amca/identifiers/publication.rb +13 -9
  11. data/lib/pubid/amca/identifiers/standard.rb +2 -0
  12. data/lib/pubid/amca/parser.rb +1 -1
  13. data/lib/pubid/amca/renderer.rb +4 -4
  14. data/lib/pubid/amca/urn_generator.rb +2 -2
  15. data/lib/pubid/amca.rb +2 -1
  16. data/lib/pubid/ansi/builder.rb +2 -2
  17. data/lib/pubid/ansi/identifier.rb +18 -0
  18. data/lib/pubid/ansi/parser.rb +1 -1
  19. data/lib/pubid/ansi/renderer.rb +2 -2
  20. data/lib/pubid/ansi.rb +5 -5
  21. data/lib/pubid/api/builder.rb +16 -2
  22. data/lib/pubid/api/identifier.rb +25 -4
  23. data/lib/pubid/api/identifiers/mpms.rb +10 -8
  24. data/lib/pubid/api/parser.rb +1 -1
  25. data/lib/pubid/api/renderer.rb +16 -7
  26. data/lib/pubid/api/single_identifier.rb +5 -12
  27. data/lib/pubid/api.rb +1 -0
  28. data/lib/pubid/ashrae/builder.rb +31 -10
  29. data/lib/pubid/ashrae/identifiers/addenda_package.rb +6 -0
  30. data/lib/pubid/ashrae/identifiers/addendum.rb +8 -0
  31. data/lib/pubid/ashrae/identifiers/base.rb +81 -5
  32. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +7 -0
  33. data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
  34. data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
  35. data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
  36. data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
  37. data/lib/pubid/ashrae/parser.rb +23 -8
  38. data/lib/pubid/ashrae/renderer.rb +6 -6
  39. data/lib/pubid/ashrae/supplement_identifier.rb +17 -2
  40. data/lib/pubid/ashrae/urn_generator.rb +8 -2
  41. data/lib/pubid/ashrae.rb +7 -1
  42. data/lib/pubid/asme/builder.rb +11 -2
  43. data/lib/pubid/asme/identifier.rb +9 -0
  44. data/lib/pubid/asme/identifiers/standard.rb +86 -2
  45. data/lib/pubid/asme/parser.rb +1 -1
  46. data/lib/pubid/asme/renderer.rb +3 -3
  47. data/lib/pubid/asme/single_identifier.rb +8 -1
  48. data/lib/pubid/asme/urn_generator.rb +2 -2
  49. data/lib/pubid/asme.rb +1 -0
  50. data/lib/pubid/astm/builder.rb +10 -3
  51. data/lib/pubid/astm/identifier.rb +9 -0
  52. data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
  53. data/lib/pubid/astm/identifiers/code_number.rb +81 -0
  54. data/lib/pubid/astm/identifiers/data_series.rb +2 -0
  55. data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
  56. data/lib/pubid/astm/identifiers/manual.rb +10 -0
  57. data/lib/pubid/astm/identifiers/monograph.rb +2 -0
  58. data/lib/pubid/astm/identifiers/research_report.rb +10 -0
  59. data/lib/pubid/astm/identifiers/standard.rb +10 -0
  60. data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
  61. data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
  62. data/lib/pubid/astm/identifiers.rb +1 -0
  63. data/lib/pubid/astm/parser.rb +1 -1
  64. data/lib/pubid/astm/renderer.rb +1 -1
  65. data/lib/pubid/astm/single_identifier.rb +31 -1
  66. data/lib/pubid/astm/urn_generator.rb +7 -5
  67. data/lib/pubid/astm.rb +1 -0
  68. data/lib/pubid/bipm/builder.rb +66 -10
  69. data/lib/pubid/bipm/identifier.rb +134 -9
  70. data/lib/pubid/bipm/identifiers/committee_document.rb +12 -0
  71. data/lib/pubid/bipm/identifiers/guide.rb +11 -0
  72. data/lib/pubid/bipm/identifiers/meeting.rb +12 -0
  73. data/lib/pubid/bipm/identifiers/mep.rb +12 -0
  74. data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
  75. data/lib/pubid/bipm/identifiers/si_brochure.rb +13 -0
  76. data/lib/pubid/bipm/parser.rb +65 -12
  77. data/lib/pubid/bipm/renderer.rb +8 -0
  78. data/lib/pubid/bipm/urn_parser.rb +11 -3
  79. data/lib/pubid/bipm.rb +7 -1
  80. data/lib/pubid/bsi/builder.rb +48 -38
  81. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  82. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -1
  84. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  85. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  86. data/lib/pubid/bsi/identifiers/handbook.rb +0 -2
  87. data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
  88. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  89. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  90. data/lib/pubid/bsi/parser.rb +1 -1
  91. data/lib/pubid/bsi/renderer.rb +63 -51
  92. data/lib/pubid/bsi/single_identifier.rb +16 -7
  93. data/lib/pubid/bsi/urn_generator.rb +11 -2
  94. data/lib/pubid/bsi.rb +7 -1
  95. data/lib/pubid/builder/base.rb +18 -8
  96. data/lib/pubid/bundled_identifier.rb +16 -6
  97. data/lib/pubid/calconnect/identifier.rb +9 -5
  98. data/lib/pubid/calconnect/parser.rb +1 -1
  99. data/lib/pubid/calconnect.rb +7 -1
  100. data/lib/pubid/ccsds/identifier.rb +9 -2
  101. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  102. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  103. data/lib/pubid/ccsds/parser.rb +1 -1
  104. data/lib/pubid/ccsds/single_identifier.rb +2 -2
  105. data/lib/pubid/ccsds.rb +1 -0
  106. data/lib/pubid/cen_cenelec/builder.rb +101 -76
  107. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  108. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  109. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  110. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  111. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  112. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  113. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  114. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
  115. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  116. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  117. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  118. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  119. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  120. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  121. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  122. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  123. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  124. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  125. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  126. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  127. data/lib/pubid/cen_cenelec.rb +28 -10
  128. data/lib/pubid/cie/builder.rb +10 -0
  129. data/lib/pubid/cie/identifier.rb +6 -1
  130. data/lib/pubid/cie/identifiers/bundle.rb +4 -2
  131. data/lib/pubid/cie/identifiers/conference.rb +2 -2
  132. data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
  133. data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
  134. data/lib/pubid/cie/identifiers/identical.rb +2 -2
  135. data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
  136. data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
  137. data/lib/pubid/cie/identifiers/standard.rb +22 -13
  138. data/lib/pubid/cie/identifiers/supplement.rb +2 -2
  139. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
  140. data/lib/pubid/cie/parser.rb +1 -1
  141. data/lib/pubid/cie.rb +7 -1
  142. data/lib/pubid/conformance/checks.rb +72 -0
  143. data/lib/pubid/conformance/corpus/case.rb +55 -0
  144. data/lib/pubid/conformance/corpus.rb +36 -0
  145. data/lib/pubid/conformance/generator.rb +212 -0
  146. data/lib/pubid/conformance/pending.rb +63 -0
  147. data/lib/pubid/conformance/runner.rb +153 -0
  148. data/lib/pubid/conformance.rb +55 -0
  149. data/lib/pubid/core.rb +2 -0
  150. data/lib/pubid/csa/builder.rb +47 -47
  151. data/lib/pubid/csa/composite_identifier.rb +14 -19
  152. data/lib/pubid/csa/identifier.rb +143 -81
  153. data/lib/pubid/csa/identifiers/bundled.rb +23 -13
  154. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  155. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  156. data/lib/pubid/csa/identifiers/combined.rb +95 -73
  157. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  158. data/lib/pubid/csa/identifiers/package.rb +2 -2
  159. data/lib/pubid/csa/parser.rb +6 -2
  160. data/lib/pubid/csa/renderer.rb +13 -5
  161. data/lib/pubid/csa/single_identifier.rb +93 -4
  162. data/lib/pubid/csa/urn_generator.rb +9 -2
  163. data/lib/pubid/csa/wrapper_identifier.rb +39 -23
  164. data/lib/pubid/csa.rb +7 -1
  165. data/lib/pubid/doi/identifier.rb +6 -3
  166. data/lib/pubid/doi/parser.rb +1 -1
  167. data/lib/pubid/doi.rb +1 -0
  168. data/lib/pubid/easc/identifier.rb +0 -2
  169. data/lib/pubid/easc/parser.rb +10 -2
  170. data/lib/pubid/easc.rb +1 -0
  171. data/lib/pubid/ecma/builder.rb +23 -9
  172. data/lib/pubid/ecma/identifier.rb +81 -10
  173. data/lib/pubid/ecma/parser.rb +39 -4
  174. data/lib/pubid/ecma/renderer.rb +29 -8
  175. data/lib/pubid/ecma/urn_generator.rb +34 -13
  176. data/lib/pubid/ecma/urn_parser.rb +30 -14
  177. data/lib/pubid/ecma.rb +1 -0
  178. data/lib/pubid/errors.rb +80 -0
  179. data/lib/pubid/etsi/builder.rb +6 -1
  180. data/lib/pubid/etsi/identifiers/base.rb +34 -20
  181. data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
  182. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
  183. data/lib/pubid/etsi/parser.rb +1 -1
  184. data/lib/pubid/etsi.rb +1 -0
  185. data/lib/pubid/evs/builder.rb +26 -0
  186. data/lib/pubid/evs/identifier.rb +37 -0
  187. data/lib/pubid/evs/identifiers/national_adoption.rb +17 -0
  188. data/lib/pubid/evs/identifiers.rb +9 -0
  189. data/lib/pubid/evs/parser.rb +27 -0
  190. data/lib/pubid/evs/renderer.rb +30 -0
  191. data/lib/pubid/evs/urn_generator.rb +30 -0
  192. data/lib/pubid/evs/urn_parser.rb +80 -0
  193. data/lib/pubid/evs.rb +90 -0
  194. data/lib/pubid/export.rb +1 -0
  195. data/lib/pubid/format_detector.rb +1 -0
  196. data/lib/pubid/gb/identifier.rb +6 -3
  197. data/lib/pubid/gb/parser.rb +1 -1
  198. data/lib/pubid/gb.rb +1 -0
  199. data/lib/pubid/gost/builder.rb +46 -9
  200. data/lib/pubid/gost/identifier.rb +0 -2
  201. data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
  202. data/lib/pubid/gost/parser.rb +10 -2
  203. data/lib/pubid/gost.rb +1 -0
  204. data/lib/pubid/iala/identifier.rb +9 -6
  205. data/lib/pubid/iala/parser.rb +10 -2
  206. data/lib/pubid/iala/urn_parser.rb +6 -2
  207. data/lib/pubid/iala.rb +1 -0
  208. data/lib/pubid/iana/builder.rb +3 -1
  209. data/lib/pubid/iana/identifier.rb +74 -6
  210. data/lib/pubid/iana/identifiers/registry.rb +36 -0
  211. data/lib/pubid/iana/parser.rb +1 -1
  212. data/lib/pubid/iana/renderer.rb +3 -0
  213. data/lib/pubid/iana/urn_generator.rb +5 -1
  214. data/lib/pubid/iana.rb +1 -0
  215. data/lib/pubid/identifier.rb +594 -10
  216. data/lib/pubid/identifier_metadata.rb +1 -0
  217. data/lib/pubid/idf/builder.rb +3 -3
  218. data/lib/pubid/idf/identifier.rb +18 -9
  219. data/lib/pubid/idf/parser.rb +1 -1
  220. data/lib/pubid/idf/renderer.rb +4 -4
  221. data/lib/pubid/idf/urn_generator.rb +1 -1
  222. data/lib/pubid/idf.rb +7 -1
  223. data/lib/pubid/iec/builder.rb +14 -7
  224. data/lib/pubid/iec/components.rb +0 -1
  225. data/lib/pubid/iec/identifier.rb +73 -83
  226. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  227. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  228. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  229. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  230. data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
  231. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  232. data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
  233. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  234. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  235. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  236. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  237. data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
  238. data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
  239. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  240. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  241. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  242. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  243. data/lib/pubid/iec/parser.rb +2 -18
  244. data/lib/pubid/iec/renderer.rb +13 -10
  245. data/lib/pubid/iec/single_identifier.rb +33 -10
  246. data/lib/pubid/iec/urn_generator.rb +227 -61
  247. data/lib/pubid/iec/urn_parser.rb +42 -4
  248. data/lib/pubid/iec.rb +1 -0
  249. data/lib/pubid/ieee/aiee/identifier.rb +2 -2
  250. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  251. data/lib/pubid/ieee/builder.rb +45 -1
  252. data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
  253. data/lib/pubid/ieee/identifiers/base.rb +42 -5
  254. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
  255. data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
  256. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
  257. data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
  258. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
  259. data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
  260. data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
  261. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
  262. data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
  263. data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
  264. data/lib/pubid/ieee/ire/identifier.rb +2 -2
  265. data/lib/pubid/ieee/ire/parser.rb +1 -1
  266. data/lib/pubid/ieee/nesc/parser.rb +1 -1
  267. data/lib/pubid/ieee/parser.rb +1 -1
  268. data/lib/pubid/ieee/renderer.rb +5 -1
  269. data/lib/pubid/ieee/urn_generator.rb +32 -3
  270. data/lib/pubid/ieee.rb +7 -1
  271. data/lib/pubid/ieee_debug.rb +1 -0
  272. data/lib/pubid/ietf/builder.rb +24 -8
  273. data/lib/pubid/ietf/identifiers/base.rb +25 -28
  274. data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
  275. data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
  276. data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
  277. data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
  278. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  279. data/lib/pubid/ietf/identifiers/std.rb +11 -0
  280. data/lib/pubid/ietf/identifiers.rb +1 -0
  281. data/lib/pubid/ietf/parser.rb +27 -9
  282. data/lib/pubid/ietf/renderer.rb +44 -6
  283. data/lib/pubid/ietf/urn_generator.rb +20 -6
  284. data/lib/pubid/ietf/urn_parser.rb +10 -2
  285. data/lib/pubid/ietf.rb +12 -2
  286. data/lib/pubid/iho/identifiers/base.rb +10 -3
  287. data/lib/pubid/iho/parser.rb +1 -1
  288. data/lib/pubid/iho.rb +1 -0
  289. data/lib/pubid/isbn/identifier.rb +25 -7
  290. data/lib/pubid/isbn/parser.rb +1 -1
  291. data/lib/pubid/isbn.rb +1 -0
  292. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  293. data/lib/pubid/iso/combined_identifier.rb +5 -3
  294. data/lib/pubid/iso/identifier.rb +12 -7
  295. data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
  296. data/lib/pubid/iso/parser.rb +1 -1
  297. data/lib/pubid/iso.rb +7 -1
  298. data/lib/pubid/itu/identifiers/addendum.rb +2 -2
  299. data/lib/pubid/itu/identifiers/amendment.rb +2 -2
  300. data/lib/pubid/itu/identifiers/base.rb +19 -5
  301. data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
  302. data/lib/pubid/itu/identifiers/errata.rb +2 -2
  303. data/lib/pubid/itu/identifiers/supplement.rb +2 -2
  304. data/lib/pubid/itu/parser.rb +1 -1
  305. data/lib/pubid/itu.rb +1 -0
  306. data/lib/pubid/jcgm/builder.rb +1 -1
  307. data/lib/pubid/jcgm/identifier.rb +10 -0
  308. data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
  309. data/lib/pubid/jcgm/parser.rb +10 -3
  310. data/lib/pubid/jcgm/renderer.rb +10 -3
  311. data/lib/pubid/jcgm/single_identifier.rb +24 -15
  312. data/lib/pubid/jcgm/urn_generator.rb +1 -1
  313. data/lib/pubid/jcgm/urn_parser.rb +156 -14
  314. data/lib/pubid/jcgm.rb +10 -0
  315. data/lib/pubid/jis/identifier.rb +10 -3
  316. data/lib/pubid/jis/parser.rb +1 -1
  317. data/lib/pubid/jis.rb +1 -0
  318. data/lib/pubid/nist/components/stage.rb +2 -2
  319. data/lib/pubid/nist/configuration.rb +6 -8
  320. data/lib/pubid/nist/identifiers/base.rb +12 -2
  321. data/lib/pubid/nist/identifiers/circular.rb +9 -2
  322. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  323. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
  324. data/lib/pubid/nist/identifiers/crpl_report.rb +7 -1
  325. data/lib/pubid/nist/identifiers/handbook.rb +9 -2
  326. data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
  327. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +14 -6
  328. data/lib/pubid/nist/identifiers/monograph.rb +14 -7
  329. data/lib/pubid/nist/identifiers/report.rb +14 -6
  330. data/lib/pubid/nist/parser.rb +1 -1
  331. data/lib/pubid/nist/supplement_identifier.rb +16 -1
  332. data/lib/pubid/nist.rb +7 -1
  333. data/lib/pubid/oasis/builder.rb +12 -10
  334. data/lib/pubid/oasis/identifier.rb +89 -11
  335. data/lib/pubid/oasis/parser.rb +1 -1
  336. data/lib/pubid/oasis.rb +7 -1
  337. data/lib/pubid/ogc/identifier.rb +9 -5
  338. data/lib/pubid/ogc/parser.rb +1 -1
  339. data/lib/pubid/ogc.rb +1 -0
  340. data/lib/pubid/oiml/builder.rb +5 -1
  341. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  342. data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
  343. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  344. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  345. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  346. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  347. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  348. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  349. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  350. data/lib/pubid/oiml/identifiers.rb +1 -0
  351. data/lib/pubid/oiml/parser.rb +1 -1
  352. data/lib/pubid/oiml/single_identifier.rb +26 -42
  353. data/lib/pubid/oiml/supplement_identifier.rb +27 -0
  354. data/lib/pubid/oiml.rb +7 -1
  355. data/lib/pubid/omg/builder.rb +1 -0
  356. data/lib/pubid/omg/identifier.rb +20 -3
  357. data/lib/pubid/omg/parser.rb +64 -11
  358. data/lib/pubid/omg/renderer.rb +13 -1
  359. data/lib/pubid/omg.rb +2 -1
  360. data/lib/pubid/parser/grammar.rb +74 -0
  361. data/lib/pubid/parser.rb +2 -0
  362. data/lib/pubid/parsers/mr_string.rb +19 -0
  363. data/lib/pubid/plateau/parser.rb +1 -1
  364. data/lib/pubid/plateau.rb +10 -0
  365. data/lib/pubid/prefixes_support.rb +1 -0
  366. data/lib/pubid/renderers/annotator.rb +233 -0
  367. data/lib/pubid/renderers/base.rb +13 -0
  368. data/lib/pubid/renderers/directives_renderer.rb +3 -3
  369. data/lib/pubid/renderers/human_readable.rb +3 -3
  370. data/lib/pubid/renderers/mr_string.rb +15 -9
  371. data/lib/pubid/renderers.rb +1 -0
  372. data/lib/pubid/rendering/numbering.rb +25 -7
  373. data/lib/pubid/rendering.rb +1 -0
  374. data/lib/pubid/sae/identifiers/base.rb +9 -2
  375. data/lib/pubid/sae/parser.rb +1 -1
  376. data/lib/pubid/sae.rb +1 -0
  377. data/lib/pubid/schema/declaration.rb +33 -0
  378. data/lib/pubid/schema/error.rb +14 -0
  379. data/lib/pubid/schema/identifier_type.rb +23 -0
  380. data/lib/pubid/schema/loader.rb +117 -0
  381. data/lib/pubid/schema/typed_stage.rb +24 -0
  382. data/lib/pubid/schema.rb +25 -0
  383. data/lib/pubid/tgpp/builder.rb +1 -1
  384. data/lib/pubid/tgpp/identifier.rb +21 -5
  385. data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
  386. data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
  387. data/lib/pubid/tgpp/parser.rb +22 -6
  388. data/lib/pubid/tgpp/renderer.rb +21 -5
  389. data/lib/pubid/tgpp/urn_generator.rb +27 -8
  390. data/lib/pubid/tgpp/urn_parser.rb +8 -6
  391. data/lib/pubid/tgpp.rb +7 -1
  392. data/lib/pubid/type_resolver.rb +16 -1
  393. data/lib/pubid/un/identifier.rb +6 -3
  394. data/lib/pubid/un/parser.rb +1 -1
  395. data/lib/pubid/un.rb +1 -0
  396. data/lib/pubid/urn_parser/errors.rb +8 -1
  397. data/lib/pubid/urn_parser.rb +1 -0
  398. data/lib/pubid/utils.rb +1 -0
  399. data/lib/pubid/version.rb +1 -1
  400. data/lib/pubid/w3c/builder.rb +5 -5
  401. data/lib/pubid/w3c/identifier.rb +38 -9
  402. data/lib/pubid/w3c/parser.rb +1 -1
  403. data/lib/pubid/w3c/renderer.rb +1 -1
  404. data/lib/pubid/w3c/urn_generator.rb +2 -2
  405. data/lib/pubid/w3c.rb +1 -0
  406. data/lib/pubid/xsf/identifier.rb +9 -5
  407. data/lib/pubid/xsf/parser.rb +17 -4
  408. data/lib/pubid/xsf.rb +7 -1
  409. data/lib/pubid.rb +399 -21
  410. data/lib/tasks/conformance.rake +34 -0
  411. data/lib/tasks/docs.rake +3 -3
  412. data/lib/tasks/schema.rake +88 -0
  413. data/schema/core/joint_prefixes.yaml +24 -0
  414. data/schema/iec.yaml +1017 -0
  415. data/schema/iso.yaml +1586 -0
  416. data/schema/schema.schema.yaml +96 -0
  417. metadata +38 -17
  418. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  419. data/archived-gems/pubid-iec/stages.yaml +0 -129
  420. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  421. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  422. data/archived-gems/pubid-iso/stages.yaml +0 -106
  423. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  424. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  425. data/archived-gems/pubid-itu/series.yaml +0 -42
  426. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  427. data/archived-gems/pubid-nist/series.yaml +0 -121
  428. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  429. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  430. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  431. data/lib/pubid/iec/components/code.rb +0 -36
  432. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
@@ -44,20 +44,38 @@ module Pubid
44
44
  end
45
45
 
46
46
  def self.parse(identifier)
47
+ unless identifier.is_a?(String)
48
+ raise Pubid::Errors::InvalidInputError,
49
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
50
+ end
51
+
47
52
  if identifier.length > Pubid::MAX_INPUT_LENGTH
48
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
53
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
49
54
  end
50
55
 
56
+ # The two guards above must stay OUTSIDE build_identifier: this method
57
+ # rescues ArgumentError to convert the Builder's check-digit and
58
+ # length validation into a parse failure, and that rescue used to
59
+ # swallow the guards' own ArgumentError and re-raise it as a
60
+ # RuntimeError - so ISBN was the one guarded flavor where an over-long
61
+ # input did not surface as ArgumentError.
62
+ build_identifier(identifier)
63
+ end
64
+
65
+ # @raise [Pubid::Errors::ParseError] if the string is not a valid ISBN
66
+ def self.build_identifier(identifier)
51
67
  parsed = Parser.parse(identifier)
52
68
  Builder.build(parsed)
53
- rescue Parslet::ParseFailed => e
54
- raise "Failed to parse ISBN '#{identifier}': #{e.message}"
55
69
  rescue ArgumentError => e
56
- # Builder validates length/check-digit; surface as a parse error so
57
- # the error contract matches other flavors (always raises a string
58
- # beginning with "Failed to parse").
59
- raise "Failed to parse ISBN '#{identifier}': #{e.message}"
70
+ # The Builder validates length and check digit. Surface that as a parse
71
+ # failure, so every ISBN rejection reaches the caller as the same class
72
+ # a grammar rejection does.
73
+ raise Pubid::Errors::ParseError.new(
74
+ "invalid ISBN '#{identifier}': #{e.message}",
75
+ input: identifier, flavor: "isbn",
76
+ )
60
77
  end
78
+ private_class_method :build_identifier
61
79
  end
62
80
  end
63
81
  end
@@ -12,7 +12,7 @@ module Pubid
12
12
  # ISBN-10 final digit may be "X" (check digit value 10). Hyphens are
13
13
  # optional and may appear in any group position; they are preserved
14
14
  # for round-trip rendering.
15
- class Parser < Parslet::Parser
15
+ class Parser < ::Pubid::Parser::Grammar
16
16
  rule(:space) { str(" ") }
17
17
  rule(:colon) { str(":") }
18
18
  rule(:hyphen) { str("-") }
data/lib/pubid/isbn.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  # ISBN flavor — bibliographic book identifier per ISO 2108.
5
6
  #
@@ -86,15 +86,17 @@ module Pubid
86
86
  base_document&.copublishers
87
87
  end
88
88
 
89
+ # See the note on Pubid::BundledIdentifier#to_s: `**opts` carries flags
90
+ # this list does not name, `annotated:` above all.
89
91
  def to_s(lang: :en, lang_single: false, with_edition: false, format: nil,
90
- stage_format_long: nil, with_date: nil)
92
+ stage_format_long: nil, with_date: nil, **opts)
91
93
  parts = [base_document.to_s(lang: lang, lang_single: lang_single,
92
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date)]
94
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts)]
93
95
 
94
96
  # Add each supplement with "+" separator
95
97
  supplements.each do |supplement|
96
98
  supplement_str = supplement.to_supplement_s(lang: lang, lang_single: lang_single,
97
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date)
99
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts)
98
100
  parts << "+ #{supplement_str}"
99
101
  end
100
102
 
@@ -9,11 +9,13 @@ module Pubid
9
9
  polymorphic: true, collection: true
10
10
  attribute :type, :string, default: -> { "combined_identifier" }
11
11
 
12
- def to_s(lang: :en, lang_single: false)
12
+ # `**opts` carries render flags this list does not name (`annotated:`),
13
+ # which the closed signature used to reject outright.
14
+ def to_s(lang: :en, lang_single: false, **opts)
13
15
  [
14
- base.to_s(lang: lang, lang_single: lang_single),
16
+ base.to_s(lang: lang, lang_single: lang_single, **opts),
15
17
  additional_identifiers.map do |id|
16
- id.to_s(lang: lang, lang_single: lang_single)
18
+ id.to_s(lang: lang, lang_single: lang_single, **opts)
17
19
  end,
18
20
  ].flatten.join(" | ")
19
21
  end
@@ -166,9 +166,14 @@ module Pubid
166
166
  def stage_from_kv(model, value)
167
167
  return if value.nil? || value.to_s.empty?
168
168
 
169
+ # The fallback consults the flavor-wide table. It used to call
170
+ # `Pubid::Iso::Scheme`, a class removed repo-wide in e3c19ea1 — so any
171
+ # code absent from the class's own TYPED_STAGES raised NameError
172
+ # instead of falling back. The IEC twin (iec/identifier.rb) was
173
+ # migrated at the time; ISO was missed.
169
174
  ts = (model.class.const_defined?(:TYPED_STAGES) &&
170
175
  model.class::TYPED_STAGES.find { |t| t.code.to_s == value.to_s }) ||
171
- Pubid::Iso::Scheme.locate_typed_stage_by_code(value)
176
+ Pubid::Iso.locate_stage_by_code(value)
172
177
  return unless ts
173
178
 
174
179
  # The renderer prefers `original_abbr` (the parsed surface form); without
@@ -283,8 +288,13 @@ module Pubid
283
288
  end
284
289
 
285
290
  def self.parse(string, format: :auto)
291
+ unless string.is_a?(String)
292
+ raise Pubid::Errors::InvalidInputError,
293
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
294
+ end
295
+
286
296
  if string.length > Pubid::MAX_INPUT_LENGTH
287
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
297
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
288
298
  end
289
299
 
290
300
  format = Pubid::FormatDetector.detect(string) if format == :auto
@@ -296,11 +306,6 @@ module Pubid
296
306
  Pubid::Parsers::MrString.parse(string)
297
307
  else
298
308
  parsed = Pubid::Iso::Parser.new.parse(string)
299
- if parsed.nil? || parsed.empty?
300
- raise Pubid::Iso::Parser::ParseError,
301
- "Invalid identifier format"
302
- end
303
-
304
309
  Pubid::Iso::Builder.new.build(parsed)
305
310
  end
306
311
  end
@@ -68,12 +68,12 @@ module Pubid
68
68
  # end
69
69
 
70
70
  def to_s(lang: :en, lang_single: false, with_edition: false,
71
- format: nil, stage_format_long: nil, with_date: nil)
71
+ format: nil, stage_format_long: nil, with_date: nil, **opts)
72
72
  if base
73
73
  # Full rendering with base identifier
74
74
  [
75
75
  base.to_s(lang: lang, lang_single: lang_single,
76
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date),
76
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts),
77
77
  " #{supplement_publisher.render}",
78
78
  " SUP", # Always render as "SUP" even though typed_stage.abbreviation is "DIR SUP"
79
79
  (date ? ":#{date.render}" : ""),
@@ -81,13 +81,13 @@ format: nil, stage_format_long: nil, with_date: nil)
81
81
  ].join
82
82
  else
83
83
  # Simplified rendering for bundled identifiers (just the supplement part)
84
- to_supplement_s(lang: lang, lang_single: lang_single)
84
+ to_supplement_s(lang: lang, lang_single: lang_single, **opts)
85
85
  end
86
86
  end
87
87
 
88
88
  # Render just the supplement part (for use in bundled identifiers)
89
89
  def to_supplement_s(lang: :en, lang_single: false, with_edition: false,
90
- format: nil, stage_format_long: nil, with_date: nil)
90
+ format: nil, stage_format_long: nil, with_date: nil, **_opts)
91
91
  date_str = if date
92
92
  month_part = date.month ? "-#{date.month}" : ""
93
93
  ":#{date.render}#{month_part}"
@@ -3,7 +3,7 @@ require "parslet"
3
3
 
4
4
  module Pubid
5
5
  module Iso
6
- class Parser < Parslet::Parser
6
+ class Parser < ::Pubid::Parser::Grammar
7
7
  include ::Pubid::Parser::CommonParseRules
8
8
  include ::Pubid::Parser::CommonParseMethods
9
9
 
data/lib/pubid/iso.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  require "lutaml/model"
4
5
 
5
6
  module Pubid
@@ -31,8 +32,13 @@ module Pubid
31
32
  # @param format [Symbol] :auto, :human, :mr_string, or :urn
32
33
  # @return [Identifier] the parsed identifier
33
34
  def self.parse(identifier, format: :auto)
35
+ unless identifier.is_a?(String)
36
+ raise Pubid::Errors::InvalidInputError,
37
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
38
+ end
39
+
34
40
  if identifier.length > Pubid::MAX_INPUT_LENGTH
35
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
41
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
36
42
  end
37
43
 
38
44
  format = Pubid::FormatDetector.detect(identifier) if format == :auto
@@ -6,8 +6,8 @@ module Pubid
6
6
  # Addendum identifier (Add.)
7
7
  # Pattern: "ITU-T I.363 (1993) Add. 1 (11/1993)"
8
8
  class Addendum < Supplement
9
- def to_s
10
- render_supplement("Add.")
9
+ def to_s(**opts)
10
+ annotate_plain_render(render_supplement("Add."), **opts)
11
11
  end
12
12
  end
13
13
  end
@@ -10,8 +10,8 @@ module Pubid
10
10
  # supplement types (Cor./Err./Suppl./Add.). The parser accepts both
11
11
  # spellings (see Parser#supplement_type), so the period-less input form
12
12
  # still round-trips through parse — it just normalizes here.
13
- def to_s
14
- render_supplement("Amd.")
13
+ def to_s(**opts)
14
+ annotate_plain_render(render_supplement("Amd."), **opts)
15
15
  end
16
16
  end
17
17
  end
@@ -6,18 +6,29 @@ module Pubid
6
6
  class Identifier < ::Pubid::Identifier
7
7
  # Parse an ITU identifier string into an identifier object.
8
8
  def self.parse(identifier)
9
+ unless identifier.is_a?(String)
10
+ raise Pubid::Errors::InvalidInputError,
11
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
12
+ end
13
+
14
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
15
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
16
+ end
17
+
9
18
  parsed = Parser.parse(normalize_whitespace(identifier))
10
19
  Builder.build(parsed)
11
- rescue Parslet::ParseFailed => e
12
- raise "Failed to parse ITU identifier '#{identifier}': #{e.message}"
13
20
  end
14
21
 
15
22
  # ITU's own listings occasionally carry a doubled space
16
23
  # ("ITU-T D.271 (10/2016)"). Whitespace is never significant in an ITU
17
24
  # identifier, so collapse runs of it rather than teaching every rule to
18
25
  # tolerate them. Any string over the shared input-length guard is left
19
- # untouched — `Pubid.parse` rejects it before this point, and the guard
20
- # exists precisely to keep long inputs away from regexes.
26
+ # untouched: `self.parse` above rejects it before this point, and the
27
+ # guard exists precisely to keep long inputs away from regexes. (This
28
+ # note used to credit `Pubid.parse` with the rejection, which was wrong
29
+ # in both directions — `Pubid.parse` never routes a human-readable ITU
30
+ # string to a flavor, and ITU carried no raising guard of its own until
31
+ # one was added to `self.parse`, so an over-long string did reach here.)
21
32
  def self.normalize_whitespace(identifier)
22
33
  return identifier unless identifier.is_a?(String)
23
34
  return identifier if identifier.length > ::Pubid::MAX_INPUT_LENGTH
@@ -184,10 +195,13 @@ module Pubid
184
195
  # @param format [Symbol] :long for title-style rendering of supported
185
196
  # identifiers, otherwise the default short form.
186
197
  def to_s(**opts)
198
+ annotated = opts[:annotated]
187
199
  opts = self.class.normalize_to_s_opts(opts)
188
200
  result = render_base(**opts) + render_language_suffix
189
201
  result += " | #{common_text_twin}" if common_text_twin
190
- result
202
+ # ITU composes its own string rather than going through `render`, so it
203
+ # never reaches the shared annotation hook. Apply it here.
204
+ annotate_plain_render(result, annotated: annotated)
191
205
  end
192
206
 
193
207
  def render_base(**_opts)
@@ -19,8 +19,8 @@ module Pubid
19
19
  map "technical", to: :technical
20
20
  end
21
21
 
22
- def to_s
23
- render_supplement(technical ? "Technical Cor." : "Cor.")
22
+ def to_s(**opts)
23
+ annotate_plain_render(render_supplement(technical ? "Technical Cor." : "Cor."), **opts)
24
24
  end
25
25
 
26
26
  # `super` already enforces instance_of?(self.class), so this only has
@@ -6,8 +6,8 @@ module Pubid
6
6
  # Errata identifier (Err.)
7
7
  # Pattern: "ITU-T G.9701 (2014) Err. 1 (07/2016)"
8
8
  class Errata < Supplement
9
- def to_s
10
- render_supplement("Err.")
9
+ def to_s(**opts)
10
+ annotate_plain_render(render_supplement("Err."), **opts)
11
11
  end
12
12
  end
13
13
  end
@@ -115,8 +115,8 @@ module Pubid
115
115
  result
116
116
  end
117
117
 
118
- def to_s
119
- render_supplement("Suppl.")
118
+ def to_s(**opts)
119
+ annotate_plain_render(render_supplement("Suppl."), **opts)
120
120
  end
121
121
 
122
122
  # Shared by Amendment / Corrigendum / Errata.
@@ -4,7 +4,7 @@ require "parslet"
4
4
 
5
5
  module Pubid
6
6
  module Itu
7
- class Parser < Parslet::Parser
7
+ class Parser < ::Pubid::Parser::Grammar
8
8
  # Basic elements
9
9
  rule(:digit) { match["0-9"] }
10
10
  rule(:digits) { digit.repeat(1) }
data/lib/pubid/itu.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  require "lutaml/model"
4
5
 
5
6
  module Pubid
@@ -69,7 +69,7 @@ module Pubid
69
69
  when :publisher
70
70
  Jcgm::Components::Publisher.new(publisher: value.to_s)
71
71
  when :number
72
- Pubid::Components::Code.new(value: value.to_s)
72
+ value.to_s
73
73
  when :date
74
74
  date_str = value.to_s
75
75
  if date_str.include?("-")
@@ -3,6 +3,16 @@
3
3
  module Pubid
4
4
  module Jcgm
5
5
  class Identifier < ::Pubid::Identifier
6
+ # `number`/`part`/`subpart` are declared here rather than inherited as a
7
+ # Components::Code: JCGM stores a bare string in `number` and uses neither
8
+ # of the other two. Declaring on this class is safe because its body lives
9
+ # in this one file and is never reopened, so every subclass body opens
10
+ # after it has run (lutaml deep-dups the parent attribute table at
11
+ # class-definition time).
12
+ attribute :number, :string
13
+ attribute :part, :string
14
+ attribute :subpart, :string
15
+
6
16
  def self.parse(string)
7
17
  Pubid::Jcgm.parse(string)
8
18
  end
@@ -39,7 +39,7 @@ module Pubid
39
39
  end
40
40
 
41
41
  def ordinal
42
- self.class.ordinal(number&.value)
42
+ self.class.ordinal(number)
43
43
  end
44
44
  end
45
45
  end
@@ -4,7 +4,7 @@ require "parslet"
4
4
 
5
5
  module Pubid
6
6
  module Jcgm
7
- class Parser < Parslet::Parser
7
+ class Parser < ::Pubid::Parser::Grammar
8
8
  include ::Pubid::Parser::CommonParseRules
9
9
  include ::Pubid::Parser::CommonParseMethods
10
10
 
@@ -53,10 +53,17 @@ module Pubid
53
53
  # wants the ordinal suffix), so ordered choice is unambiguous. Emits the
54
54
  # same tokens as a guide plus type_with_stage "Meeting", so the generic
55
55
  # builder path resolves it to Identifiers::Meeting (like "Amd").
56
+ #
57
+ # The trailing " (YYYY)" group is optional, so the partial reference
58
+ # "JCGM 11st Meeting" parses with `date` left nil. JCGM numbers its
59
+ # meetings in one sequence, so the ordinal alone names the event and the
60
+ # year is redundant detail. The whole group is `.maybe` (not the year
61
+ # inside it), so a dangling "(" or a truncated year still fails —
62
+ # the same shape as `date_portion.maybe` in `rule(:base)`.
56
63
  rule(:meeting_identifier) do
57
64
  publisher >> space >> digits.as(:number) >> ordinal_suffix >>
58
- space >> str("Meeting").as(:type_with_stage) >> space >>
59
- str("(") >> year_digits.as(:date) >> str(")")
65
+ space >> str("Meeting").as(:type_with_stage) >>
66
+ (space >> str("(") >> year_digits.as(:date) >> str(")")).maybe
60
67
  end
61
68
 
62
69
  rule(:ordinal_suffix) do
@@ -37,8 +37,15 @@ module Pubid
37
37
  id.date ? ":#{id.date}" : ""
38
38
  end
39
39
 
40
+ # Two surface forms:
41
+ # "JCGM 17th Meeting (2012)" — date present (published records)
42
+ # "JCGM 17th Meeting" — date absent (partial reference)
43
+ # The ordinal alone names the meeting, so the dateless form is a valid
44
+ # identifier and must stay re-parseable (the parser makes the " (YYYY)"
45
+ # group optional to match).
40
46
  def render_meeting(id)
41
- "JCGM #{id.ordinal} Meeting (#{id.date.year})"
47
+ base = "JCGM #{id.ordinal} Meeting"
48
+ id.date ? "#{base} (#{id.date.year})" : base
42
49
  end
43
50
 
44
51
  def render_single(id)
@@ -52,7 +59,7 @@ module Pubid
52
59
  def render_amendment(id, context)
53
60
  result = id.base.to_s if id.base
54
61
  result += "/Amd"
55
- result += " #{id.number.render(context:)}" if id.number
62
+ result += " #{id.number}" if id.number
56
63
  result += ":#{id.date}" if id.date
57
64
  result
58
65
  end
@@ -60,7 +67,7 @@ module Pubid
60
67
  def render_gum_guide(id, context)
61
68
  parts = []
62
69
  parts << id.publisher.publisher if id.publisher
63
- parts << "GUM-#{id.number.render(context:)}" if id.number
70
+ parts << "GUM-#{id.number}" if id.number
64
71
 
65
72
  result = parts.join(" ")
66
73
  result += ":#{id.date}" if id.date
@@ -7,7 +7,6 @@ module Pubid
7
7
  default: -> { self.class.default_publisher }
8
8
  attribute :typed_stage, Pubid::Components::TypedStage,
9
9
  default: -> { self.class.published_typed_stage }
10
- attribute :number, Pubid::Components::Code
11
10
  attribute :date, Pubid::Components::Date
12
11
  attribute :languages, Pubid::Components::Language, collection: true
13
12
  attribute :stage, Pubid::Components::Stage
@@ -18,7 +17,7 @@ module Pubid
18
17
  # (fully determined by the class, i.e. `_type`) are intentionally NOT
19
18
  # mapped — they are reconstructed from the class on load via the
20
19
  # attribute defaults above. Components collapse to bare scalars:
21
- # number -> "100" (not {value: "100"}); date -> year/month/day scalars.
20
+ # number is already a bare :string; date -> year/month/day scalars.
22
21
  # Mirrors ISO (lib/pubid/iso/identifier.rb) and OIML.
23
22
  key_value do
24
23
  map "_type", to: :_type
@@ -37,15 +36,29 @@ module Pubid
37
36
  # The class's published typed_stage (canonical surface form). Each JCGM
38
37
  # class registers exactly one, all :published; `_type` fixes the class,
39
38
  # so an omitted typed_stage reconstructs deterministically on from_hash.
39
+ #
40
+ # `original_abbr` is deliberately LEFT NIL. It records the spelling the
41
+ # input used and is not serialized, so it cannot survive a round trip —
42
+ # and this method is one of the two paths that fill `typed_stage`. The
43
+ # other is the parse path (`Builder#locate_typed_stage` ->
44
+ # `Jcgm.locate_stage`), which returns the registry entry untouched.
45
+ # Setting it here made the two disagree, so `from_hash(to_hash) != parse`
46
+ # for every type the grammar tags (Meeting, Corrigendum, Amendment) —
47
+ # and because `#matches?` is `exclude(...) == other.exclude(...)`, a
48
+ # relaton index lookup then silently matched nothing. Nothing in JCGM
49
+ # reads the field: the renderer hardcodes its surface words, the URN
50
+ # generator reads only `type_code`, and `TypedStage#abbreviation` chooses
51
+ # among long_abbr/short_abbr/abbr.first. Recording the *matched* token
52
+ # instead would not work either — "/Cor 1" would store "Cor" where
53
+ # from_hash rebuilds "Corrigendum".
40
54
  def self.published_typed_stage
41
55
  return nil unless const_defined?(:TYPED_STAGES)
42
56
 
43
57
  ts = self::TYPED_STAGES.find { |t| t.stage_code.to_s == "published" }
44
- return nil unless ts
45
-
46
- ts = ts.dup
47
- ts.original_abbr = ts.canonical_abbreviation
48
- ts
58
+ # dup: locate_stage hands out the shared object from the frozen
59
+ # TYPED_STAGES array (the array is frozen, its elements are not), so a
60
+ # future in-place mutation would otherwise leak globally.
61
+ ts&.dup
49
62
  end
50
63
 
51
64
  # type and stage are derived from typed_stage, never stored — so the
@@ -58,13 +71,9 @@ module Pubid
58
71
  typed_stage&.to_stage
59
72
  end
60
73
 
61
- # --- number (Code) flattened to a bare string ---
62
- def number_to_kv(model, doc) = emit_kv(doc, "number", model.number&.value)
63
- def number_from_kv(model, value) = model.number = build_code(value)
64
-
65
- def build_code(value)
66
- Pubid::Components::Code.new(value: value.to_s)
67
- end
74
+ # --- number ---
75
+ def number_to_kv(model, doc) = emit_kv(doc, "number", model.number)
76
+ def number_from_kv(model, value) = model.number = value.to_s
68
77
 
69
78
  # --- date flattened to top-level year/month/day scalars ---
70
79
  def year_to_kv(model, doc) = emit_kv(doc, "year", model.date&.year)
@@ -90,7 +99,7 @@ module Pubid
90
99
 
91
100
  def number_portion
92
101
  parts = []
93
- parts << number.value if number
102
+ parts << number if number
94
103
  parts << ":#{date.year}" if date
95
104
  parts.join
96
105
  end
@@ -18,7 +18,7 @@ module Pubid
18
18
  # urn:jcgm:meeting:<number>:<year>, e.g. urn:jcgm:meeting:17:2012
19
19
  def generate_meeting_urn
20
20
  parts = ["urn", "jcgm", "meeting"]
21
- parts << identifier.number.value if identifier.number
21
+ parts << identifier.number if identifier.number
22
22
  parts << identifier.date.year if identifier.date
23
23
  parts.join(":")
24
24
  end