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
@@ -41,9 +41,9 @@ module Pubid
41
41
  number = parts.shift
42
42
  part = parts.shift
43
43
  subpart = parts.size.positive? ? parts.join("-") : nil
44
- code_hash = { number: Components::Code.new(value: number) }
45
- code_hash[:part] = Components::Code.new(value: part) if part
46
- code_hash[:subpart] = Components::Code.new(value: subpart) if subpart
44
+ code_hash = { number: number }
45
+ code_hash[:part] = part if part
46
+ code_hash[:subpart] = subpart if subpart
47
47
  code_hash
48
48
  when :type_with_stage
49
49
  iteration = value.to_s.match(/(\d+)$/)
@@ -5,8 +5,24 @@ module Pubid
5
5
  module Idf
6
6
  # An IDF identifier has no copublisher
7
7
  class Identifier < ::Pubid::Identifier
8
+ # A Type INSTANCE, never the raw :key symbol - lutaml materializes
9
+ # defaults during from_hash; casting a Symbol into the
10
+ # component raises InvalidFormatError (pubid#383).
11
+ def self.default_type
12
+ Components::Type.new(abbr: type[:short])
13
+ end
14
+
8
15
  attribute :typed_stage, Components::TypedStage
9
16
 
17
+ # `number`/`part`/`subpart` are declared here rather than inherited as a
18
+ # Components::Code: IDF stores a bare string in every one of them.
19
+ # Declaring on this class is safe because its body lives in this one file
20
+ # and is never reopened, so every subclass body opens after it has run
21
+ # (lutaml deep-dups the parent attribute table at class-definition time).
22
+ attribute :number, :string
23
+ attribute :part, :string
24
+ attribute :subpart, :string
25
+
10
26
  def to_s(**opts)
11
27
  render(format: :human, **opts)
12
28
  end
@@ -21,11 +37,11 @@ module Pubid
21
37
  def number_portion(lang_single: false)
22
38
  [
23
39
  # Directives may not have a number
24
- (number ? " #{number.value}" : ""),
40
+ (number ? " #{number}" : ""),
25
41
 
26
42
  # Parts and subparts are optional
27
- (part ? "-#{part.value}" : ""),
28
- (subpart ? "-#{subpart.value}" : ""),
43
+ (part ? "-#{part}" : ""),
44
+ (subpart ? "-#{subpart}" : ""),
29
45
 
30
46
  # Stage iteration is optional
31
47
  (stage_iteration ? ".#{stage_iteration.number}" : ""),
@@ -53,16 +69,16 @@ module Pubid
53
69
  end
54
70
 
55
71
  def self.parse(string)
56
- if string.length > Pubid::MAX_INPUT_LENGTH
57
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
72
+ unless string.is_a?(String)
73
+ raise Pubid::Errors::InvalidInputError,
74
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
58
75
  end
59
76
 
60
- parsed = Pubid::Idf::Parser.new.parse(string)
61
- if parsed.nil? || parsed.empty?
62
- raise Pubid::Idf::Parser::ParseError,
63
- "Invalid identifier format"
77
+ if string.length > Pubid::MAX_INPUT_LENGTH
78
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
64
79
  end
65
80
 
81
+ parsed = Pubid::Idf::Parser.new.parse(string)
66
82
  Pubid::Idf::Builder.new.build(parsed)
67
83
  end
68
84
  end
@@ -4,7 +4,7 @@ module Pubid
4
4
  module Idf
5
5
  module Identifiers
6
6
  class Amendment < SupplementIdentifier
7
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
7
+ attribute :type, Components::Type, default: -> { self.class.default_type }
8
8
 
9
9
  TYPED_STAGES = [
10
10
  Components::TypedStage.new(
@@ -4,7 +4,7 @@ module Pubid
4
4
  module Idf
5
5
  module Identifiers
6
6
  class Corrigendum < SupplementIdentifier
7
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
7
+ attribute :type, Components::Type, default: -> { self.class.default_type }
8
8
 
9
9
  TYPED_STAGES = [
10
10
  Components::TypedStage.new(
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # International Standard Identifier
7
7
  class InternationalStandard < SingleIdentifier
8
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
8
+ attribute :type, Components::Type, default: -> { self.class.default_type }
9
9
 
10
10
  TYPED_STAGES = [
11
11
  Components::TypedStage.new(
@@ -4,7 +4,7 @@ module Pubid
4
4
  module Idf
5
5
  module Identifiers
6
6
  class ReviewedMethod < SingleIdentifier
7
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
7
+ attribute :type, Components::Type, default: -> { self.class.default_type }
8
8
  TYPED_STAGES = [
9
9
  Components::TypedStage.new(
10
10
  code: :pwirm,
@@ -4,7 +4,7 @@ require "parslet"
4
4
 
5
5
  module Pubid
6
6
  module Idf
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
 
@@ -43,9 +43,9 @@ module Pubid
43
43
  lang_single = opts[:lang_single] || false
44
44
 
45
45
  [
46
- (id.number ? " #{id.number.render(context:)}" : ""),
47
- (id.part ? "-#{id.part.render(context:)}" : ""),
48
- (id.subpart ? "-#{id.subpart.render(context:)}" : ""),
46
+ (id.number ? " #{id.number}" : ""),
47
+ (id.part ? "-#{id.part}" : ""),
48
+ (id.subpart ? "-#{id.subpart}" : ""),
49
49
  (id.stage_iteration ? ".#{id.stage_iteration.render(context:)}" : ""),
50
50
  (id.date ? ":#{id.date.render(context:)}" : ""),
51
51
  language_portion(id, lang_single: lang_single),
@@ -75,7 +75,7 @@ module Pubid
75
75
  "/",
76
76
  id.typed_stage.abbreviation,
77
77
  " ",
78
- id.number.render(context:),
78
+ id.number,
79
79
  (id.date ? ":#{id.date.render(context:)}" : ""),
80
80
  ].join
81
81
  end
@@ -12,7 +12,7 @@ module Pubid
12
12
  #
13
13
  # Note: The type attribute is inherited from the base Identifier class.
14
14
  # Concrete classes should add their own default value like:
15
- # attribute :type, Components::Type, default: -> { self.class.type[:key] }
15
+ # attribute :type, Components::Type, default: -> { self.class.default_type }
16
16
  class SingleIdentifier < Identifier
17
17
  end
18
18
  end
@@ -38,7 +38,7 @@ module Pubid
38
38
  end
39
39
 
40
40
  if identifier.number
41
- parts << identifier.number.render(context: URN_CONTEXT)
41
+ parts << identifier.number
42
42
  end
43
43
  end
44
44
 
data/lib/pubid/idf.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  module Idf
5
6
  extend Pubid::PrefixesSupport
@@ -18,8 +19,13 @@ module Pubid
18
19
  autoload :UrnParser, "#{__dir__}/idf/urn_parser"
19
20
 
20
21
  def self.parse(identifier)
22
+ unless identifier.is_a?(String)
23
+ raise Pubid::Errors::InvalidInputError,
24
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
25
+ end
26
+
21
27
  if identifier.length > Pubid::MAX_INPUT_LENGTH
22
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
28
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
23
29
  end
24
30
 
25
31
  parser = Parser.new
@@ -59,7 +59,7 @@ module Pubid
59
59
  supplement = identifier_class.new
60
60
  supp_attrs = identifier_class.attributes
61
61
  if supp_attrs.key?(:number)
62
- supplement.number = Components::Code.new(value: supplement_number.to_s)
62
+ supplement.number = supplement_number.to_s
63
63
  end
64
64
  if supplement_date && supp_attrs.key?(:date)
65
65
  supplement.date = cast(:date, supplement_date)
@@ -151,7 +151,15 @@ module Pubid
151
151
 
152
152
  assign_attributes(identifier, parsed_hash)
153
153
 
154
- # Detect rendering style from parsed abbreviation
154
+ # Detect rendering style from parsed abbreviation.
155
+ #
156
+ # UNREACHABLE TODAY: no IEC identifier class declares a
157
+ # `rendering_style` attribute, so this whole block never runs. Its
158
+ # `original_abbr` reads below are therefore NOT a live consumer of that
159
+ # field — which is why `original_abbr` can be left nil on both the parse
160
+ # and the from_hash paths (see Identifier.published_typed_stage). The
161
+ # long-vs-short stage spelling is already collapsed: "…/Amd 1:2017"
162
+ # renders back as "…/AMD1:2017". Do not treat this as working code.
155
163
  if identifier.class.attributes.key?(:rendering_style) && identifier.typed_stage
156
164
  ts = identifier.typed_stage
157
165
 
@@ -288,12 +296,12 @@ module Pubid
288
296
 
289
297
  if type == "AMD"
290
298
  Identifiers::Amendment.new(
291
- number: Components::Code.new(value: number),
299
+ number: number,
292
300
  date: date_component,
293
301
  )
294
302
  elsif type == "COR"
295
303
  Identifiers::Corrigendum.new(
296
- number: Components::Code.new(value: number),
304
+ number: number,
297
305
  date: date_component,
298
306
  )
299
307
  end
@@ -371,15 +379,14 @@ module Pubid
371
379
 
372
380
  when :number
373
381
  # Plain number for sub-org identifiers (CA, IECQ CS, IECQ OD)
374
- # Just return as Code component
375
- { number: Components::Code.new(value: value.to_s) }
382
+ { number: value.to_s }
376
383
 
377
384
  when :number_with_part
378
385
  # "60038" (no part)
379
386
  # or "60038-1" ('1' is part)
380
387
  # or "60038-1-2" ('1' is part, '2' is subpart)
381
388
  # or "29110-5-1-1" ('5' is part, '1-1' is subpart)
382
- parse_number_with_part(value, code_class: Components::Code)
389
+ parse_number_with_part(value)
383
390
 
384
391
  when :type_with_stage
385
392
  # "WD"
@@ -3,7 +3,6 @@
3
3
  module Pubid
4
4
  module Iec
5
5
  module Components
6
- autoload :Code, "#{__dir__}/components/code"
7
6
  autoload :ConsolidatedAmendment, "#{__dir__}/components/consolidated_amendment"
8
7
  autoload :Publisher, "#{__dir__}/components/publisher"
9
8
  autoload :Sheet, "#{__dir__}/components/sheet"
@@ -9,11 +9,15 @@ module Pubid
9
9
  # "base". No-op the delegated maps so they serialize once. (Mirrors
10
10
  # Iso::BundledIdentifier.) Fragment keeps its own stage/edition, so it
11
11
  # suppresses a subset inline instead of including this.
12
+ #
13
+ # number/part/subpart are NOT here, and deliberately so: their maps live on
14
+ # SingleIdentifier, which the four wrappers do not inherit from, so the
15
+ # exclusion is structural rather than a denylist that can drift. Only a
16
+ # converter can be no-opped this way, so a key that needs `with:` for
17
+ # another reason — year, publisher, copublishers, stage — still lists here.
18
+ # (`month`/`day`/`undated` are missing from that list and leak a duplicated
19
+ # top-level key on a wrapper; pre-existing, see docs/flavors/iec.md.)
12
20
  module DelegatedFieldSuppression
13
- def number_to_kv(_model, _doc); end
14
- def part_to_kv(_model, _doc); end
15
- def subpart_to_kv(_model, _doc); end
16
- def stage_iteration_to_kv(_model, _doc); end
17
21
  def year_to_kv(_model, _doc); end
18
22
  def publisher_to_kv(_model, _doc); end
19
23
  def copublishers_to_kv(_model, _doc); end
@@ -23,14 +27,33 @@ module Pubid
23
27
  class Identifier < ::Pubid::Identifier
24
28
  # Override base types with IEC-specific ones. publisher defaults to the
25
29
  # type's implied publisher (IEC), so an omitted publisher key reconstructs
26
- # correctly on from_hash. number/part/subpart are IEC codes.
30
+ # correctly on from_hash.
27
31
  attribute :publisher, ::Pubid::Iec::Components::Publisher,
28
32
  default: -> { self.class.default_publisher }
29
33
  attribute :copublishers, ::Pubid::Iec::Components::Publisher,
30
34
  collection: true
31
- attribute :number, ::Pubid::Iec::Components::Code
32
- attribute :part, ::Pubid::Iec::Components::Code
33
- attribute :subpart, ::Pubid::Iec::Components::Code
35
+
36
+ # number/part/subpart are plain strings, not a Components::Code.
37
+ # ::Pubid::Identifier declares them as a Code, so this is a REDECLARATION
38
+ # — safe here because this class body lives in this one file and is never
39
+ # reopened, so lutaml's deep-dup of the attribute table into each subclass
40
+ # always sees the complete table.
41
+ #
42
+ # The Code they used to hold was an empty box. Measured over all 12,331
43
+ # parseable IEC pass fixtures, number/part/subpart were a Code 9,975 /
44
+ # 5,422 / 2,416 times and NOT ONE populated `prefix`, `parts`, `part` or
45
+ # `subpart` inside it; `Iec::Components::Code` existed solely to render a
46
+ # `prefix` that no construction path ever set, and is deleted.
47
+ #
48
+ # The split was a live defect, not just clutter: `parse` produced a Code
49
+ # while `new` left a String (a `:string` assigned to a Code-typed
50
+ # attribute stays a String), so a hand-built identifier was not `==` the
51
+ # parsed one — and `#matches?` is `exclude(*ignore) == other.exclude(...)`,
52
+ # so every match between them silently returned false while `to_s`,
53
+ # `to_urn` and `to_hash` all agreed. See spec/pubid/iec/number_string_spec.
54
+ attribute :number, :string
55
+ attribute :part, :string
56
+ attribute :subpart, :string
34
57
 
35
58
  # The publisher implied when none is serialized (IEC for every type).
36
59
  def self.default_publisher
@@ -45,15 +68,17 @@ module Pubid
45
68
 
46
69
  # The class's published typed_stage (canonical surface form), or nil for
47
70
  # types without a published stage.
71
+ #
72
+ # `original_abbr` is deliberately LEFT NIL. It records the spelling the
73
+ # input used, it is not serialized, and the parse path (Builder#
74
+ # locate_typed_stage) never writes it — so setting it here alone made
75
+ # `from_hash(to_hash) != parse` for every IEC identifier. The `dup` stays:
76
+ # TYPED_STAGES is frozen, its elements are not.
48
77
  def self.published_typed_stage
49
78
  return nil unless const_defined?(:TYPED_STAGES)
50
79
 
51
80
  ts = self::TYPED_STAGES.find { |t| t.stage_code.to_s == "published" }
52
- return nil unless ts
53
-
54
- ts = ts.dup
55
- ts.original_abbr = ts.canonical_abbreviation
56
- ts
81
+ ts&.dup
57
82
  end
58
83
 
59
84
  # type and generic stage are derived from typed_stage, never stored — so
@@ -117,19 +142,31 @@ module Pubid
117
142
 
118
143
  # The base Pubid::Identifier no longer auto-maps attributes, so each
119
144
  # flavor's top class declares its own key_value mapping. Subclasses merge
120
- # their own blocks on top of this one (e.g. SupplementIdentifier adds
121
- # base; VapIdentifier adds vap), so list every base attribute IEC
122
- # serializes here once. Code/Date are flattened to plain scalars; the
123
- # verbose type/stage trees are not mapped (type/stage are recomputed from
124
- # typed_stage, which serializes as just its code under "stage").
145
+ # their own blocks on top of this one — lutaml APPENDS a subclass's maps
146
+ # to the parent's (e.g. SingleIdentifier adds number/part/subpart,
147
+ # SupplementIdentifier adds base, VapIdentifier adds vap) — so list every
148
+ # attribute EVERY IEC type serializes here once, and put a key that only
149
+ # some types own on the class that owns it.
150
+ #
151
+ # Date is flattened to plain scalars; the verbose type/stage trees are not
152
+ # mapped (type/stage are recomputed from typed_stage, which serializes as
153
+ # just its code under "stage").
154
+ #
155
+ # A converter (`with:`) is for a custom class, or for splitting one
156
+ # attribute across several keys. A primitive takes a plain map: a nil and
157
+ # a default-valued attribute are both dropped by
158
+ # ::Pubid::Identifier#to_hash, so no converter is needed to omit them.
125
159
  key_value do
126
160
  map "_type", to: :_type, polymorphic_map: IEC_TYPE_MAP
127
- # Code components serialize as their plain string value, not {value,...}.
128
- map "number", with: { to: :number_to_kv, from: :number_from_kv }
129
- map "part", with: { to: :part_to_kv, from: :part_from_kv }
130
- map "subpart", with: { to: :subpart_to_kv, from: :subpart_from_kv }
131
- map "stage_iteration",
132
- with: { to: :stage_iteration_to_kv, from: :stage_iteration_from_kv }
161
+ # number/part/subpart are NOT mapped here — they live on
162
+ # SingleIdentifier, the seam that excludes the four delegating wrappers.
163
+ # See the comment on that block.
164
+ #
165
+ # stage_iteration is a degenerate Components::Iteration (one :string
166
+ # field, `number`), so the shared FLAT_SCALAR_COMPONENTS rule on
167
+ # ::Pubid::Identifier flattens it to a bare scalar and inflates it back.
168
+ # A plain map is enough; no converter.
169
+ map "stage_iteration", to: :stage_iteration, render_default: false
133
170
  # date serialized flat as year/month/day, nils omitted.
134
171
  map "year", with: { to: :year_to_kv, from: :year_from_kv }
135
172
  map "month", with: { to: :month_to_kv, from: :month_from_kv }
@@ -148,45 +185,9 @@ module Pubid
148
185
  # serialize only the unique typed-stage code under "stage" and recompute
149
186
  # the rest on load. _type already pins the document type.
150
187
  map "stage", with: { to: :stage_to_kv, from: :stage_from_kv }
151
- # Omit the `false` default; only the meaningful `true` is serialized.
152
- map "all_parts", with: { to: :all_parts_to_kv, from: :all_parts_from_kv }
153
- end
154
-
155
- # --- Code components <-> plain string ---
156
- def number_to_kv(model, doc) = emit_code(doc, "number", model.number)
157
- def number_from_kv(model, value) = model.number = build_code(value)
158
- def part_to_kv(model, doc) = emit_code(doc, "part", model.part)
159
- def part_from_kv(model, value) = model.part = build_code(value)
160
- def subpart_to_kv(model, doc) = emit_code(doc, "subpart", model.subpart)
161
- def subpart_from_kv(model, value) = model.subpart = build_code(value)
162
-
163
- def emit_code(doc, key, code)
164
- v = code.is_a?(::Pubid::Components::Code) ? code.value : code
165
- return if v.nil? || v.to_s.empty?
166
-
167
- doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
168
- end
169
-
170
- def build_code(value)
171
- return if value.nil? || value.to_s.empty?
172
-
173
- ::Pubid::Iec::Components::Code.new(value: value.to_s)
174
- end
175
-
176
- def stage_iteration_to_kv(model, doc)
177
- iter = model.stage_iteration
178
- v = iter.is_a?(::Pubid::Components::Iteration) ? iter.number : iter
179
- return if v.nil? || v.to_s.empty?
180
-
181
- doc.add_child(Lutaml::KeyValue::DataModel::Element.new("stage_iteration",
182
- v.to_s))
183
- end
184
-
185
- def stage_iteration_from_kv(model, value)
186
- return if value.nil? || value.to_s.empty?
187
-
188
- model.stage_iteration =
189
- ::Pubid::Components::Iteration.new(number: value.to_s)
188
+ # A Boolean attribute whose `false` default ::Pubid::Identifier#to_hash
189
+ # already drops, so a plain map suffices (the GB spelling).
190
+ map "all_parts", to: :all_parts, render_default: false
190
191
  end
191
192
 
192
193
  # --- date serialized flat as year/month/day ---
@@ -274,17 +275,6 @@ module Pubid
274
275
  end
275
276
  end
276
277
 
277
- # --- all_parts: omit the false default ---
278
- def all_parts_to_kv(model, doc)
279
- return unless model.all_parts
280
-
281
- doc.add_child(Lutaml::KeyValue::DataModel::Element.new("all_parts", true))
282
- end
283
-
284
- def all_parts_from_kv(model, value)
285
- model.all_parts = value
286
- end
287
-
288
278
  # Serialize typed_stage as just its unique code (e.g. "cd", "fdis"); the
289
279
  # published default is omitted (recomputed from the class on load).
290
280
  def stage_to_kv(model, doc)
@@ -298,6 +288,8 @@ module Pubid
298
288
  end
299
289
 
300
290
  # Resolve the typed-stage code back within this identifier's class.
291
+ # `original_abbr` is left nil here for the same reason as in
292
+ # `published_typed_stage` above.
301
293
  def stage_from_kv(model, value)
302
294
  return if value.nil? || value.to_s.empty?
303
295
 
@@ -306,14 +298,17 @@ module Pubid
306
298
  Pubid::Iec.all_typed_stages.find { |t| t.code.to_s == value.to_s }
307
299
  return unless ts
308
300
 
309
- ts = ts.dup
310
- ts.original_abbr = ts.canonical_abbreviation
311
- model.typed_stage = ts
301
+ model.typed_stage = ts.dup
312
302
  end
313
303
 
314
304
  def self.parse(string)
305
+ unless string.is_a?(String)
306
+ raise Pubid::Errors::InvalidInputError,
307
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
308
+ end
309
+
315
310
  if string.length > Pubid::MAX_INPUT_LENGTH
316
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
311
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
317
312
  end
318
313
 
319
314
  # Route URN strings to the URN parser (mirrors Iso::Identifier.parse)
@@ -324,11 +319,6 @@ module Pubid
324
319
  # Apply legacy update_codes normalization first, before any other preprocessing
325
320
  normalized = Core::UpdateCodes.apply(string, :iec)
326
321
  parsed = Pubid::Iec::Parser.new.parse(normalized)
327
- if parsed.nil? || parsed.empty?
328
- raise Pubid::Iec::Parser::ParseError,
329
- "Invalid identifier format"
330
- end
331
-
332
322
  Pubid::Iec::Builder.new.build(parsed)
333
323
  end
334
324
 
@@ -5,8 +5,12 @@ module Pubid
5
5
  module Identifiers
6
6
  # Amendment Identifier
7
7
  class Amendment < SupplementIdentifier
8
- attribute :type, Pubid::Components::Type, default: -> { self.class.type[:key] }
9
-
8
+ # `type` is NOT redeclared here. It is derived from `typed_stage` by
9
+ # Pubid::Iec::Identifier#type, like every other IEC type. A redeclared
10
+ # attribute shadowed that reader and, because `type` is not serialized,
11
+ # its class-level default assigned the Symbol `:amd` on the from_hash
12
+ # path where the parse path assigns a Components::Type — so
13
+ # `from_hash(to_hash) != parse` for every amendment.
10
14
  TYPED_STAGES = [
11
15
  Pubid::Components::TypedStage.new(
12
16
  code: :pwi_amd,
@@ -23,16 +23,6 @@ module Pubid
23
23
  web: :component_specification, title: "Component Specification", short: "CS" }
24
24
  end
25
25
 
26
- # Override publisher_portion to add CS
27
- def publisher_portion
28
- result = publisher.to_s
29
-
30
- if typed_stage && typed_stage.abbreviation == "CS"
31
- result += " CS"
32
- end
33
-
34
- result
35
- end
36
26
  end
37
27
  end
38
28
  end
@@ -22,16 +22,6 @@ module Pubid
22
22
  { key: :ca, title: "Conformity Assessment", short: "CA" }
23
23
  end
24
24
 
25
- # Override publisher_portion to add /CA
26
- def publisher_portion
27
- result = publisher.to_s
28
-
29
- if typed_stage && typed_stage.abbreviation == "CA"
30
- result += " CA"
31
- end
32
-
33
- result
34
- end
35
25
  end
36
26
  end
37
27
  end
@@ -5,8 +5,8 @@ module Pubid
5
5
  module Identifiers
6
6
  # Corrigendum Identifier
7
7
  class Corrigendum < SupplementIdentifier
8
- attribute :type, Pubid::Components::Type, default: -> { self.class.type[:key] }
9
-
8
+ # `type` is NOT redeclared here — see the note on Amendment. The
9
+ # redeclaration assigned the Symbol `:cor` on the from_hash path.
10
10
  TYPED_STAGES = [
11
11
  Pubid::Components::TypedStage.new(
12
12
  code: :pwi_cor,
@@ -25,10 +25,8 @@ module Pubid
25
25
  map "fragment_number", to: :fragment_number, render_default: false
26
26
  end
27
27
 
28
- def number_to_kv(_model, _doc); end
29
- def part_to_kv(_model, _doc); end
30
- def subpart_to_kv(_model, _doc); end
31
- def stage_iteration_to_kv(_model, _doc); end
28
+ # number/part/subpart need no no-op here: their maps live on
29
+ # SingleIdentifier, which this class does not inherit from.
32
30
  def year_to_kv(_model, _doc); end
33
31
  def publisher_to_kv(_model, _doc); end
34
32
  def copublishers_to_kv(_model, _doc); end
@@ -80,22 +80,6 @@ module Pubid
80
80
  { key: :guide, title: "Guide", short: %w[Guide GUIDE] }
81
81
  end
82
82
 
83
- # Override publisher_portion to handle Guide formatting
84
- # If copublishers exist, use parent implementation
85
- def publisher_portion
86
- # If copublishers, delegate to parent (SingleIdentifier) which handles them
87
- return super if copublishers&.any?
88
-
89
- # No copublishers: simple Guide formatting
90
- result = publisher.to_s
91
-
92
- if typed_stage
93
- abbr = typed_stage.abbreviation
94
- result += " #{abbr}" unless abbr.empty?
95
- end
96
-
97
- result
98
- end
99
83
  end
100
84
  end
101
85
  end
@@ -13,7 +13,7 @@ module Pubid
13
13
  code: :pwi,
14
14
  stage_code: :pwi,
15
15
  type_code: :is,
16
- abbr: %w[PWI PNW NWIP BWG AWIN AMW],
16
+ abbr: %w[PWI NWIP BWG AWIN AMW],
17
17
  name: "Preliminary Work Item",
18
18
  harmonized_stages: %w[00.00 00.20 00.60 00.98 00.99],
19
19
  ),
@@ -23,7 +23,20 @@ module Pubid
23
23
  type_code: :is,
24
24
  abbr: ["NP"],
25
25
  name: "New Proposal",
26
- harmonized_stages: %w[10.00 10.20 10.60 10.92 10.98],
26
+ harmonized_stages: %w[10.00 10.60 10.92 10.98],
27
+ ),
28
+ # PNW is a stage of its own, not an alias of PWI. IEC's portal and
29
+ # pubid-iec 1.x both give it harmonized code 10.20 ("New work item
30
+ # proposal"), which is why 10.20 is absent from :np above — the two
31
+ # must not both claim it, or a lookup by harmonized code is
32
+ # ambiguous. See issue #360 item 1.
33
+ Pubid::Components::TypedStage.new(
34
+ code: :pnw,
35
+ stage_code: :pnw,
36
+ type_code: :is,
37
+ abbr: ["PNW"],
38
+ name: "New work item proposal",
39
+ harmonized_stages: %w[10.20],
27
40
  ),
28
41
  Pubid::Components::TypedStage.new(
29
42
  code: :anw,
@@ -23,16 +23,6 @@ module Pubid
23
23
  web: :operational_document, title: "Operational Document", short: "OD" }
24
24
  end
25
25
 
26
- # Override publisher_portion to add OD
27
- def publisher_portion
28
- result = publisher.to_s
29
-
30
- if typed_stage && typed_stage.abbreviation == "OD"
31
- result += " OD"
32
- end
33
-
34
- result
35
- end
36
26
  end
37
27
  end
38
28
  end