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
@@ -94,6 +94,16 @@ module Pubid
94
94
 
95
95
  private
96
96
 
97
+ # Read a value that may be a component or a bare scalar. BSI's own
98
+ # `number`/`part`/`subpart` are plain strings, but a bundle member or an
99
+ # adopted identifier can be a foreign one (ISO, IEC, CEN/CENELEC) whose
100
+ # equivalents are still a Components::Code.
101
+ def component_str(value)
102
+ return "" if value.nil?
103
+
104
+ (value.respond_to?(:render) ? value.render(context: @context) : value).to_s
105
+ end
106
+
97
107
  # ------------------------------------------------------------------
98
108
  # SingleIdentifier (base BSI identifier)
99
109
  # ------------------------------------------------------------------
@@ -109,7 +119,7 @@ module Pubid
109
119
  end
110
120
 
111
121
  if id.number
112
- number_str = id.number.render(context: @context)
122
+ number_str = id.number
113
123
 
114
124
  if id.second_number
115
125
  second_val = id.second_number.render(context: @context)
@@ -118,13 +128,13 @@ module Pubid
118
128
 
119
129
  space_separated = id.space_separated_part
120
130
  if id.part
121
- part_val = id.part.render(context: @context)
131
+ part_val = id.part
122
132
  part_str = part_val.to_s.strip
123
133
  separator = space_separated ? " " : "-"
124
134
  number_str += "#{separator}#{part_str}"
125
135
  end
126
136
  if id.subpart
127
- subpart_val = id.subpart.render(context: @context)
137
+ subpart_val = id.subpart
128
138
  subpart_str = subpart_val.to_s.strip
129
139
  number_str += "-#{subpart_str}"
130
140
  end
@@ -202,7 +212,7 @@ module Pubid
202
212
  end
203
213
 
204
214
  result = prefix
205
- result += " #{id.adopted_identifier}" if id.adopted_identifier
215
+ result += " #{id.adopted}" if id.adopted
206
216
  result += " ED#{id.edition}" if id.edition
207
217
 
208
218
  result += " (R#{id.reaffirmation_year})" if id.reaffirmation_year
@@ -227,7 +237,7 @@ module Pubid
227
237
  end
228
238
 
229
239
  result = prefix
230
- result += " #{id.adopted_identifier}" if id.adopted_identifier
240
+ result += " #{id.adopted}" if id.adopted
231
241
  result += " ED#{id.edition}" if id.edition
232
242
 
233
243
  result += " (R#{id.reaffirmation_year})" if id.reaffirmation_year
@@ -249,14 +259,14 @@ module Pubid
249
259
  parts << id.prefix if id.prefix
250
260
 
251
261
  if id.number
252
- number_str = id.number.render(context: @context)
262
+ number_str = id.number
253
263
 
254
264
  if id.part
255
- part_val = id.part.render(context: @context)
265
+ part_val = id.part
256
266
  number_str += "-#{part_val}"
257
267
  end
258
268
  if id.subpart
259
- subpart_val = id.subpart.render(context: @context)
269
+ subpart_val = id.subpart
260
270
  number_str += "-#{subpart_val}"
261
271
  end
262
272
 
@@ -321,8 +331,10 @@ module Pubid
321
331
  parts_list = id.identifiers[1..].map do |idd|
322
332
  part_val = idd.class.attributes.key?(:part) ? idd.part : nil
323
333
  if part_val
324
- pv = part_val.render(context: @context)
325
- pv.to_s
334
+ # A bundle member may be a foreign identifier (ISO, CEN/CENELEC),
335
+ # whose `part` is still a Components::Code, so read through
336
+ # whichever shape it holds.
337
+ component_str(part_val)
326
338
  else
327
339
  idd.to_s
328
340
  end
@@ -350,23 +362,23 @@ module Pubid
350
362
  abbrev_str = prefix.to_s
351
363
  end
352
364
  if idd.number
353
- number_val = idd.number.render(context: @context)
365
+ number_val = idd.number
354
366
  abbrev_str += " " if !abbrev_str.empty?
355
367
  abbrev_str += number_val.to_s
356
368
  end
357
369
  if idd.part
358
- part_val = idd.part.render(context: @context)
370
+ part_val = idd.part
359
371
  abbrev_str += "-#{part_val}"
360
372
  end
361
373
  parts << abbrev_str
362
374
  else
363
375
  abbrev_str = ""
364
376
  if idd.number
365
- number_val = idd.number.render(context: @context)
377
+ number_val = idd.number
366
378
  abbrev_str = number_val.to_s
367
379
  end
368
380
  if idd.part
369
- part_val = idd.part.render(context: @context)
381
+ part_val = idd.part
370
382
  abbrev_str += "-#{part_val}"
371
383
  end
372
384
  parts << abbrev_str
@@ -394,7 +406,7 @@ module Pubid
394
406
  "00"
395
407
  end
396
408
 
397
- "#{year_str}/#{id.document_number} DC"
409
+ "#{year_str}/#{id.number} DC"
398
410
  end
399
411
 
400
412
  def render_consolidated_identifier(id, opts)
@@ -483,7 +495,7 @@ module Pubid
483
495
  parts << "BS"
484
496
 
485
497
  if id.number
486
- number_str = id.number.render(context: @context)
498
+ number_str = id.number
487
499
  parts << number_str
488
500
  end
489
501
 
@@ -507,9 +519,9 @@ module Pubid
507
519
  parts << "DISC"
508
520
 
509
521
  if id.number
510
- number_str = id.number.render(context: @context)
522
+ number_str = id.number
511
523
  if id.part
512
- part_val = id.part.render(context: @context)
524
+ part_val = id.part
513
525
  number_str += "-#{part_val.to_s.strip}"
514
526
  end
515
527
  parts << "PD #{number_str}"
@@ -529,14 +541,14 @@ module Pubid
529
541
  parts << type_abbr
530
542
 
531
543
  if id.number
532
- number_str = id.number.render(context: @context)
544
+ number_str = id.number
533
545
 
534
546
  if id.part
535
- part_val = id.part.render(context: @context)
547
+ part_val = id.part
536
548
  number_str += "-#{part_val.to_s.strip}"
537
549
  end
538
550
  if id.subpart
539
- subpart_val = id.subpart.render(context: @context)
551
+ subpart_val = id.subpart
540
552
  number_str += "-#{subpart_val.to_s.strip}"
541
553
  end
542
554
 
@@ -562,14 +574,14 @@ module Pubid
562
574
  parts << "EP"
563
575
 
564
576
  if id.number
565
- number_str = id.number.render(context: @context)
577
+ number_str = id.number
566
578
 
567
579
  if id.part
568
- part_val = id.part.render(context: @context)
580
+ part_val = id.part
569
581
  number_str += "-#{part_val.to_s.strip}"
570
582
  end
571
583
  if id.subpart
572
- subpart_val = id.subpart.render(context: @context)
584
+ subpart_val = id.subpart
573
585
  number_str += "-#{subpart_val.to_s.strip}"
574
586
  end
575
587
 
@@ -607,14 +619,14 @@ module Pubid
607
619
  parts << "BS"
608
620
 
609
621
  if id.number
610
- number_str = id.number.render(context: @context)
622
+ number_str = id.number
611
623
 
612
624
  if id.part
613
- part_val = id.part.render(context: @context)
625
+ part_val = id.part
614
626
  number_str += "-#{part_val}"
615
627
  end
616
628
  if id.subpart
617
- subpart_val = id.subpart.render(context: @context)
629
+ subpart_val = id.subpart
618
630
  number_str += "-#{subpart_val}"
619
631
  end
620
632
 
@@ -637,13 +649,13 @@ module Pubid
637
649
  parts << "BSI Flex"
638
650
 
639
651
  if id.number
640
- number_str = id.number.render(context: @context)
652
+ number_str = id.number
641
653
  if id.part
642
- part_val = id.part.render(context: @context)
654
+ part_val = id.part
643
655
  number_str += "-#{part_val}"
644
656
  end
645
657
  if id.subpart
646
- subpart_val = id.subpart.render(context: @context)
658
+ subpart_val = id.subpart
647
659
  number_str += "-#{subpart_val}"
648
660
  end
649
661
  parts << number_str
@@ -665,9 +677,9 @@ module Pubid
665
677
  def render_handbook(id)
666
678
  abbr = id.original_abbr || "Handbook"
667
679
 
668
- number_str = id.number.render(context: @context)
680
+ number_str = id.number
669
681
  if id.part
670
- part_val = id.part.render(context: @context)
682
+ part_val = id.part
671
683
  number_str += "-#{part_val.to_s.strip}"
672
684
  end
673
685
 
@@ -681,7 +693,7 @@ module Pubid
681
693
  parts << id.publisher.to_s if id.publisher
682
694
 
683
695
  if id.number
684
- number_str = id.number.render(context: @context)
696
+ number_str = id.number
685
697
  parts << number_str
686
698
  end
687
699
 
@@ -708,9 +720,9 @@ module Pubid
708
720
  parts << id.publisher.to_s if id.publisher
709
721
 
710
722
  if id.number
711
- number_str = id.number.render(context: @context)
723
+ number_str = id.number
712
724
  if id.part
713
- part_val = id.part.render(context: @context)
725
+ part_val = id.part
714
726
  number_str += "-#{part_val}"
715
727
  end
716
728
  parts << number_str
@@ -771,7 +783,7 @@ module Pubid
771
783
  parts << type_abbr
772
784
 
773
785
  if id.number
774
- number_str = id.number.render(context: @context)
786
+ number_str = id.number
775
787
 
776
788
  if id.second_number
777
789
  second_val = id.second_number.render(context: @context)
@@ -779,11 +791,11 @@ module Pubid
779
791
  end
780
792
 
781
793
  if id.part
782
- part_val = id.part.render(context: @context)
794
+ part_val = id.part
783
795
  number_str += "-#{part_val.to_s.strip}"
784
796
  end
785
797
  if id.subpart
786
- subpart_val = id.subpart.render(context: @context)
798
+ subpart_val = id.subpart
787
799
  number_str += "-#{subpart_val.to_s.strip}"
788
800
  end
789
801
 
@@ -811,7 +823,7 @@ module Pubid
811
823
  parts << type_abbr
812
824
 
813
825
  if id.number
814
- number_str = id.number.render(context: @context)
826
+ number_str = id.number
815
827
 
816
828
  if id.second_number
817
829
  second_val = id.second_number.render(context: @context)
@@ -819,11 +831,11 @@ module Pubid
819
831
  end
820
832
 
821
833
  if id.part
822
- part_val = id.part.render(context: @context)
834
+ part_val = id.part
823
835
  number_str += "-#{part_val.to_s.strip}"
824
836
  end
825
837
  if id.subpart
826
- subpart_val = id.subpart.render(context: @context)
838
+ subpart_val = id.subpart
827
839
  number_str += "-#{subpart_val.to_s.strip}"
828
840
  end
829
841
 
@@ -850,7 +862,7 @@ module Pubid
850
862
  parts << id.publisher.to_s if id.publisher
851
863
 
852
864
  if id.number
853
- number_str = id.number.render(context: @context)
865
+ number_str = id.number
854
866
  parts << number_str
855
867
  end
856
868
 
@@ -886,9 +898,9 @@ module Pubid
886
898
 
887
899
  def render_standalone_amendment(id)
888
900
  base = if id.corrigendum
889
- "AMD Corrigendum #{id.amendment_number}"
901
+ "AMD Corrigendum #{id.number}"
890
902
  else
891
- "AMD #{id.amendment_number}"
903
+ "AMD #{id.number}"
892
904
  end
893
905
 
894
906
  id.parenthesized ? "(#{base})" : base
@@ -919,14 +931,14 @@ module Pubid
919
931
  parts << "BS"
920
932
 
921
933
  if id.number
922
- number_str = id.number.render(context: @context)
934
+ number_str = id.number
923
935
 
924
936
  if id.part
925
- part_val = id.part.render(context: @context)
937
+ part_val = id.part
926
938
  number_str += "-#{part_val}"
927
939
  end
928
940
  if id.subpart
929
- subpart_val = id.subpart.render(context: @context)
941
+ subpart_val = id.subpart
930
942
  number_str += "-#{subpart_val}"
931
943
  end
932
944
 
@@ -949,14 +961,14 @@ module Pubid
949
961
  parts << "TS"
950
962
 
951
963
  if id.number
952
- number_str = id.number.render(context: @context)
964
+ number_str = id.number
953
965
 
954
966
  if id.part
955
- part_val = id.part.render(context: @context)
967
+ part_val = id.part
956
968
  number_str += "-#{part_val}"
957
969
  end
958
970
  if id.subpart
959
- subpart_val = id.subpart.render(context: @context)
971
+ subpart_val = id.subpart
960
972
  number_str += "-#{subpart_val}"
961
973
  end
962
974
 
@@ -979,7 +991,7 @@ module Pubid
979
991
  parts << "BS"
980
992
 
981
993
  if id.number
982
- number_str = id.number.render(context: @context)
994
+ number_str = id.number
983
995
  parts << number_str
984
996
  end
985
997
 
@@ -9,8 +9,13 @@ module Pubid
9
9
  # `from_hash` (no facade needed).
10
10
  class Identifier < ::Pubid::Identifier
11
11
  def self.parse(string)
12
+ unless string.is_a?(String)
13
+ raise Pubid::Errors::InvalidInputError,
14
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
15
+ end
16
+
12
17
  if string.length > Pubid::MAX_INPUT_LENGTH
13
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
18
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
14
19
  end
15
20
 
16
21
  # Delegate to IEC for bare IEC identifiers. This handles IEC-specific
@@ -27,8 +32,6 @@ module Pubid
27
32
 
28
33
  parsed = parser.parse(string)
29
34
  Builder.build(parsed)
30
- rescue Parslet::ParseFailed => e
31
- raise StandardError, "Failed to parse '#{string}': #{e.message}"
32
35
  end
33
36
 
34
37
  attribute :publisher, Bsi::Components::Publisher, default: -> {
@@ -36,14 +39,29 @@ module Pubid
36
39
  }
37
40
  attribute :prefix, :string # Specialized prefix (A, AU, C, M, 2A, etc.)
38
41
  attribute :flex_prefix, :string # Flex type prefix (CECC, E9111, M, etc.)
39
- attribute :number, Bsi::Components::Code
42
+ # `number`/`part`/`subpart` are plain strings, not Bsi::Components::Code:
43
+ # BSI never populates a field of that component beyond `value`. This class
44
+ # body is the sole home of Pubid::Bsi::Identifier (bsi/identifier.rb is a
45
+ # comment-only load stub), so declaring here is safe - every subclass body
46
+ # opens after it has run. `second_number` keeps the component type: it is
47
+ # not one of the three attributes the shared base declares.
48
+ attribute :number, :string
40
49
  attribute :iteration, :string # For bracket notation like 1000[9]
41
- attribute :part, Bsi::Components::Code
42
- attribute :subpart, Bsi::Components::Code
50
+ attribute :part, :string
51
+ attribute :subpart, :string
43
52
  attribute :second_number, Bsi::Components::Code # For collections like PAS 2035/2030
44
- attribute :date, Bsi::Components::Date
53
+ # The shared component, not Bsi::Components::Date: the adoption wrappers
54
+ # (AdoptedEuropeanNorm, AdoptedInternationalStandard) delegate `date` to
55
+ # the foreign identifier they wrap, whose date is a plain
56
+ # ::Pubid::Components::Date — the empty BSI subclass rejected it and
57
+ # to_hash/from_hash raised on every "BS EN …"/"BS ISO …" (pubid#379,
58
+ # the same shape as the bsi-set-cross-flavor-type fix).
59
+ attribute :date, ::Pubid::Components::Date
45
60
  attribute :stage, Pubid::Components::Stage
46
- attribute :type, Bsi::Components::Type
61
+ # Shared Type too: the leaf builders reach for ::Pubid::Components::Type
62
+ # (e.g. a default materialized from self.type), which the empty BSI
63
+ # subclass rejected — "BIP 2225:2022" et al. failed to_hash on `type`.
64
+ attribute :type, ::Pubid::Components::Type
47
65
  attribute :typed_stage, Pubid::Components::TypedStage
48
66
  attribute :edition, :string
49
67
  attribute :month, :integer
@@ -61,7 +79,7 @@ module Pubid
61
79
  return num_cmp unless num_cmp.zero?
62
80
 
63
81
  # Then by part
64
- part_cmp = (part || Components::Code.new(value: "0")).to_s <=> (other.part || Components::Code.new(value: "0")).to_s
82
+ part_cmp = (part || "0").to_s <=> (other.part || "0").to_s
65
83
  return part_cmp unless part_cmp.zero?
66
84
 
67
85
  # Then by date
@@ -21,8 +21,17 @@ module Pubid
21
21
  parts << identifier.flex_prefix.to_s.downcase
22
22
  end
23
23
 
24
- if identifier.number
25
- number = identifier.number.to_s
24
+ # Fall back to the wrapped document's number. A wrapper — an adopted
25
+ # European norm, a bundle, a set — carries no number of its own, and
26
+ # `AdoptedEuropeanNorm#number` only delegates ONE level, so a
27
+ # "DD ENV ISO 11079:1999" (which adopts a CEN prestandard that is
28
+ # itself a wrapper around the ISO standard) emitted the identity-free
29
+ # `urn:bsi:dd` — the same URN as every other DD adoption. `#root`
30
+ # recurses to the origin document, and for a non-wrapper it is `self`,
31
+ # so this changes nothing for an ordinary identifier.
32
+ urn_number = identifier.number || identifier.root.number
33
+ if urn_number
34
+ number = urn_number.to_s
26
35
  if identifier.iteration && !identifier.iteration.empty?
27
36
  number += "[#{identifier.iteration}]"
28
37
  end
data/lib/pubid/bsi.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  module Bsi
5
6
  extend Pubid::PrefixesSupport
@@ -221,8 +222,13 @@ module Pubid
221
222
  ].freeze
222
223
 
223
224
  def self.parse(string)
225
+ unless string.is_a?(String)
226
+ raise Pubid::Errors::InvalidInputError,
227
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
228
+ end
229
+
224
230
  if string.length > Pubid::MAX_INPUT_LENGTH
225
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
231
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
226
232
  end
227
233
 
228
234
  Identifier.parse(string)
@@ -137,11 +137,14 @@ module Pubid
137
137
  end
138
138
  end
139
139
 
140
- # Splits a compound document number ("1234", "1234-1", "1234-1-2")
141
- # into number/part/subpart Code components. Flavor-specific dash/slash
142
- # normalization lives in +normalize_number_with_part+; legacy year
143
- # extraction (e.g. ISO "4037-1979") lives in +extract_legacy_year+.
144
- def parse_number_with_part(value, code_class:)
140
+ # Splits a compound document number ("1234", "1234-1", "1234-1-2") into
141
+ # number/part/subpart. Each piece is wrapped in +code_class+ when the
142
+ # flavor declares those attributes as a Components::Code (ISO), and kept
143
+ # as a plain string when +code_class+ is nil (IEC and the other retyped
144
+ # flavors). Flavor-specific dash/slash normalization lives in
145
+ # +normalize_number_with_part+; legacy year extraction (e.g. ISO
146
+ # "4037-1979") lives in +extract_legacy_year+.
147
+ def parse_number_with_part(value, code_class: nil)
145
148
  normalized = normalize_number_with_part(value)
146
149
  parts = normalized.split("-").reject(&:empty?)
147
150
  number = parts.shift
@@ -153,12 +156,19 @@ module Pubid
153
156
 
154
157
  part = convert_roman_to_integer(part) if part
155
158
 
156
- code_hash = { number: code_class.new(value: number) }
157
- code_hash[:part] = code_class.new(value: part) if part
158
- code_hash[:subpart] = code_class.new(value: subpart) if subpart
159
+ code_hash = { number: wrap_component(number, code_class) }
160
+ code_hash[:part] = wrap_component(part, code_class) if part
161
+ code_hash[:subpart] = wrap_component(subpart, code_class) if subpart
159
162
  code_hash
160
163
  end
161
164
 
165
+ # A nil +code_class+ means the flavor holds number/part/subpart as plain
166
+ # strings — the `number` retype tranches — so keep the raw scalar. ISO
167
+ # still passes its Components::Code and is unaffected.
168
+ def wrap_component(value, code_class)
169
+ code_class ? code_class.new(value: value) : value
170
+ end
171
+
162
172
  # Hook: normalize the raw number_with_part string before splitting.
163
173
  # Override in subclasses for flavor-specific dash/slash/space handling.
164
174
  def normalize_number_with_part(value)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  # Identifier that represents a combined bundle of documents using the + operator.
5
6
  # Examples:
@@ -45,10 +46,15 @@ module Pubid
45
46
  base_document&.typed_stage
46
47
  end
47
48
 
49
+ # `**opts` carries render flags this method does not name — `annotated:`
50
+ # above all. Without it the closed keyword list raised
51
+ # `ArgumentError: unknown keyword: :annotated` for every bundled
52
+ # identifier, which is worse than a missing span: a wrapper is exactly the
53
+ # shape a consumer renders.
48
54
  def to_s(lang: :en, lang_single: false, with_edition: false, format: nil,
49
- stage_format_long: nil, with_date: nil)
55
+ stage_format_long: nil, with_date: nil, **opts)
50
56
  result = base_document.to_s(lang: lang, lang_single: lang_single,
51
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date)
57
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts)
52
58
 
53
59
  supplements.each do |supplement|
54
60
  # ISO DirectivesSupplement always uses " + " (space before)
@@ -57,10 +63,10 @@ stage_format_long: nil, with_date: nil)
57
63
  if supplement.class.name&.include?("DirectivesSupplement") ||
58
64
  (supplement.class.attributes.key?(:base) && !supplement.base.nil?)
59
65
  result += " + #{supplement.to_s(lang: lang, lang_single: lang_single,
60
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date)}"
66
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts)}"
61
67
  else
62
68
  result += "+#{supplement.to_s(lang: lang, lang_single: lang_single,
63
- with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date)}"
69
+ with_edition: with_edition, format: format, stage_format_long: stage_format_long, with_date: with_date, **opts)}"
64
70
  end
65
71
  end
66
72
 
@@ -102,9 +108,13 @@ stage_format_long: nil, with_date: nil)
102
108
  parts << supplement.date.year.to_s
103
109
  end
104
110
 
105
- # Add supplement number if present
111
+ # Add supplement number if present. `supplement` is polymorphic and
112
+ # `number` is a Components::Code on ::Pubid::Identifier but a plain
113
+ # :string in a growing number of flavors, so read through either.
106
114
  if supplement.number
107
- parts << "v#{supplement.number.value}"
115
+ number = supplement.number
116
+ value = number.respond_to?(:value) ? number.value : number
117
+ parts << "v#{value}"
108
118
  end
109
119
  end
110
120
  end
@@ -101,16 +101,20 @@ module Pubid
101
101
  # Parse a CalConnect identifier string into an identifier object.
102
102
  # @param identifier [String] The CalConnect identifier string to parse
103
103
  # @return [Identifier] The appropriate identifier object
104
- # @raise [ArgumentError] If the input exceeds the maximum length
105
- # @raise [RuntimeError] If parsing fails
104
+ # @raise [Pubid::Errors::InvalidInputError]
105
+ # If the input exceeds the maximum length
106
+ # @raise [Pubid::Errors::ParseError] If parsing fails
106
107
  def self.parse(identifier)
108
+ unless identifier.is_a?(String)
109
+ raise Pubid::Errors::InvalidInputError,
110
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
111
+ end
112
+
107
113
  if identifier.length > Pubid::MAX_INPUT_LENGTH
108
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
114
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
109
115
  end
110
116
 
111
117
  Builder.build(Parser.parse(identifier))
112
- rescue Parslet::ParseFailed => e
113
- raise "Failed to parse CalConnect '#{identifier}': #{e.message}"
114
118
  end
115
119
  end
116
120
  end
@@ -12,7 +12,7 @@ module Pubid
12
12
  # CC/Adv 0707.1:2007 (dot sub-part)
13
13
  # CC/A 0812-1:2008 (dash sub-part)
14
14
  # CC/WD 51017:2024-07-23 (full ISO date)
15
- class Parser < Parslet::Parser
15
+ class Parser < ::Pubid::Parser::Grammar
16
16
  rule(:digit) { match["0-9"] }
17
17
  rule(:digits) { digit.repeat(1) }
18
18
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  # CalConnect (The Calendaring and Scheduling Consortium) flavor.
5
6
  #
@@ -24,8 +25,13 @@ module Pubid
24
25
 
25
26
  # Parse a CalConnect identifier string
26
27
  def self.parse(identifier)
28
+ unless identifier.is_a?(String)
29
+ raise Pubid::Errors::InvalidInputError,
30
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
31
+ end
32
+
27
33
  if identifier.length > Pubid::MAX_INPUT_LENGTH
28
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
34
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
29
35
  end
30
36
 
31
37
  Identifier.parse(identifier)
@@ -22,6 +22,10 @@ module Pubid
22
22
  # are likewise CCSDS-specific plain strings.
23
23
  attribute :number, :string
24
24
  attribute :part, :string
25
+ # CCSDS never populates `subpart`, but the inherited declaration is a
26
+ # Components::Code, and a parent that disagrees with its leaves is the
27
+ # determinism landmine. Declare it here, like every converted flavor.
28
+ attribute :subpart, :string
25
29
  attribute :edition, :string
26
30
  attribute :type, :string
27
31
  attribute :suffix, :string
@@ -54,12 +58,19 @@ module Pubid
54
58
 
55
59
  # Parse a CCSDS identifier string into the appropriate identifier object.
56
60
  def self.parse(identifier)
61
+ unless identifier.is_a?(String)
62
+ raise Pubid::Errors::InvalidInputError,
63
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
64
+ end
65
+
66
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
67
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
68
+ end
69
+
57
70
  # Apply legacy update_codes normalization first
58
71
  normalized = Core::UpdateCodes.apply(identifier, :ccsds)
59
72
  parsed = Pubid::Ccsds::Parser.parse(normalized)
60
73
  Pubid::Ccsds::Builder.build(parsed)
61
- rescue Parslet::ParseFailed => e
62
- raise "Failed to parse CCSDS identifier '#{identifier}': #{e.message}"
63
74
  end
64
75
 
65
76
  # from_hash is the shared polymorphic dispatch on Pubid::Identifier.
@@ -24,14 +24,16 @@ module Pubid
24
24
  { key: :base, web: :base, title: "Base Standard", short: nil }
25
25
  end
26
26
 
27
- def to_s(**_opts)
27
+ # Composes its string by hand rather than going through `render`, so
28
+ # the annotation hook has to be applied on the way out.
29
+ def to_s(**opts)
28
30
  result = "#{publisher} #{number}"
29
31
  result += ".#{part}" if part
30
32
  result += "-#{type}" if type
31
33
  result += "-#{edition}" if edition
32
34
  result += "-#{suffix}" if suffix
33
35
  result += " - #{language} Translated" if language
34
- result
36
+ annotate_plain_render(result, **opts)
35
37
  end
36
38
  end
37
39
  end