relaton 3.0.0.pre.alpha.1 → 3.0.0.pre.alpha.2

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +57 -1
  3. data/bin/console +0 -1
  4. data/lib/relaton/3gpp/bibliography.rb +82 -7
  5. data/lib/relaton/3gpp/data_fetcher.rb +51 -3
  6. data/lib/relaton/3gpp/docidentifier.rb +114 -0
  7. data/lib/relaton/3gpp/item.rb +6 -0
  8. data/lib/relaton/3gpp/parser.rb +1 -1
  9. data/lib/relaton/3gpp/processor.rb +4 -1
  10. data/lib/relaton/3gpp.rb +5 -1
  11. data/lib/relaton/adobe/bibdata.rb +8 -0
  12. data/lib/relaton/adobe/bibitem.rb +8 -0
  13. data/lib/relaton/adobe/bibliography.rb +92 -0
  14. data/lib/relaton/adobe/docidentifier.rb +49 -0
  15. data/lib/relaton/adobe/doctype.rb +14 -0
  16. data/lib/relaton/adobe/ext.rb +32 -0
  17. data/lib/relaton/adobe/item.rb +15 -0
  18. data/lib/relaton/adobe/item_base.rb +18 -0
  19. data/lib/relaton/adobe/item_data.rb +6 -0
  20. data/lib/relaton/adobe/processor.rb +45 -0
  21. data/lib/relaton/adobe/util.rb +8 -0
  22. data/lib/relaton/adobe.rb +37 -0
  23. data/lib/relaton/bib/model/address.rb +2 -2
  24. data/lib/relaton/bib/model/docidentifier.rb +24 -9
  25. data/lib/relaton/bib/model/localized_string.rb +1 -1
  26. data/lib/relaton/bib/model/structured_identifier.rb +10 -9
  27. data/lib/relaton/bib/sanitizer.rb +202 -6
  28. data/lib/relaton/bib.rb +0 -2
  29. data/lib/relaton/bipm/bibliography.rb +159 -10
  30. data/lib/relaton/bipm/data_fetcher.rb +26 -2
  31. data/lib/relaton/bipm/data_outcomes_parser.rb +3 -4
  32. data/lib/relaton/bipm/id_parser.rb +5 -4
  33. data/lib/relaton/bipm/model/structured_identifier.rb +21 -0
  34. data/lib/relaton/bipm/processor.rb +2 -2
  35. data/lib/relaton/bipm/rawdata_bipm_metrologia/fetcher.rb +2 -4
  36. data/lib/relaton/bipm/si_brochure_parser.rb +5 -3
  37. data/lib/relaton/bipm.rb +7 -1
  38. data/lib/relaton/bsi/bibliography.rb +115 -43
  39. data/lib/relaton/bsi/hit.rb +14 -0
  40. data/lib/relaton/bsi/hit_collection.rb +15 -16
  41. data/lib/relaton/bsi/model/docidentifier.rb +99 -1
  42. data/lib/relaton/bsi/processor.rb +1 -0
  43. data/lib/relaton/calconnect/bibliography.rb +12 -14
  44. data/lib/relaton/calconnect/data_fetcher.rb +77 -9
  45. data/lib/relaton/calconnect/docidentifier.rb +80 -0
  46. data/lib/relaton/calconnect/hit_collection.rb +65 -57
  47. data/lib/relaton/calconnect/model/item.rb +7 -0
  48. data/lib/relaton/calconnect/processor.rb +7 -1
  49. data/lib/relaton/calconnect.rb +11 -1
  50. data/lib/relaton/ccsds/data/fetcher.rb +17 -12
  51. data/lib/relaton/ccsds/data/parser.rb +1 -1
  52. data/lib/relaton/ccsds/hit_collection.rb +6 -1
  53. data/lib/relaton/ccsds/model/docidentifier.rb +121 -0
  54. data/lib/relaton/ccsds/model/item.rb +2 -0
  55. data/lib/relaton/cen/bibliography.rb +75 -47
  56. data/lib/relaton/cen/hit.rb +16 -1
  57. data/lib/relaton/cen/hit_collection.rb +59 -11
  58. data/lib/relaton/cen/model/docidentifier.rb +92 -1
  59. data/lib/relaton/cen/processor.rb +13 -8
  60. data/lib/relaton/cen/scraper.rb +13 -5
  61. data/lib/relaton/cen.rb +1 -0
  62. data/lib/relaton/cie/data_fetcher.rb +215 -30
  63. data/lib/relaton/cie/processor.rb +3 -1
  64. data/lib/relaton/cie/scrapper.rb +15 -2
  65. data/lib/relaton/cie.rb +2 -1
  66. data/lib/relaton/core/data_fetcher.rb +150 -3
  67. data/lib/relaton/core/governor.rb +320 -0
  68. data/lib/relaton/core/pacer.rb +134 -0
  69. data/lib/relaton/core/processor.rb +19 -0
  70. data/lib/relaton/core/request_error.rb +14 -0
  71. data/lib/relaton/core.rb +3 -0
  72. data/lib/relaton/db/registry.rb +41 -1
  73. data/lib/relaton/doi/crossref.rb +19 -2
  74. data/lib/relaton/doi/parser.rb +109 -15
  75. data/lib/relaton/easc/bibdata.rb +8 -0
  76. data/lib/relaton/easc/bibitem.rb +8 -0
  77. data/lib/relaton/easc/bibliography.rb +95 -0
  78. data/lib/relaton/easc/docidentifier.rb +100 -0
  79. data/lib/relaton/easc/doctype.rb +14 -0
  80. data/lib/relaton/easc/ext.rb +44 -0
  81. data/lib/relaton/easc/item.rb +13 -0
  82. data/lib/relaton/easc/item_base.rb +18 -0
  83. data/lib/relaton/easc/item_data.rb +6 -0
  84. data/lib/relaton/easc/processor.rb +46 -0
  85. data/lib/relaton/easc/util.rb +8 -0
  86. data/lib/relaton/easc.rb +35 -0
  87. data/lib/relaton/ecma/bibliography.rb +93 -25
  88. data/lib/relaton/ecma/data_fetcher.rb +71 -12
  89. data/lib/relaton/ecma/docidentifier.rb +124 -0
  90. data/lib/relaton/ecma/item.rb +2 -0
  91. data/lib/relaton/ecma/memento_parser.rb +1 -1
  92. data/lib/relaton/ecma/page_fetcher.rb +15 -3
  93. data/lib/relaton/ecma/parser_common.rb +2 -2
  94. data/lib/relaton/ecma/processor.rb +4 -1
  95. data/lib/relaton/ecma/standard_parser.rb +2 -2
  96. data/lib/relaton/ecma.rb +10 -1
  97. data/lib/relaton/etsi/bibliography.rb +67 -2
  98. data/lib/relaton/etsi/data_fetcher.rb +43 -4
  99. data/lib/relaton/etsi/processor.rb +3 -1
  100. data/lib/relaton/etsi.rb +2 -1
  101. data/lib/relaton/gb/bibliography.rb +55 -29
  102. data/lib/relaton/gb/docidentifier.rb +58 -9
  103. data/lib/relaton/gb/processor.rb +3 -0
  104. data/lib/relaton/gb/scraper.rb +27 -10
  105. data/lib/relaton/gost/bibdata.rb +8 -0
  106. data/lib/relaton/gost/bibitem.rb +8 -0
  107. data/lib/relaton/gost/bibliography.rb +107 -0
  108. data/lib/relaton/gost/docidentifier.rb +80 -0
  109. data/lib/relaton/gost/doctype.rb +16 -0
  110. data/lib/relaton/gost/ext.rb +46 -0
  111. data/lib/relaton/gost/item.rb +15 -0
  112. data/lib/relaton/gost/item_base.rb +18 -0
  113. data/lib/relaton/gost/item_data.rb +6 -0
  114. data/lib/relaton/gost/processor.rb +49 -0
  115. data/lib/relaton/gost/util.rb +8 -0
  116. data/lib/relaton/gost.rb +36 -0
  117. data/lib/relaton/iala/bibdata.rb +8 -0
  118. data/lib/relaton/iala/bibitem.rb +8 -0
  119. data/lib/relaton/iala/bibliography.rb +146 -0
  120. data/lib/relaton/iala/docidentifier.rb +89 -0
  121. data/lib/relaton/iala/doctype.rb +18 -0
  122. data/lib/relaton/iala/ext.rb +32 -0
  123. data/lib/relaton/iala/item.rb +21 -0
  124. data/lib/relaton/iala/item_base.rb +18 -0
  125. data/lib/relaton/iala/item_data.rb +6 -0
  126. data/lib/relaton/iala/processor.rb +43 -0
  127. data/lib/relaton/iala/relation.rb +7 -0
  128. data/lib/relaton/iala/util.rb +8 -0
  129. data/lib/relaton/iala.rb +35 -0
  130. data/lib/relaton/iana/bibliography.rb +67 -14
  131. data/lib/relaton/iana/data_fetcher.rb +35 -5
  132. data/lib/relaton/iana/processor.rb +3 -1
  133. data/lib/relaton/iana.rb +12 -1
  134. data/lib/relaton/iec/data_fetcher.rb +7 -1
  135. data/lib/relaton/iec/hit_collection.rb +1 -1
  136. data/lib/relaton/iec/model/docidentifier.rb +9 -5
  137. data/lib/relaton/iec/model/ext.rb +2 -2
  138. data/lib/relaton/iec/processor.rb +1 -0
  139. data/lib/relaton/ieee/bibliography.rb +25 -3
  140. data/lib/relaton/ieee/data_fetcher.rb +158 -17
  141. data/lib/relaton/ieee/idams_parser.rb +18 -11
  142. data/lib/relaton/ieee/processor.rb +4 -1
  143. data/lib/relaton/ieee/rawbib_id_parser.rb +291 -86
  144. data/lib/relaton/ieee.rb +2 -1
  145. data/lib/relaton/ietf/data_fetcher.rb +295 -12
  146. data/lib/relaton/ietf/processor.rb +7 -3
  147. data/lib/relaton/ietf/rfc/entry.rb +39 -3
  148. data/lib/relaton/ietf/scraper.rb +69 -36
  149. data/lib/relaton/ietf.rb +4 -1
  150. data/lib/relaton/iho/bibliography.rb +1 -1
  151. data/lib/relaton/iho/docidentifier.rb +1 -1
  152. data/lib/relaton/index/file_io.rb +11 -11
  153. data/lib/relaton/index/file_storage.rb +6 -1
  154. data/lib/relaton/index/pool.rb +6 -1
  155. data/lib/relaton/index/shard_source.rb +201 -0
  156. data/lib/relaton/index/type.rb +63 -12
  157. data/lib/relaton/index.rb +2 -1
  158. data/lib/relaton/iso/bibliography.rb +20 -15
  159. data/lib/relaton/iso/data_fetcher.rb +3 -3
  160. data/lib/relaton/iso/data_parser.rb +17 -3
  161. data/lib/relaton/iso/hit_collection.rb +27 -15
  162. data/lib/relaton/iso/item_data.rb +22 -0
  163. data/lib/relaton/iso/model/docidentifier.rb +24 -12
  164. data/lib/relaton/iso/processor.rb +1 -0
  165. data/lib/relaton/iso/scraper.rb +19 -3
  166. data/lib/relaton/itu/bibliography.rb +9 -4
  167. data/lib/relaton/itu/data_crawler_r.rb +664 -0
  168. data/lib/relaton/itu/data_fetcher.rb +496 -50
  169. data/lib/relaton/itu/data_merge_r.rb +149 -0
  170. data/lib/relaton/itu/data_parser_r.rb +163 -89
  171. data/lib/relaton/itu/data_parser_t.rb +228 -0
  172. data/lib/relaton/itu/family_cache.rb +177 -0
  173. data/lib/relaton/itu/governor.rb +56 -0
  174. data/lib/relaton/itu/hit.rb +9 -3
  175. data/lib/relaton/itu/hit_collection.rb +258 -86
  176. data/lib/relaton/itu/model/docidentifier.rb +67 -1
  177. data/lib/relaton/itu/model/structured_identifier.rb +19 -0
  178. data/lib/relaton/itu/processor.rb +10 -4
  179. data/lib/relaton/itu/pubid.rb +27 -5
  180. data/lib/relaton/itu/recommendation_fields.rb +334 -0
  181. data/lib/relaton/itu/recommendation_parser.rb +18 -149
  182. data/lib/relaton/itu/scraper.rb +13 -3
  183. data/lib/relaton/itu.rb +2 -1
  184. data/lib/relaton/jcgm/bibdata.rb +8 -0
  185. data/lib/relaton/jcgm/bibitem.rb +8 -0
  186. data/lib/relaton/jcgm/bibliography.rb +97 -0
  187. data/lib/relaton/jcgm/data_fetcher.rb +81 -0
  188. data/lib/relaton/jcgm/docidentifier.rb +102 -0
  189. data/lib/relaton/jcgm/doctype.rb +12 -0
  190. data/lib/relaton/jcgm/ext.rb +23 -0
  191. data/lib/relaton/jcgm/item.rb +20 -0
  192. data/lib/relaton/jcgm/item_base.rb +18 -0
  193. data/lib/relaton/jcgm/item_data.rb +6 -0
  194. data/lib/relaton/jcgm/meetings_parser.rb +175 -0
  195. data/lib/relaton/jcgm/processor.rb +71 -0
  196. data/lib/relaton/jcgm/relation.rb +9 -0
  197. data/lib/relaton/jcgm/structured_identifier.rb +40 -0
  198. data/lib/relaton/jcgm/util.rb +8 -0
  199. data/lib/relaton/jcgm.rb +24 -0
  200. data/lib/relaton/jis/bibliography.rb +8 -10
  201. data/lib/relaton/jis/data_fetcher.rb +21 -19
  202. data/lib/relaton/jis/docidentifier.rb +104 -5
  203. data/lib/relaton/jis/hit.rb +18 -23
  204. data/lib/relaton/jis/hit_collection.rb +19 -18
  205. data/lib/relaton/jis/processor.rb +1 -1
  206. data/lib/relaton/jis.rb +2 -3
  207. data/lib/relaton/logger/channels/gh_issue.rb +78 -13
  208. data/lib/relaton/nist/data_fetcher.rb +63 -13
  209. data/lib/relaton/nist/docidentifier.rb +165 -0
  210. data/lib/relaton/nist/item.rb +2 -0
  211. data/lib/relaton/nist/item_base.rb +16 -0
  212. data/lib/relaton/nist/mods_parser.rb +38 -12
  213. data/lib/relaton/nist/processor.rb +2 -1
  214. data/lib/relaton/nist/relation.rb +3 -0
  215. data/lib/relaton/nist/scraper.rb +6 -3
  216. data/lib/relaton/oasis/bibliography.rb +147 -6
  217. data/lib/relaton/oasis/data_fetcher.rb +41 -5
  218. data/lib/relaton/oasis/data_parser_utils.rb +37 -3
  219. data/lib/relaton/oasis/docidentifier.rb +54 -0
  220. data/lib/relaton/oasis/item.rb +3 -0
  221. data/lib/relaton/oasis/processor.rb +7 -1
  222. data/lib/relaton/oasis.rb +14 -1
  223. data/lib/relaton/ogc/data_fetcher.rb +23 -2
  224. data/lib/relaton/ogc/docidentifier.rb +105 -0
  225. data/lib/relaton/ogc/hit_collection.rb +78 -3
  226. data/lib/relaton/ogc/processor.rb +2 -1
  227. data/lib/relaton/ogc.rb +5 -1
  228. data/lib/relaton/oiml/bibliography.rb +90 -15
  229. data/lib/relaton/oiml/docidentifier.rb +18 -3
  230. data/lib/relaton/omg/docidentifier.rb +67 -0
  231. data/lib/relaton/omg/item.rb +1 -0
  232. data/lib/relaton/omg/processor.rb +1 -0
  233. data/lib/relaton/omg/scraper.rb +61 -16
  234. data/lib/relaton/omg.rb +1 -0
  235. data/lib/relaton/plateau/bibliography.rb +10 -3
  236. data/lib/relaton/plateau/data_fetcher.rb +25 -2
  237. data/lib/relaton/plateau/handbook_parser.rb +8 -1
  238. data/lib/relaton/plateau/hit.rb +10 -2
  239. data/lib/relaton/plateau/hit_collection.rb +31 -11
  240. data/lib/relaton/plateau/processor.rb +3 -1
  241. data/lib/relaton/plateau/technical_report_parser.rb +8 -1
  242. data/lib/relaton/plateau.rb +2 -1
  243. data/lib/relaton/sdo/config.rb +34 -0
  244. data/lib/relaton/sdo/fetcher.rb +52 -0
  245. data/lib/relaton/sdo/logo.rb +95 -0
  246. data/lib/relaton/sdo/name.rb +26 -0
  247. data/lib/relaton/sdo/organization.rb +71 -0
  248. data/lib/relaton/sdo/store.rb +49 -0
  249. data/lib/relaton/sdo.rb +29 -0
  250. data/lib/relaton/version.rb +1 -1
  251. data/lib/relaton/w3c/bibliography.rb +132 -12
  252. data/lib/relaton/w3c/data_fetcher.rb +194 -16
  253. data/lib/relaton/w3c/data_parser.rb +3 -3
  254. data/lib/relaton/w3c/docidentifier.rb +48 -0
  255. data/lib/relaton/w3c/governor.rb +32 -0
  256. data/lib/relaton/w3c/item.rb +3 -0
  257. data/lib/relaton/w3c/pubid.rb +12 -0
  258. data/lib/relaton/w3c/safe_realize.rb +110 -21
  259. data/lib/relaton/w3c.rb +12 -1
  260. data/lib/relaton/xsf/bibliography.rb +61 -1
  261. data/lib/relaton/xsf/data_fetcher.rb +55 -5
  262. data/lib/relaton/xsf/docidentifier.rb +46 -0
  263. data/lib/relaton/xsf/hit_collection.rb +31 -3
  264. data/lib/relaton/xsf/item.rb +6 -0
  265. data/lib/relaton/xsf/processor.rb +1 -0
  266. data/lib/relaton/xsf.rb +5 -1
  267. data/lib/relaton.rb +42 -0
  268. metadata +135 -24
  269. data/lib/relaton/ieee/pub_id.rb +0 -161
  270. data/lib/relaton/index/id_number.rb +0 -30
@@ -28,12 +28,21 @@ module Relaton
28
28
  out
29
29
  end
30
30
 
31
+ # `ref` itself when it is a plain identifier; the wrapped member when an
32
+ # all-parts request wrapped it. pubid's `==` is class-strict, so
33
+ # comparing against index rows (always plain identifiers) needs this
34
+ # unwrapped form — `ref.root` would over-unwrap a supplement's own
35
+ # `.base` chain, which this must leave intact.
36
+ def ref_document
37
+ ref.all_parts? ? ref.identifiers.first : ref
38
+ end
39
+
31
40
  def ref_pubid_no_year
32
41
  @ref_pubid_no_year ||=
33
- if ref.base_identifier
34
- ref.dup.tap { |r| r.base_identifier = r.base_identifier.exclude(:date) }
42
+ if ref_document.base
43
+ ref_document.dup.tap { |r| r.base = r.base.exclude(:date) }
35
44
  else
36
- ref.exclude(:date)
45
+ ref_document.exclude(:date)
37
46
  end
38
47
  end
39
48
 
@@ -61,7 +70,7 @@ module Relaton
61
70
  end.map { |row| Hit.new row, self }
62
71
  # An all-parts query drops :part from the match, so multiple rows can
63
72
  # resolve to the same pubid; collapse them so each part appears once.
64
- @array.uniq! { |h| h.pubid.to_s } if ref.root.all_parts
73
+ @array.uniq! { |h| h.pubid.to_s } if ref.all_parts
65
74
  # Most-recent first (pubid string desc ~ year desc), then float
66
75
  # published-stage ids above drafts. An undated query excludes :stage
67
76
  # when matching, so a future draft (e.g. ISO/AWI) matches alongside the
@@ -97,21 +106,19 @@ module Relaton
97
106
  # `exclude` returns a fresh instance, so mutating this copy is safe.
98
107
  # Remove once pubid create() splits compound parts itself.
99
108
  def normalize_compound_part(pubid)
100
- num = pubid.part&.value.to_s
109
+ num = pubid.part.to_s
101
110
  return pubid unless pubid.subpart.nil? && num.include?("-")
102
111
 
103
- head, tail = num.split("-", 2)
104
- pubid.part = ::Pubid::Iso::Components::Code.new(value: head)
105
- pubid.subpart = ::Pubid::Iso::Components::Code.new(value: tail)
112
+ pubid.part, pubid.subpart = num.split("-", 2)
106
113
  pubid
107
114
  end
108
115
 
109
116
  def exclude_id_attrs(pubid, *attrs)
110
117
  xid = pubid.exclude(*attrs)
111
118
  curr = xid
112
- while curr.base_identifier
113
- curr.base_identifier = curr.base_identifier.exclude(*attrs)
114
- curr = curr.base_identifier
119
+ while curr.base
120
+ curr.base = curr.base.exclude(*attrs)
121
+ curr = curr.base
115
122
  end
116
123
  xid
117
124
  end
@@ -120,8 +127,13 @@ module Relaton
120
127
  return @excludings if defined? @excludings
121
128
 
122
129
  excl_attrs = %i[year]
123
- excl_attrs << :part if ref.root.part.nil? || ref.root.all_parts
124
- if default_published_stage?(ref) || ref.root.all_parts
130
+ excl_attrs << :part if ref.root.part.nil? || ref.all_parts
131
+ # `ref_document` (not `ref`), since an all-parts-wrapped `ref`'s own
132
+ # `typed_stage` is never set (always nil) — reading it directly would
133
+ # answer "no stage specified" for the wrapper regardless of the real
134
+ # underlying document's stage. Correct today only because this is
135
+ # OR'd with `ref.all_parts` (already true whenever wrapped).
136
+ if default_published_stage?(ref_document) || ref.all_parts
125
137
  excl_attrs << :stage
126
138
  excl_attrs << :iteration
127
139
  end
@@ -149,7 +161,7 @@ module Relaton
149
161
  @excludings = nil if options != opts
150
162
  @opts = options
151
163
 
152
- if !ref.root.all_parts || size == 1
164
+ if !ref.all_parts || size == 1
153
165
  any? && first.item # (opts[:lang])
154
166
  else
155
167
  to_all_parts
@@ -162,7 +174,7 @@ module Relaton
162
174
  if opts[:publication_date_before] || opts[:publication_date_after]
163
175
  parts = parts.select { |h| Bibliography.send(:year_in_range?, (h.pubid.date&.year || h.hit[:year]).to_i, opts) }
164
176
  end
165
- hit = parts.min_by { |h| h.pubid.part.value.to_i }
177
+ hit = parts.min_by { |h| h.pubid.part.to_i }
166
178
  return @array.first&.item unless hit
167
179
 
168
180
  bibitem = hit.item
@@ -12,8 +12,30 @@ module Relaton
12
12
  end
13
13
  end
14
14
 
15
+ # These item-level transforms rewrite every docidentifier in place
16
+ # (all-parts / date removal). That can collapse the `iso-undated`
17
+ # entry onto the primary, so re-run the same de-dup the builders apply
18
+ # at construction time (see DataParser#undated_docid).
19
+ def to_all_parts
20
+ drop_redundant_undated_docid(super)
21
+ end
22
+
23
+ def to_most_recent_reference
24
+ drop_redundant_undated_docid(super)
25
+ end
26
+
15
27
  private
16
28
 
29
+ def drop_redundant_undated_docid(item)
30
+ primary = item.docidentifier.find(&:primary)
31
+ return item unless primary
32
+
33
+ item.docidentifier = item.docidentifier.reject do |d|
34
+ !d.primary && d.type == "iso-undated" && d.to_s == primary.to_s
35
+ end
36
+ item
37
+ end
38
+
17
39
  def create_id_from_string(content, without_date)
18
40
  pubid = without_date ? content.sub(/:\d{4}$/, "") : content
19
41
  self.id = pubid.gsub(/\W+/, "")
@@ -68,13 +68,17 @@ module Relaton
68
68
  content.to_s
69
69
  end
70
70
 
71
+ # `remove_part!`/`remove_date!` are unnecessary here: `to_all_parts`'s
72
+ # own identity computation already excludes part/date (down the whole
73
+ # base chain, so a supplement's own year is dropped too — a disclosed
74
+ # pubid behavior change, not a bug; see spec/iso/…/docidentifier_spec.rb
75
+ # "#to_all_parts!"). `remove_stage!` stays: stage isn't one of the
76
+ # attributes pubid's `all_parts_edition_keys` strips.
71
77
  def to_all_parts!
72
78
  return unless @pubid
73
79
 
74
- remove_part!
75
- remove_date!
76
80
  remove_stage!
77
- @pubid.all_parts = true
81
+ @pubid = @pubid.to_all_parts
78
82
  refresh_content!
79
83
  end
80
84
 
@@ -94,13 +98,7 @@ module Relaton
94
98
  return @raw_content if @raw_content
95
99
  return nil unless @pubid
96
100
 
97
- pubid = @pubid.exclude(:date)
98
- current = pubid
99
- while current.base_identifier
100
- current.base_identifier = current.base_identifier.exclude(:date)
101
- current = current.base_identifier
102
- end
103
- pubid
101
+ exclude_date(@pubid)
104
102
  end
105
103
 
106
104
  private
@@ -109,19 +107,33 @@ module Relaton
109
107
  case type
110
108
  when "URN" then pubid.to_urn
111
109
  when "ISO" then pubid.exclude(:languages).to_s
110
+ when "iso-undated" then exclude_date(pubid).exclude(:languages).to_s
112
111
  else
113
112
  pubid.to_s
114
113
  end
115
114
  end
116
115
 
116
+ # Return a copy of +pubid+ with the year removed from it and every
117
+ # identifier in its `base` chain (e.g. the base of an
118
+ # amendment/corrigendum). The original is left untouched.
119
+ def exclude_date(pubid)
120
+ result = pubid.exclude(:date)
121
+ current = result
122
+ while current.base
123
+ current.base = current.base.exclude(:date)
124
+ current = current.base
125
+ end
126
+ result
127
+ end
128
+
117
129
  def remove_attr!(attr)
118
130
  return unless @pubid
119
131
 
120
132
  @pubid.send("#{attr}=", nil)
121
- base = @pubid.base_identifier
133
+ base = @pubid.base
122
134
  while base
123
135
  base.send("#{attr}=", nil)
124
- base = base.base_identifier
136
+ base = base.base
125
137
  end
126
138
  refresh_content!
127
139
  end
@@ -8,6 +8,7 @@ module Relaton
8
8
  def initialize # rubocop:disable Lint/MissingSuper
9
9
  @short = :relaton_iso
10
10
  @prefix = "ISO"
11
+ @pubid_flavor = :Iso # global prefixes sourced from Pubid::Iso.prefixes
11
12
  @defaultprefix = %r{^ISO(/IEC)?\s}
12
13
  @idtype = "ISO"
13
14
  @datasets = %w[iso-open-data iso-open-data-all]
@@ -104,7 +104,7 @@ module Relaton
104
104
  return @pubid if @pubid
105
105
 
106
106
  @pubid = ::Pubid::Iso::Identifier.parse(id)
107
- @pubid.root.edition ||= edition.content if @pubid.base_identifier
107
+ @pubid.root.edition ||= edition.content if @pubid.base
108
108
  @pubid
109
109
  rescue StandardError => e
110
110
  Util.error "Failed to parse pubid from #{id}: #{e.message}"
@@ -128,11 +128,27 @@ module Relaton
128
128
  # @return [Array<RelatonBib::DocumentIdentifier>]
129
129
  #
130
130
  def fetch_relaton_docids
131
+ primary = Docidentifier.new(content: pubid, type: "ISO", primary: true)
131
132
  [
132
- Docidentifier.new(content: pubid, type: "ISO", primary: true),
133
+ primary,
134
+ undated_docid(primary),
133
135
  Docidentifier.new(content: isoref, type: "iso-reference"),
134
136
  Docidentifier.new(content: urn, type: "URN"),
135
- ]
137
+ ].compact
138
+ end
139
+
140
+ #
141
+ # Create the undated reference docid (e.g. `ISO 123` from `ISO 123:2001`).
142
+ # Returns nil for an already-undated identifier so it does not duplicate
143
+ # the primary.
144
+ #
145
+ # @return [Relaton::Iso::Docidentifier, nil]
146
+ #
147
+ def undated_docid(primary)
148
+ undated = Docidentifier.new(content: pubid, type: "iso-undated")
149
+ undated unless undated.to_s == primary.to_s
150
+ rescue StandardError
151
+ nil
136
152
  end
137
153
 
138
154
  #
@@ -43,10 +43,13 @@ module Relaton
43
43
 
44
44
  def fetch_ref_err(refid, missed_years)
45
45
  Util.info "Not found.", key: refid.to_s
46
- if missed_years.any?
47
- plural = missed_years.size > 1 ? "s" : ""
46
+ # one hit per edition means a year can repeat (a recommendation and its
47
+ # amendment); the requested year itself is not a "different year" hint
48
+ years = missed_years.uniq.reject { |y| y == refid.year }
49
+ if years.any?
50
+ plural = years.size > 1 ? "s" : ""
48
51
  Util.info "There was no match for `#{refid.year}` year, though there were matches " \
49
- "found for `#{missed_years.join('`, `')}` year#{plural}.", key: refid.to_s
52
+ "found for `#{years.join('`, `')}` year#{plural}.", key: refid.to_s
50
53
  end
51
54
  nil
52
55
  end
@@ -70,7 +73,9 @@ module Relaton
70
73
  return { ret: ret } if ret
71
74
  end
72
75
 
73
- missed_years << pyear
76
+ # a hit whose code carries no year contributes nothing to the
77
+ # "matches found for `<year>`" hint
78
+ missed_years << pyear if pyear
74
79
  end
75
80
  { years: missed_years }
76
81
  end