pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.12

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 (461) 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/components/date.rb +10 -4
  82. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  83. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  84. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -2
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  87. data/lib/pubid/bsi/identifiers/handbook.rb +1 -3
  88. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -2
  89. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  90. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  91. data/lib/pubid/bsi/parser.rb +1 -1
  92. data/lib/pubid/bsi/renderer.rb +63 -51
  93. data/lib/pubid/bsi/single_identifier.rb +27 -9
  94. data/lib/pubid/bsi/urn_generator.rb +11 -2
  95. data/lib/pubid/bsi.rb +7 -1
  96. data/lib/pubid/builder/base.rb +18 -8
  97. data/lib/pubid/bundled_identifier.rb +16 -6
  98. data/lib/pubid/calconnect/identifier.rb +9 -5
  99. data/lib/pubid/calconnect/parser.rb +1 -1
  100. data/lib/pubid/calconnect.rb +7 -1
  101. data/lib/pubid/ccsds/identifier.rb +13 -2
  102. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  103. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  104. data/lib/pubid/ccsds/parser.rb +1 -1
  105. data/lib/pubid/ccsds/single_identifier.rb +16 -12
  106. data/lib/pubid/ccsds.rb +1 -0
  107. data/lib/pubid/cen_cenelec/builder.rb +101 -76
  108. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  109. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  110. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  111. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  112. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  113. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  114. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  115. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
  116. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  117. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  118. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  119. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  120. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  121. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  122. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  123. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  124. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  125. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  126. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  127. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  128. data/lib/pubid/cen_cenelec.rb +28 -10
  129. data/lib/pubid/cie/builder.rb +10 -0
  130. data/lib/pubid/cie/identifier.rb +6 -1
  131. data/lib/pubid/cie/identifiers/bundle.rb +4 -2
  132. data/lib/pubid/cie/identifiers/conference.rb +2 -2
  133. data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
  134. data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
  135. data/lib/pubid/cie/identifiers/identical.rb +2 -2
  136. data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
  137. data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
  138. data/lib/pubid/cie/identifiers/standard.rb +22 -13
  139. data/lib/pubid/cie/identifiers/supplement.rb +2 -2
  140. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
  141. data/lib/pubid/cie/parser.rb +1 -1
  142. data/lib/pubid/cie.rb +7 -1
  143. data/lib/pubid/conformance/checks.rb +72 -0
  144. data/lib/pubid/conformance/corpus/case.rb +55 -0
  145. data/lib/pubid/conformance/corpus.rb +36 -0
  146. data/lib/pubid/conformance/generator.rb +212 -0
  147. data/lib/pubid/conformance/pending.rb +63 -0
  148. data/lib/pubid/conformance/runner.rb +153 -0
  149. data/lib/pubid/conformance.rb +55 -0
  150. data/lib/pubid/core.rb +2 -0
  151. data/lib/pubid/csa/builder.rb +47 -47
  152. data/lib/pubid/csa/composite_identifier.rb +14 -19
  153. data/lib/pubid/csa/identifier.rb +143 -81
  154. data/lib/pubid/csa/identifiers/bundled.rb +23 -13
  155. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  156. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  157. data/lib/pubid/csa/identifiers/combined.rb +95 -73
  158. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  159. data/lib/pubid/csa/identifiers/package.rb +2 -2
  160. data/lib/pubid/csa/parser.rb +6 -2
  161. data/lib/pubid/csa/renderer.rb +13 -5
  162. data/lib/pubid/csa/single_identifier.rb +93 -4
  163. data/lib/pubid/csa/urn_generator.rb +9 -2
  164. data/lib/pubid/csa/wrapper_identifier.rb +39 -23
  165. data/lib/pubid/csa.rb +7 -1
  166. data/lib/pubid/doi/identifier.rb +6 -3
  167. data/lib/pubid/doi/parser.rb +1 -1
  168. data/lib/pubid/doi.rb +1 -0
  169. data/lib/pubid/easc/identifier.rb +0 -2
  170. data/lib/pubid/easc/parser.rb +10 -2
  171. data/lib/pubid/easc.rb +1 -0
  172. data/lib/pubid/ecma/builder.rb +23 -9
  173. data/lib/pubid/ecma/identifier.rb +81 -10
  174. data/lib/pubid/ecma/parser.rb +39 -4
  175. data/lib/pubid/ecma/renderer.rb +29 -8
  176. data/lib/pubid/ecma/urn_generator.rb +34 -13
  177. data/lib/pubid/ecma/urn_parser.rb +30 -14
  178. data/lib/pubid/ecma.rb +1 -0
  179. data/lib/pubid/errors.rb +80 -0
  180. data/lib/pubid/etsi/builder.rb +6 -1
  181. data/lib/pubid/etsi/identifiers/base.rb +34 -20
  182. data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
  183. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
  184. data/lib/pubid/etsi/parser.rb +1 -1
  185. data/lib/pubid/etsi.rb +1 -0
  186. data/lib/pubid/evs/builder.rb +26 -0
  187. data/lib/pubid/evs/identifier.rb +37 -0
  188. data/lib/pubid/evs/identifiers/national_adoption.rb +22 -0
  189. data/lib/pubid/evs/identifiers.rb +9 -0
  190. data/lib/pubid/evs/parser.rb +27 -0
  191. data/lib/pubid/evs/renderer.rb +30 -0
  192. data/lib/pubid/evs/urn_generator.rb +30 -0
  193. data/lib/pubid/evs/urn_parser.rb +80 -0
  194. data/lib/pubid/evs.rb +90 -0
  195. data/lib/pubid/export.rb +1 -0
  196. data/lib/pubid/format_detector.rb +1 -0
  197. data/lib/pubid/gb/builder.rb +14 -9
  198. data/lib/pubid/gb/identifier.rb +29 -7
  199. data/lib/pubid/gb/parser.rb +5 -1
  200. data/lib/pubid/gb/renderer.rb +4 -3
  201. data/lib/pubid/gb.rb +2 -0
  202. data/lib/pubid/gost/builder.rb +46 -9
  203. data/lib/pubid/gost/identifier.rb +0 -2
  204. data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
  205. data/lib/pubid/gost/parser.rb +10 -2
  206. data/lib/pubid/gost.rb +1 -0
  207. data/lib/pubid/iala/identifier.rb +9 -6
  208. data/lib/pubid/iala/parser.rb +10 -2
  209. data/lib/pubid/iala/urn_parser.rb +6 -2
  210. data/lib/pubid/iala.rb +1 -0
  211. data/lib/pubid/iana/builder.rb +3 -1
  212. data/lib/pubid/iana/identifier.rb +74 -6
  213. data/lib/pubid/iana/identifiers/registry.rb +36 -0
  214. data/lib/pubid/iana/parser.rb +1 -1
  215. data/lib/pubid/iana/renderer.rb +3 -0
  216. data/lib/pubid/iana/urn_generator.rb +5 -1
  217. data/lib/pubid/iana.rb +1 -0
  218. data/lib/pubid/identifier.rb +605 -13
  219. data/lib/pubid/identifier_metadata.rb +1 -0
  220. data/lib/pubid/idf/builder.rb +3 -3
  221. data/lib/pubid/idf/identifier.rb +25 -9
  222. data/lib/pubid/idf/identifiers/amendment.rb +1 -1
  223. data/lib/pubid/idf/identifiers/corrigendum.rb +1 -1
  224. data/lib/pubid/idf/identifiers/international_standard.rb +1 -1
  225. data/lib/pubid/idf/identifiers/reviewed_method.rb +1 -1
  226. data/lib/pubid/idf/parser.rb +1 -1
  227. data/lib/pubid/idf/renderer.rb +4 -4
  228. data/lib/pubid/idf/single_identifier.rb +1 -1
  229. data/lib/pubid/idf/urn_generator.rb +1 -1
  230. data/lib/pubid/idf.rb +7 -1
  231. data/lib/pubid/iec/builder.rb +14 -7
  232. data/lib/pubid/iec/components.rb +0 -1
  233. data/lib/pubid/iec/identifier.rb +73 -83
  234. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  235. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  236. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  237. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  238. data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
  239. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  240. data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
  241. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  242. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  243. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  244. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  245. data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
  246. data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
  247. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  248. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  249. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  250. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  251. data/lib/pubid/iec/parser.rb +2 -18
  252. data/lib/pubid/iec/renderer.rb +13 -10
  253. data/lib/pubid/iec/single_identifier.rb +33 -10
  254. data/lib/pubid/iec/urn_generator.rb +227 -61
  255. data/lib/pubid/iec/urn_parser.rb +42 -4
  256. data/lib/pubid/iec.rb +1 -0
  257. data/lib/pubid/ieee/aiee/identifier.rb +2 -2
  258. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  259. data/lib/pubid/ieee/builder.rb +87 -3
  260. data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
  261. data/lib/pubid/ieee/identifiers/base.rb +42 -5
  262. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
  263. data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
  264. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
  265. data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
  266. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
  267. data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
  268. data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
  269. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
  270. data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
  271. data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
  272. data/lib/pubid/ieee/identifiers/si_standard.rb +5 -2
  273. data/lib/pubid/ieee/ire/identifier.rb +2 -2
  274. data/lib/pubid/ieee/ire/parser.rb +20 -2
  275. data/lib/pubid/ieee/nesc/parser.rb +1 -1
  276. data/lib/pubid/ieee/parser.rb +208 -33
  277. data/lib/pubid/ieee/project_renderer.rb +46 -0
  278. data/lib/pubid/ieee/renderer.rb +11 -8
  279. data/lib/pubid/ieee/urn_generator.rb +32 -3
  280. data/lib/pubid/ieee.rb +9 -1
  281. data/lib/pubid/ieee_debug.rb +1 -0
  282. data/lib/pubid/ietf/builder.rb +24 -8
  283. data/lib/pubid/ietf/identifiers/base.rb +25 -28
  284. data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
  285. data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
  286. data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
  287. data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
  288. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  289. data/lib/pubid/ietf/identifiers/std.rb +11 -0
  290. data/lib/pubid/ietf/identifiers.rb +1 -0
  291. data/lib/pubid/ietf/parser.rb +27 -9
  292. data/lib/pubid/ietf/renderer.rb +44 -6
  293. data/lib/pubid/ietf/urn_generator.rb +20 -6
  294. data/lib/pubid/ietf/urn_parser.rb +10 -2
  295. data/lib/pubid/ietf.rb +12 -2
  296. data/lib/pubid/iho/identifiers/base.rb +10 -3
  297. data/lib/pubid/iho/parser.rb +1 -1
  298. data/lib/pubid/iho.rb +1 -0
  299. data/lib/pubid/isbn/identifier.rb +25 -7
  300. data/lib/pubid/isbn/parser.rb +1 -1
  301. data/lib/pubid/isbn.rb +1 -0
  302. data/lib/pubid/iso/builder.rb +10 -11
  303. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  304. data/lib/pubid/iso/combined_identifier.rb +5 -3
  305. data/lib/pubid/iso/components.rb +0 -1
  306. data/lib/pubid/iso/identifier.rb +23 -11
  307. data/lib/pubid/iso/identifiers/directives.rb +7 -4
  308. data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
  309. data/lib/pubid/iso/identifiers/tc_document.rb +31 -46
  310. data/lib/pubid/iso/normalizer.rb +1 -1
  311. data/lib/pubid/iso/parser.rb +1 -1
  312. data/lib/pubid/iso/urn_generator.rb +10 -10
  313. data/lib/pubid/iso.rb +12 -5
  314. data/lib/pubid/itu/builder.rb +10 -0
  315. data/lib/pubid/itu/identifiers/addendum.rb +2 -2
  316. data/lib/pubid/itu/identifiers/amendment.rb +2 -2
  317. data/lib/pubid/itu/identifiers/base.rb +29 -5
  318. data/lib/pubid/itu/identifiers/contribution.rb +31 -0
  319. data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
  320. data/lib/pubid/itu/identifiers/errata.rb +2 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +2 -2
  322. data/lib/pubid/itu/identifiers.rb +1 -0
  323. data/lib/pubid/itu/parser.rb +20 -3
  324. data/lib/pubid/itu.rb +1 -0
  325. data/lib/pubid/jcgm/builder.rb +1 -1
  326. data/lib/pubid/jcgm/identifier.rb +10 -0
  327. data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
  328. data/lib/pubid/jcgm/parser.rb +10 -3
  329. data/lib/pubid/jcgm/renderer.rb +10 -3
  330. data/lib/pubid/jcgm/single_identifier.rb +24 -15
  331. data/lib/pubid/jcgm/urn_generator.rb +1 -1
  332. data/lib/pubid/jcgm/urn_parser.rb +156 -14
  333. data/lib/pubid/jcgm.rb +10 -0
  334. data/lib/pubid/jis/identifier.rb +10 -3
  335. data/lib/pubid/jis/parser.rb +1 -1
  336. data/lib/pubid/jis.rb +1 -0
  337. data/lib/pubid/nist/builder.rb +12 -12
  338. data/lib/pubid/nist/components/stage.rb +2 -2
  339. data/lib/pubid/nist/configuration.rb +6 -8
  340. data/lib/pubid/nist/identifiers/base.rb +22 -5
  341. data/lib/pubid/nist/identifiers/circular.rb +9 -2
  342. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  343. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  344. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
  345. data/lib/pubid/nist/identifiers/crpl_report.rb +12 -7
  346. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +2 -2
  347. data/lib/pubid/nist/identifiers/handbook.rb +9 -2
  348. data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
  349. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +16 -8
  350. data/lib/pubid/nist/identifiers/monograph.rb +14 -7
  351. data/lib/pubid/nist/identifiers/report.rb +14 -6
  352. data/lib/pubid/nist/parser.rb +1 -1
  353. data/lib/pubid/nist/series/ir.rb +3 -7
  354. data/lib/pubid/nist/supplement_identifier.rb +16 -1
  355. data/lib/pubid/nist.rb +7 -1
  356. data/lib/pubid/oasis/builder.rb +12 -10
  357. data/lib/pubid/oasis/identifier.rb +89 -11
  358. data/lib/pubid/oasis/parser.rb +1 -1
  359. data/lib/pubid/oasis.rb +7 -1
  360. data/lib/pubid/ogc/identifier.rb +9 -5
  361. data/lib/pubid/ogc/parser.rb +1 -1
  362. data/lib/pubid/ogc.rb +1 -0
  363. data/lib/pubid/oiml/builder.rb +7 -3
  364. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  365. data/lib/pubid/oiml/identifiers/bulletin.rb +40 -10
  366. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  367. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  368. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  369. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  370. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  371. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  372. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  373. data/lib/pubid/oiml/identifiers.rb +1 -0
  374. data/lib/pubid/oiml/parser.rb +8 -3
  375. data/lib/pubid/oiml/renderer.rb +3 -3
  376. data/lib/pubid/oiml/single_identifier.rb +26 -42
  377. data/lib/pubid/oiml/supplement_identifier.rb +27 -0
  378. data/lib/pubid/oiml/urn_generator.rb +4 -4
  379. data/lib/pubid/oiml.rb +7 -1
  380. data/lib/pubid/omg/builder.rb +1 -0
  381. data/lib/pubid/omg/identifier.rb +20 -3
  382. data/lib/pubid/omg/parser.rb +64 -11
  383. data/lib/pubid/omg/renderer.rb +13 -1
  384. data/lib/pubid/omg.rb +2 -1
  385. data/lib/pubid/parser/grammar.rb +74 -0
  386. data/lib/pubid/parser.rb +2 -0
  387. data/lib/pubid/parsers/mr_string.rb +19 -0
  388. data/lib/pubid/plateau/parser.rb +1 -1
  389. data/lib/pubid/plateau.rb +10 -0
  390. data/lib/pubid/prefixes_support.rb +1 -0
  391. data/lib/pubid/renderers/annotator.rb +233 -0
  392. data/lib/pubid/renderers/base.rb +13 -0
  393. data/lib/pubid/renderers/directives_renderer.rb +6 -4
  394. data/lib/pubid/renderers/human_readable.rb +3 -3
  395. data/lib/pubid/renderers/mr_string.rb +15 -9
  396. data/lib/pubid/renderers.rb +1 -0
  397. data/lib/pubid/rendering/numbering.rb +25 -7
  398. data/lib/pubid/rendering.rb +1 -0
  399. data/lib/pubid/sae/builder.rb +1 -1
  400. data/lib/pubid/sae/identifiers/base.rb +13 -3
  401. data/lib/pubid/sae/parser.rb +1 -1
  402. data/lib/pubid/sae/urn_generator.rb +1 -1
  403. data/lib/pubid/sae.rb +1 -0
  404. data/lib/pubid/schema/declaration.rb +33 -0
  405. data/lib/pubid/schema/error.rb +14 -0
  406. data/lib/pubid/schema/identifier_type.rb +23 -0
  407. data/lib/pubid/schema/loader.rb +117 -0
  408. data/lib/pubid/schema/typed_stage.rb +24 -0
  409. data/lib/pubid/schema.rb +25 -0
  410. data/lib/pubid/tgpp/builder.rb +1 -1
  411. data/lib/pubid/tgpp/identifier.rb +21 -5
  412. data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
  413. data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
  414. data/lib/pubid/tgpp/parser.rb +22 -6
  415. data/lib/pubid/tgpp/renderer.rb +21 -5
  416. data/lib/pubid/tgpp/urn_generator.rb +27 -8
  417. data/lib/pubid/tgpp/urn_parser.rb +8 -6
  418. data/lib/pubid/tgpp.rb +7 -1
  419. data/lib/pubid/type_resolver.rb +16 -1
  420. data/lib/pubid/un/identifier.rb +6 -3
  421. data/lib/pubid/un/parser.rb +1 -1
  422. data/lib/pubid/un.rb +1 -0
  423. data/lib/pubid/urn_parser/errors.rb +8 -1
  424. data/lib/pubid/urn_parser.rb +1 -0
  425. data/lib/pubid/utils.rb +1 -0
  426. data/lib/pubid/version.rb +1 -1
  427. data/lib/pubid/w3c/builder.rb +5 -5
  428. data/lib/pubid/w3c/identifier.rb +38 -9
  429. data/lib/pubid/w3c/parser.rb +1 -1
  430. data/lib/pubid/w3c/renderer.rb +1 -1
  431. data/lib/pubid/w3c/urn_generator.rb +2 -2
  432. data/lib/pubid/w3c.rb +1 -0
  433. data/lib/pubid/xsf/identifier.rb +9 -5
  434. data/lib/pubid/xsf/parser.rb +17 -4
  435. data/lib/pubid/xsf.rb +7 -1
  436. data/lib/pubid.rb +399 -21
  437. data/lib/tasks/conformance.rake +34 -0
  438. data/lib/tasks/docs.rake +16 -14
  439. data/lib/tasks/schema.rake +88 -0
  440. data/schema/core/joint_prefixes.yaml +24 -0
  441. data/schema/iec.yaml +1017 -0
  442. data/schema/iso.yaml +1586 -0
  443. data/schema/schema.schema.yaml +96 -0
  444. metadata +40 -19
  445. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  446. data/archived-gems/pubid-iec/stages.yaml +0 -129
  447. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  448. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  449. data/archived-gems/pubid-iso/stages.yaml +0 -106
  450. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  451. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  452. data/archived-gems/pubid-itu/series.yaml +0 -42
  453. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  454. data/archived-gems/pubid-nist/series.yaml +0 -121
  455. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  456. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  457. data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +0 -70
  458. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  459. data/lib/pubid/iec/components/code.rb +0 -36
  460. data/lib/pubid/iso/components/code.rb +0 -24
  461. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
@@ -143,7 +143,7 @@ module Pubid
143
143
  return nil unless year_value.between?(1900, 2099)
144
144
 
145
145
  {
146
- number: code_class.new(value: number),
146
+ number: number,
147
147
  date: ::Pubid::Components::Date.new(year: part),
148
148
  }
149
149
  end
@@ -197,7 +197,7 @@ module Pubid
197
197
  # or "105/F" ('F' is part)
198
198
  # or "5843/6" ('6' is part)
199
199
  # LEGACY: "4037-1979" (number-year, year should become date)
200
- parse_number_with_part(value, code_class: Pubid::Iso::Components::Code)
200
+ parse_number_with_part(value)
201
201
 
202
202
  when :directives_type
203
203
  # nothing to do here, just return nil
@@ -240,8 +240,10 @@ module Pubid
240
240
  original_text = value.to_s
241
241
  # Extract just the digit(s) for the number field
242
242
  number_string = original_text.match(/\d+/)&.to_s
243
- number_code = number_string ? Pubid::Iso::Components::Code.new(value: number_string) : nil
244
- Pubid::Components::Edition.new(number: number_code,
243
+ # A plain string: Components::Edition#number is typed Value, so a
244
+ # component here would leak a live Ruby object into to_hash (and a
245
+ # !ruby/object tag into to_yaml).
246
+ Pubid::Components::Edition.new(number: number_string,
245
247
  original_text: original_text)
246
248
 
247
249
  when :languages
@@ -260,8 +262,7 @@ module Pubid
260
262
 
261
263
  when :subgroup
262
264
  # Handle JTC 1 subgroup in directives (ISO/IEC JTC 1 DIR)
263
- # Store as a component for potential use in rendering
264
- Pubid::Iso::Components::Code.new(value: value.to_s)
265
+ value.to_s
265
266
 
266
267
  when :supplements
267
268
  # Handle bundled supplements (+ operator)
@@ -274,12 +275,10 @@ module Pubid
274
275
 
275
276
  # TC Document attributes
276
277
  when :tc_type, :sc_type, :wg_type
277
- # TC, SC, WG types are code components
278
- Pubid::Iso::Components::Code.new(value: value.to_s)
278
+ value.to_s
279
279
 
280
280
  when :tc_number, :sc_number, :wg_number
281
- # TC, SC, WG numbers are code components
282
- Pubid::Iso::Components::Code.new(value: value.to_s)
281
+ value.to_s
283
282
 
284
283
  when :year
285
284
  # For TC documents with year, convert to Date
@@ -290,7 +289,7 @@ module Pubid
290
289
  # For regular identifiers, this is handled in :number_with_part
291
290
  if value.is_a?(Parslet::Slice) || value.is_a?(String) ||
292
291
  value.is_a?(Integer)
293
- Pubid::Iso::Components::Code.new(value: value.to_s)
292
+ value.to_s
294
293
  else
295
294
  value
296
295
  end
@@ -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
@@ -3,7 +3,6 @@
3
3
  module Pubid
4
4
  module Iso
5
5
  module Components
6
- autoload :Code, "#{__dir__}/components/code"
7
6
  autoload :Publisher, "#{__dir__}/components/publisher"
8
7
  end
9
8
  end
@@ -56,9 +56,14 @@ module Pubid
56
56
  ts ? dup.tap { |id| id.typed_stage = ts } : dup
57
57
  end
58
58
 
59
- attribute :number, ::Pubid::Iso::Components::Code
60
- attribute :part, ::Pubid::Iso::Components::Code
61
- attribute :subpart, ::Pubid::Iso::Components::Code
59
+ # Plain strings. Iso::Components::Code existed to join `parts` with
60
+ # "-", a composition no ISO identifier ever reached: `parts` is never
61
+ # written in lib/pubid/iso and no Code in the 7,613-id corpus carries
62
+ # anything but `value`. ISO part and subpart are sibling attributes, not
63
+ # fields of the number.
64
+ attribute :number, :string
65
+ attribute :part, :string
66
+ attribute :subpart, :string
62
67
 
63
68
  # Polymorphic type map for lutaml::Model key_value serialization
64
69
  # Maps polymorphic_name → class name for deserialization
@@ -166,9 +171,14 @@ module Pubid
166
171
  def stage_from_kv(model, value)
167
172
  return if value.nil? || value.to_s.empty?
168
173
 
174
+ # The fallback consults the flavor-wide table. It used to call
175
+ # `Pubid::Iso::Scheme`, a class removed repo-wide in e3c19ea1 — so any
176
+ # code absent from the class's own TYPED_STAGES raised NameError
177
+ # instead of falling back. The IEC twin (iec/identifier.rb) was
178
+ # migrated at the time; ISO was missed.
169
179
  ts = (model.class.const_defined?(:TYPED_STAGES) &&
170
180
  model.class::TYPED_STAGES.find { |t| t.code.to_s == value.to_s }) ||
171
- Pubid::Iso::Scheme.locate_typed_stage_by_code(value)
181
+ Pubid::Iso.locate_stage_by_code(value)
172
182
  return unless ts
173
183
 
174
184
  # The renderer prefers `original_abbr` (the parsed surface form); without
@@ -208,8 +218,10 @@ module Pubid
208
218
  doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
209
219
  end
210
220
 
221
+ # number/part/subpart are plain strings; the converter name is kept
222
+ # so the key_value map below does not have to change.
211
223
  def build_code(value)
212
- ::Pubid::Iso::Components::Code.new(value: value.to_s)
224
+ value.to_s
213
225
  end
214
226
 
215
227
  # --- date serialized flat as year/month/day ---
@@ -283,8 +295,13 @@ module Pubid
283
295
  end
284
296
 
285
297
  def self.parse(string, format: :auto)
298
+ unless string.is_a?(String)
299
+ raise Pubid::Errors::InvalidInputError,
300
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
301
+ end
302
+
286
303
  if string.length > Pubid::MAX_INPUT_LENGTH
287
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
304
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
288
305
  end
289
306
 
290
307
  format = Pubid::FormatDetector.detect(string) if format == :auto
@@ -296,11 +313,6 @@ module Pubid
296
313
  Pubid::Parsers::MrString.parse(string)
297
314
  else
298
315
  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
316
  Pubid::Iso::Builder.new.build(parsed)
305
317
  end
306
318
  end
@@ -4,7 +4,10 @@ module Pubid
4
4
  module Iso
5
5
  module Identifiers
6
6
  class Directives < SingleIdentifier
7
- attribute :subgroup, ::Pubid::Components::Code
7
+ # A plain string ("JTC 1"). The serialized form flattens from
8
+ # `{"value" => "JTC 1"}` to `"JTC 1"`, so the 5 directives rows of
9
+ # relaton-data-iso need a re-crawl; no compatibility shim is kept.
10
+ attribute :subgroup, :string
8
11
 
9
12
  # Merges with Identifier's block (base attributes); only adds the
10
13
  # Directives-specific subgroup so it survives to_hash/from_hash.
@@ -46,15 +49,15 @@ module Pubid
46
49
  parts << ([publisher] + copubs).map(&:body).map(&:downcase).join("-")
47
50
 
48
51
  if subgroup
49
- subgroup_parts = subgroup.value.split
52
+ subgroup_parts = subgroup.split
50
53
  parts << subgroup_parts[0].downcase if subgroup_parts[0]
51
54
  parts << subgroup_parts[1] if subgroup_parts[1]
52
55
  end
53
56
 
54
57
  parts << "dir"
55
58
 
56
- parts << number.value if number
57
- parts << part.value.downcase if part
59
+ parts << number.to_s if number
60
+ parts << part.to_s.downcase if part
58
61
  parts << date.year if date
59
62
 
60
63
  parts.join(":")
@@ -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}"
@@ -6,18 +6,15 @@ module Pubid
6
6
  # Technical Committee Document
7
7
  # Format: TC 184/SC 4/WG 3 N 123, JTC 1 N 456, TC 184 N 100
8
8
  class TcDocument < Identifier
9
- # TC type (TC, JTC, PC, IT, etc.)
10
- attribute :tc_type, ::Pubid::Components::Code
11
- # TC number
12
- attribute :tc_number, ::Pubid::Components::Code
13
- # SC type
14
- attribute :sc_type, ::Pubid::Components::Code
15
- # SC number
16
- attribute :sc_number, ::Pubid::Components::Code
17
- # WG type
18
- attribute :wg_type, ::Pubid::Components::Code
19
- # WG number
20
- attribute :wg_number, ::Pubid::Components::Code
9
+ # The committee structure: plain strings ("TC", "184", "SC", "4").
10
+ # Each held a Components::Code carrying nothing but `value`, and the
11
+ # serialized form was already the bare scalar.
12
+ attribute :tc_type, :string
13
+ attribute :tc_number, :string
14
+ attribute :sc_type, :string
15
+ attribute :sc_number, :string
16
+ attribute :wg_type, :string
17
+ attribute :wg_number, :string
21
18
 
22
19
  # TC types from ISO system
23
20
  TC_TYPES = %w[TC JTC PC IT CAB CASCO COPOLCO COUNCIL CPSG CS DEVCO GA
@@ -33,33 +30,21 @@ module Pubid
33
30
  # TC documents don't use typed stages like other identifiers
34
31
  TYPED_STAGES = [].freeze
35
32
 
36
- # Serialize the committee structure (all plain-string Codes) on top of
37
- # the inherited ISO mapping; TC documents have no stage.
33
+ # Serialize the committee structure on top of the inherited ISO
34
+ # mapping; TC documents have no stage. The attributes are plain
35
+ # strings, so lutaml needs no converter (the ETSI/OIML shape).
38
36
  key_value do
39
- map "tc_type", with: { to: :tc_type_to_kv, from: :tc_type_from_kv }
40
- map "tc_number", with: { to: :tc_number_to_kv, from: :tc_number_from_kv }
41
- map "sc_type", with: { to: :sc_type_to_kv, from: :sc_type_from_kv }
42
- map "sc_number", with: { to: :sc_number_to_kv, from: :sc_number_from_kv }
43
- map "wg_type", with: { to: :wg_type_to_kv, from: :wg_type_from_kv }
44
- map "wg_number", with: { to: :wg_number_to_kv, from: :wg_number_from_kv }
37
+ map "tc_type", to: :tc_type
38
+ map "tc_number", to: :tc_number
39
+ map "sc_type", to: :sc_type
40
+ map "sc_number", to: :sc_number
41
+ map "wg_type", to: :wg_type
42
+ map "wg_number", to: :wg_number
45
43
  end
46
44
 
47
45
  # TC documents have no stage; suppress the inherited stage emission.
48
46
  def stage_to_kv(_model, _doc); end
49
47
 
50
- def tc_type_to_kv(m, doc) = emit_code(doc, "tc_type", m.tc_type)
51
- def tc_type_from_kv(m, v) = m.tc_type = build_code(v)
52
- def tc_number_to_kv(m, doc) = emit_code(doc, "tc_number", m.tc_number)
53
- def tc_number_from_kv(m, v) = m.tc_number = build_code(v)
54
- def sc_type_to_kv(m, doc) = emit_code(doc, "sc_type", m.sc_type)
55
- def sc_type_from_kv(m, v) = m.sc_type = build_code(v)
56
- def sc_number_to_kv(m, doc) = emit_code(doc, "sc_number", m.sc_number)
57
- def sc_number_from_kv(m, v) = m.sc_number = build_code(v)
58
- def wg_type_to_kv(m, doc) = emit_code(doc, "wg_type", m.wg_type)
59
- def wg_type_from_kv(m, v) = m.wg_type = build_code(v)
60
- def wg_number_to_kv(m, doc) = emit_code(doc, "wg_number", m.wg_number)
61
- def wg_number_from_kv(m, v) = m.wg_number = build_code(v)
62
-
63
48
  def self.type
64
49
  { key: :tc,
65
50
  web: :tc_document, title: "Technical Committee Document", short: "TC" }
@@ -73,23 +58,23 @@ module Pubid
73
58
  result = publisher.to_s if publisher
74
59
 
75
60
  # Add TC type and number
76
- result += "/#{tc_type.render} " if tc_type&.value
77
- result += tc_number.render.to_s if tc_number&.value
61
+ result += "/#{tc_type} " unless tc_type.to_s.empty?
62
+ result += tc_number.to_s unless tc_number.to_s.empty?
78
63
 
79
64
  # Add SC type and number
80
- if sc_type&.value && sc_number&.value
81
- result += "/#{sc_type.render} "
82
- result += sc_number.render.to_s
65
+ unless sc_type.to_s.empty? || sc_number.to_s.empty?
66
+ result += "/#{sc_type} "
67
+ result += sc_number.to_s
83
68
  end
84
69
 
85
70
  # Add WG type and number
86
- if wg_type&.value && wg_number&.value
87
- result += "/#{wg_type.render} "
88
- result += wg_number.render.to_s
71
+ unless wg_type.to_s.empty? || wg_number.to_s.empty?
72
+ result += "/#{wg_type} "
73
+ result += wg_number.to_s
89
74
  end
90
75
 
91
76
  # Add document number
92
- result += " N #{number.render}" if number&.value
77
+ result += " N #{number}" unless number.to_s.empty?
93
78
 
94
79
  # Add year if present
95
80
  result += ":#{date.render}" if date&.year
@@ -105,16 +90,16 @@ module Pubid
105
90
  parts << publisher.render(context: urn_ctx) if publisher
106
91
 
107
92
  # Add TC
108
- parts << "tc:#{tc_number.render(context: urn_ctx)}" if tc_number&.value
93
+ parts << "tc:#{tc_number}" unless tc_number.to_s.empty?
109
94
 
110
95
  # Add SC
111
- parts << "sc-#{sc_number.render(context: urn_ctx)}" if sc_number&.value
96
+ parts << "sc-#{sc_number}" unless sc_number.to_s.empty?
112
97
 
113
98
  # Add WG
114
- parts << "wg-#{wg_number.render(context: urn_ctx)}" if wg_number&.value
99
+ parts << "wg-#{wg_number}" unless wg_number.to_s.empty?
115
100
 
116
101
  # Add document number
117
- parts << number.render(context: urn_ctx) if number&.value
102
+ parts << number.to_s unless number.to_s.empty?
118
103
 
119
104
  parts.join(":")
120
105
  end
@@ -73,7 +73,7 @@ module Pubid
73
73
 
74
74
  addendum = Identifiers::Addendum.new
75
75
  addendum.base = base
76
- addendum.number = Iso::Components::Code.new(value: supplement_number)
76
+ addendum.number = supplement_number
77
77
  addendum.date = Pubid::Components::Date.new(year: supplement_year) if supplement_year
78
78
 
79
79
  typed_stage = Pubid::Iso.locate_stage(stage_abbr)
@@ -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
 
@@ -63,7 +63,7 @@ module Pubid
63
63
  parts << originator_component
64
64
  type_comp = type_component
65
65
  parts << type_comp if type_comp
66
- parts << identifier.number.render(context: URN_CONTEXT) if identifier.number
66
+ parts << identifier.number.to_s if identifier.number
67
67
  part_comp = part_component
68
68
  parts << part_comp if part_comp
69
69
  stage_comp = stage_component
@@ -95,7 +95,7 @@ module Pubid
95
95
  parts << base_gen.originator_component
96
96
  type_comp = base_gen.type_component
97
97
  parts << type_comp if type_comp
98
- parts << base_id.number.render(context: URN_CONTEXT) if base_id.number
98
+ parts << base_id.number.to_s if base_id.number
99
99
  part_comp = base_gen.part_component
100
100
  parts << part_comp if part_comp
101
101
 
@@ -138,13 +138,13 @@ module Pubid
138
138
  parts << supp.date.render(context: URN_CONTEXT)
139
139
  if supp.number
140
140
  if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
141
- parts << "v#{supp.number.render(context: URN_CONTEXT)}.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
141
+ parts << "v#{supp.number}.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
142
142
  else
143
- parts << "v#{supp.number.render(context: URN_CONTEXT)}"
143
+ parts << "v#{supp.number}"
144
144
  end
145
145
  end
146
146
  else
147
- parts << supp.number.render(context: URN_CONTEXT) if supp.number
147
+ parts << supp.number.to_s if supp.number
148
148
  if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
149
149
  parts << "v1.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
150
150
  else
@@ -197,8 +197,8 @@ module Pubid
197
197
  def part_component
198
198
  return nil unless identifier.part
199
199
 
200
- result = "-#{identifier.part.render(context: URN_CONTEXT)}"
201
- result += "-#{identifier.subpart.render(context: URN_CONTEXT)}" if identifier.subpart
200
+ result = "-#{identifier.part}"
201
+ result += "-#{identifier.subpart}" if identifier.subpart
202
202
  result
203
203
  end
204
204
 
@@ -292,13 +292,13 @@ module Pubid
292
292
  parts << identifier.date.render(context: URN_CONTEXT)
293
293
  if identifier.number
294
294
  parts << if identifier.stage_iteration
295
- "v#{identifier.number.render(context: URN_CONTEXT)}.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
295
+ "v#{identifier.number}.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
296
296
  else
297
- "v#{identifier.number.render(context: URN_CONTEXT)}"
297
+ "v#{identifier.number}"
298
298
  end
299
299
  end
300
300
  else
301
- parts << identifier.number.render(context: URN_CONTEXT) if identifier.number
301
+ parts << identifier.number.to_s if identifier.number
302
302
  parts << if identifier.stage_iteration
303
303
  "v1.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
304
304
  else
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
@@ -60,7 +66,7 @@ module Pubid
60
66
  # @param type [Symbol] the type key (e.g. :is, :tr, :ts, :guide)
61
67
  # @param publisher [String, Pubid::Iso::Components::Publisher] primary publisher
62
68
  # @param copublishers [Array<String>, Array<Pubid::Components::Publisher>]
63
- # @param number [String, Integer, Pubid::Iso::Components::Code]
69
+ # @param number [String, Integer]
64
70
  # @param year [String, Integer, Pubid::Components::Date, nil]
65
71
  # @param attrs [Hash] additional identifier attributes
66
72
  # @return [Pubid::Iso::Identifier]
@@ -100,10 +106,11 @@ module Pubid
100
106
  private_class_method :build_copublishers
101
107
 
102
108
  # @!visibility private
109
+ # number/part/subpart are plain strings. A caller that still passes a
110
+ # Components::Code (another flavor's builder, a hand-built id) is read
111
+ # through its own #to_s rather than refused.
103
112
  def self.build_code(value)
104
- return value if value.is_a?(Components::Code)
105
-
106
- Components::Code.new(value: value.to_s)
113
+ value.to_s
107
114
  end
108
115
  private_class_method :build_code
109
116
 
@@ -68,6 +68,16 @@ module Pubid
68
68
  return build_question(data)
69
69
  end
70
70
 
71
+ # Contribution (Temporary Document) — "ITU-R SG17-C1000" (pubid#340).
72
+ if data[:contribution_marker]
73
+ return Identifiers::Contribution.new(
74
+ sector: Components::Sector.new(sector: data[:sector].to_s),
75
+ series: Components::Series.new(series: data[:series].to_s),
76
+ code: build_code(data),
77
+ language: data[:language]&.to_s,
78
+ )
79
+ end
80
+
71
81
  # Build basic recommendation or combined identifier
72
82
  sector = Components::Sector.new(sector: data[:sector].to_s)
73
83
  series = Components::Series.new(series: data[:series].to_s) if data[:series]
@@ -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
@@ -26,6 +37,16 @@ module Pubid
26
37
  end
27
38
  private_class_method :normalize_whitespace
28
39
 
40
+ # The type key used by Pubid::Itu.locate_type — the class name
41
+ # ("Contribution" => :contribution). No ITU leaf ever defined a
42
+ # `type` hash, so locate_type raised NoMethodError on every call;
43
+ # the derived default gives every concrete leaf a key for free
44
+ # (pubid#340's ask). metanorma-itu constructs via this lookup.
45
+ def self.type
46
+ leaf = name.split("::").last
47
+ { key: leaf.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym }
48
+ end
49
+
29
50
  # Long-form ↔ ITU single-letter language code map. The parser produces
30
51
  # single-letter codes (E/F/S/R/A/C); API callers (e.g. metanorma-itu)
31
52
  # pass long-form (en/fr/es/ru/ar/zh). Storage is normalized to the
@@ -184,10 +205,13 @@ module Pubid
184
205
  # @param format [Symbol] :long for title-style rendering of supported
185
206
  # identifiers, otherwise the default short form.
186
207
  def to_s(**opts)
208
+ annotated = opts[:annotated]
187
209
  opts = self.class.normalize_to_s_opts(opts)
188
210
  result = render_base(**opts) + render_language_suffix
189
211
  result += " | #{common_text_twin}" if common_text_twin
190
- result
212
+ # ITU composes its own string rather than going through `render`, so it
213
+ # never reaches the shared annotation hook. Apply it here.
214
+ annotate_plain_render(result, annotated: annotated)
191
215
  end
192
216
 
193
217
  def render_base(**_opts)
@@ -0,0 +1,31 @@
1
+ # frozen_string: true
2
+
3
+ module Pubid
4
+ module Itu
5
+ module Identifiers
6
+ # ITU Contribution (Temporary Document) — the working documents a study
7
+ # group circulates, numbered per study group.
8
+ #
9
+ # Format: ITU-{SECTOR} {SERIES}-C{NUMBER} e.g. ITU-R SG17-C1000
10
+ #
11
+ # Mirrors pubid-itu 1.15's Pubid::Itu::Identifier::Contribution
12
+ # ("%{series}-C%{number}"), which metanorma-itu builds from
13
+ # `:doctype: contribution` documents (pubid#340).
14
+ class Contribution < Identifier
15
+ include StandardSerialization
16
+
17
+ def render_base(**_opts)
18
+ "#{publisher}-#{sector} #{series}-C#{code&.number}"
19
+ end
20
+
21
+ def ==(other)
22
+ return false unless other.is_a?(Contribution)
23
+
24
+ sector == other.sector &&
25
+ series == other.series &&
26
+ code == other.code
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -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