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
@@ -3,8 +3,36 @@ module Relaton
3
3
  module Bibliography
4
4
  extend self
5
5
 
6
+ #
7
+ # Search the index for a reference.
8
+ #
9
+ # The reference is parsed into a `Pubid::Xsf::Identifier` here and the
10
+ # identifier -- never the string -- is what reaches `HitCollection`.
11
+ # `Index::Type#search_candidates` narrows only when its argument is not a
12
+ # `String`, so parsing at the entry point is what lets the lookup binary
13
+ # search; `Core::HitCollection` takes a `String` or a pubid by design.
14
+ #
15
+ # An unrecognized reference **raises**; like ISO, ETSI and 3GPP we let it
16
+ # propagate. relaton-cli rescues `Pubid::Errors::Error` and renders
17
+ # `"..." is not a recognized standards identifier`
18
+ # (`gems/relaton-cli/lib/relaton/cli/command.rb:324`,
19
+ # `subcommand_collection.rb:134`), and `Db#fetch` logs it via the
20
+ # `StandardError` arm at `lib/relaton/db.rb:122`. Rescuing here would
21
+ # collapse "this identifier is malformed" into "no such document", and a
22
+ # caller could no longer tell them apart.
23
+ #
24
+ # There is also deliberately no substring fallback: the old
25
+ # `index.search(ref)` compared a substring of the rendered id, so a bare
26
+ # `001` answered with 11 documents and `#get` took `.first` -- a truncated
27
+ # reference silently resolved to whichever sorted first.
28
+ #
29
+ # @param ref [String] e.g. "XEP 0001", "XEP-0001", "0001"
30
+ #
31
+ # @return [Relaton::Xsf::HitCollection]
32
+ # @raise [Pubid::Errors::ParseError] if the reference is not an XEP id
33
+ #
6
34
  def search(ref)
7
- HitCollection.new(ref).search
35
+ HitCollection.new(parse_ref(ref)).search
8
36
  end
9
37
 
10
38
  def get(code, _year = nil, _opts = {})
@@ -19,6 +47,38 @@ module Relaton
19
47
  Util.info "Found: `#{bib.docidentifier.first.content}`", key: code
20
48
  bib
21
49
  end
50
+
51
+ #
52
+ # Parse a user reference into a `Pubid::Xsf::Identifier`, or nil.
53
+ #
54
+ # `Pubid::Xsf` accepts only the canonical `XEP 0001` spelling, so two
55
+ # forms are normalized first:
56
+ #
57
+ # - **`XEP-0001`**, the spelling xmpp.org itself uses everywhere. It did
58
+ # not resolve before either (the substring match compared against
59
+ # `XEP 0001`, which has a space), so this is new support rather than a
60
+ # preserved behaviour.
61
+ # - **A bare `0001`**, which the substring match did resolve, so it has to
62
+ # keep working. The publisher token is added, the W3C idiom.
63
+ #
64
+ # The token match is case-insensitive, so `xep 0001` resolves too.
65
+ #
66
+ # Anything else raises -- see `.search`. `Pubid::Errors::ParseError`
67
+ # includes `Pubid::Errors::Error`, which is the class relaton-cli rescues.
68
+ #
69
+ # @param ref [String]
70
+ # @return [Pubid::Xsf::Identifier]
71
+ # @raise [Pubid::Errors::ParseError]
72
+ #
73
+ def parse_ref(ref)
74
+ ::Pubid::Xsf::Identifier.parse normalize_ref(ref)
75
+ end
76
+
77
+ private
78
+
79
+ def normalize_ref(ref)
80
+ "XEP #{ref.to_s.strip.sub(/\AXEP[-\s]+/i, '')}"
81
+ end
22
82
  end
23
83
  end
24
84
  end
@@ -3,8 +3,19 @@ require "relaton/core"
3
3
  module Relaton
4
4
  module Xsf
5
5
  class DataFetcher < Relaton::Core::DataFetcher
6
+ # `Core::DataFetcher#log_error` raises unless the flavor overrides it, so
7
+ # `report_errors` is unusable without this. (The ECMA precedent.)
8
+ def log_error(msg)
9
+ Util.error msg
10
+ end
11
+
6
12
  def index
7
- @index ||= Relaton::Index.find_or_create :xsf, file: "#{INDEXFILE}.yaml"
13
+ # `pubid_class:` on the producer too: FileIO#save only calls `to_hash`
14
+ # when the value is an instance of it, so without it the crawl writes
15
+ # v1-shaped rows under a v2 name, silently.
16
+ @index ||= Relaton::Index.find_or_create(
17
+ :xsf, file: "#{INDEXFILE}.yaml", pubid_class: ::Pubid::Xsf::Identifier
18
+ )
8
19
  end
9
20
 
10
21
  def fetch(_source = nil)
@@ -18,6 +29,7 @@ module Relaton
18
29
  Util.warn "Failed to parse #{link[:href]}: #{e.message}"
19
30
  end
20
31
  index.save
32
+ report_errors
21
33
  end
22
34
 
23
35
  def save_doc(bib)
@@ -30,14 +42,52 @@ module Relaton
30
42
  id = docid&.content
31
43
  return unless id
32
44
 
33
- file = output_file id
45
+ # Distinct docids can sanitize to one filename; take a path of our own
46
+ # rather than overwriting the other document (Core#unique_output_file).
47
+ file = unique_output_file id
34
48
  if @files.include? file
49
+ # Same reserved path == same id: a genuine duplicate. Checked FIRST,
50
+ # because a disambiguated path stays != output_file forever.
35
51
  Util.warn "File #{file} already exists"
36
- else
37
- @files << file
52
+ elsif file != output_file(id)
53
+ Util.warn "File #{output_file id} already exists; writing #{file} instead"
38
54
  end
55
+ @files << file
39
56
  File.write file, serialize(bib), encoding: "UTF-8"
40
- index.add_or_update id, file
57
+ add_to_index id, file
58
+ end
59
+
60
+ #
61
+ # Index a document under its pubid, skipping one pubid cannot parse.
62
+ #
63
+ # This guard is not optional here. One unparseable row does not fail that
64
+ # row: `Relaton::Index` declares the **whole file** corrupt, deletes it,
65
+ # and hands back an **empty** index. Measured — 519 good rows plus one
66
+ # unparseable id loads as 0 rows, and the only trace is two INFO lines
67
+ # ("Wrong structure of file …", "Considering … corrupt, removing it"). So
68
+ # indexing one bad row silently breaks every XSF lookup, not just its own.
69
+ #
70
+ # A rejection is recorded in `@errors`, which `report_errors` turns into a
71
+ # GitHub issue at the end of the crawl (the 3GPP/ECMA precedent). Nothing
72
+ # in the published corpus trips it today: pubid parses all 520 rows,
73
+ # including the two entries that are pages rather than XEPs — the XEP
74
+ # repository's `README` and its `xep-xxxx` template, which pubid accepts
75
+ # as the literal numbers `README` and `xxxx` while still rejecting
76
+ # anything else non-numeric (`XEP banana`, or a typo like `XEP 00O1`).
77
+ # So a recorded error now means something genuinely new appeared, which
78
+ # is exactly when an issue is worth filing.
79
+ #
80
+ # The data file is written either way, so a document that cannot be
81
+ # indexed is unindexed, never lost.
82
+ #
83
+ # @param docid [String]
84
+ # @param file [String]
85
+ #
86
+ def add_to_index(docid, file)
87
+ index.add_or_update ::Pubid::Xsf::Identifier.parse(docid), file
88
+ rescue StandardError => e
89
+ @errors[docid] =
90
+ "Unparseable primary id `#{docid}` was not indexed (#{e.message})"
41
91
  end
42
92
 
43
93
  def to_yaml(bib)
@@ -0,0 +1,46 @@
1
+ module Relaton
2
+ module Xsf
3
+ # An XSF document identifier, backed by `Pubid::Xsf`.
4
+ #
5
+ # Parses its `content` into a `Pubid::Xsf::Identifier` kept in `@pubid`,
6
+ # while the lutaml `content` attribute stays a plain **string** for
7
+ # serialization. Parsing is **soft**: `content=` lazily requires pubid and
8
+ # rescues `LoadError`/`StandardError`, so a missing gem or non-XSF content
9
+ # leaves `@pubid` nil rather than raising during deserialization.
10
+ #
11
+ # **It deliberately implements none of `remove_part!` / `remove_date!` /
12
+ # `to_all_parts!`.** An XEP identifier is a publisher and a number and
13
+ # nothing else — no part, no edition, no date — so there is genuinely
14
+ # nothing for any of them to strip, and `Bib::Docidentifier` already
15
+ # defaults all three to no-ops for exactly that case. Empty overrides here
16
+ # would assert a flavor-specific rule that does not exist. Compare
17
+ # `Relaton::Ogc::Docidentifier`, which overrides `remove_date!` because OGC
18
+ # really does carry a revision.
19
+ #
20
+ # So this class exists for `#pubid`: it gives consumers the structured
21
+ # identifier off a docidentifier, the way every other pubid-backed flavor
22
+ # does, without changing what is serialized.
23
+ class Docidentifier < Bib::Docidentifier
24
+ attr_reader :pubid
25
+
26
+ def initialize(attrs = {}, options = {})
27
+ pubid = attrs.is_a?(Hash) ? attrs.delete(:pubid) : nil
28
+ attrs[:content] ||= pubid.to_s if pubid
29
+ super
30
+ @pubid = pubid if pubid
31
+ end
32
+
33
+ def content=(value)
34
+ super
35
+ return unless value
36
+
37
+ @pubid = begin
38
+ require "pubid"
39
+ ::Pubid::Xsf::Identifier.parse(value)
40
+ rescue LoadError, StandardError
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -3,11 +3,29 @@ module Relaton
3
3
  class HitCollection < Relaton::Core::HitCollection
4
4
  GHDATA_URL = "https://raw.githubusercontent.com/relaton/relaton-data-xsf/v2/".freeze
5
5
 
6
+ #
7
+ # Find the index rows for the identifier this collection was built with.
8
+ #
9
+ # `ref` is a `Pubid::Xsf::Identifier` -- `Bibliography.parse_ref` does that
10
+ # step, and raises rather than returning nil for an unrecognized
11
+ # reference. Passing the identifier rather than a string is what enables
12
+ # the binary search on `id.root.number`. The nil guard in `#rows` is
13
+ # defensive only: `Core::HitCollection` permits a nil `ref`, and an empty
14
+ # result beats a NoMethodError if some other caller constructs one.
15
+ #
16
+ # An XEP identifier is only a publisher and a number: no edition, no date,
17
+ # no part. So the reference states everything, and `Type#search`'s default
18
+ # subset match (`Pubid::SubsetMatch`) is a plain equality -- which is the
19
+ # point. Ids are unique, one row per XEP, so there is no selection order
20
+ # to apply either.
21
+ #
22
+ # @return [self]
23
+ #
6
24
  def search
7
- @array = index.search(ref).sort_by { |hit| hit[:id] }.map do |row|
8
- Hit.new url: "#{GHDATA_URL}#{row[:file]}"
9
- end
25
+ @array = rows.map { |row| Hit.new url: "#{GHDATA_URL}#{row[:file]}" }
10
26
  self
27
+ rescue Relaton::RequestError
28
+ raise
11
29
  rescue StandardError => e
12
30
  raise Relaton::RequestError, e.message
13
31
  end
@@ -17,8 +35,18 @@ module Relaton
17
35
  :xsf,
18
36
  url: "#{GHDATA_URL}#{INDEXFILE}.zip",
19
37
  file: "#{INDEXFILE}.yaml",
38
+ pubid_class: ::Pubid::Xsf::Identifier,
20
39
  )
21
40
  end
41
+
42
+ private
43
+
44
+ def rows
45
+ return [] unless ref
46
+
47
+ index.search(ref)
48
+ .sort_by { |row| row[:id].to_s }
49
+ end
22
50
  end
23
51
  end
24
52
  end
@@ -1,7 +1,13 @@
1
+ require_relative "docidentifier"
2
+
1
3
  module Relaton
2
4
  module Xsf
3
5
  class Item < Bib::Item
4
6
  model ItemData
7
+
8
+ # Narrow the inherited `docidentifier` to the flavor's own class, so a
9
+ # deserialized item exposes `#pubid` on each id. (The OGC/ECMA shape.)
10
+ attribute :docidentifier, Docidentifier, collection: true, initialize_empty: true
5
11
  end
6
12
  end
7
13
  end
@@ -12,6 +12,7 @@ module Relaton
12
12
  @defaultprefix = %r{^XEP\s}
13
13
  @idtype = "XEP"
14
14
  @datasets = %w[xep-xmpp]
15
+ @pubid_flavor = :Xsf
15
16
  end
16
17
 
17
18
  def get(code, date, opts)
data/lib/relaton/xsf.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "mechanize"
4
+ # pubid loads with the flavor, for the ::Pubid::Xsf::Identifier that the
5
+ # index code names. Processor#remove_index_file names no pubid class: the
6
+ # delete never reads the index (see lib/relaton/index/CLAUDE.md).
7
+ require "pubid"
4
8
  require "relaton/index"
5
9
  require "relaton/bib"
6
10
  require_relative "version"
@@ -15,7 +19,7 @@ require_relative "xsf/bibliography"
15
19
 
16
20
  module Relaton
17
21
  module Xsf
18
- INDEXFILE = "index-v1"
22
+ INDEXFILE = "index-v2".freeze
19
23
 
20
24
  class Error < StandardError; end
21
25
 
data/lib/relaton.rb CHANGED
@@ -12,6 +12,7 @@ module Relaton
12
12
  autoload :Index, "relaton/index"
13
13
  autoload :Bib, "relaton/bib"
14
14
  autoload :ThreeGpp, "relaton/3gpp"
15
+ autoload :Adobe, "relaton/adobe"
15
16
  autoload :Bipm, "relaton/bipm"
16
17
  autoload :Calconnect, "relaton/calconnect"
17
18
  autoload :Ccsds, "relaton/ccsds"
@@ -19,13 +20,17 @@ module Relaton
19
20
  autoload :Cie, "relaton/cie"
20
21
  autoload :Ecma, "relaton/ecma"
21
22
  autoload :Etsi, "relaton/etsi"
23
+ autoload :Easc, "relaton/easc"
24
+ autoload :Gost, "relaton/gost"
22
25
  autoload :Iana, "relaton/iana"
26
+ autoload :Iala, "relaton/iala"
23
27
  autoload :Ieee, "relaton/ieee"
24
28
  autoload :Ietf, "relaton/ietf"
25
29
  autoload :Iho, "relaton/iho"
26
30
  autoload :Isbn, "relaton/isbn"
27
31
  autoload :Iso, "relaton/iso"
28
32
  autoload :Itu, "relaton/itu"
33
+ autoload :Jcgm, "relaton/jcgm"
29
34
  autoload :Nist, "relaton/nist"
30
35
  autoload :Oasis, "relaton/oasis"
31
36
  autoload :Oiml, "relaton/oiml"
@@ -40,6 +45,43 @@ module Relaton
40
45
  autoload :Ogc, "relaton/ogc"
41
46
  autoload :Plateau, "relaton/plateau"
42
47
  autoload :Doi, "relaton/doi"
48
+ autoload :Sdo, "relaton/sdo"
49
+
50
+ # Global PubID prefix register (relaton-db#103). Maps an SDO document-ID
51
+ # prefix to the flavor module(s) that own it. Conflicting prefixes (e.g.
52
+ # "ISO/IEC", claimed by both ISO and IEC) return several flavors.
53
+ #
54
+ # Relaton.prefix_flavor("NIST") # => [Relaton::Nist]
55
+ # Relaton.prefix_flavor("ISO/IEC") # => [Relaton::Iec, Relaton::Iso]
56
+ # Relaton.prefix_flavor("BOGUS") # => []
57
+ #
58
+ # NOTE: returning the flavor module forces that flavor's lazy load. To resolve
59
+ # a prefix without loading flavor code, use
60
+ # `Relaton::Db::Registry.instance.processors_by_prefix(prefix)`.
61
+ #
62
+ # @param prefix [String]
63
+ # @return [Array<Module>]
64
+ def self.prefix_flavor(prefix)
65
+ Db::Registry.instance.flavors_by_prefix(prefix)
66
+ end
67
+
68
+ # SDO organization & logo store (metanorma#346, relaton-db#132). Looks up a
69
+ # standards body by abbreviation and returns its metadata — names/translations
70
+ # and logo variants — from the `relaton-data-sdo` data repo. This is a
71
+ # non-flavor store: no processor, no Db::Registry entry.
72
+ #
73
+ # org = Relaton.organization("ISO")
74
+ # org.name # default name
75
+ # org.name("fr") # translated name
76
+ # org.name(language: "fr") # translated name (keyword form)
77
+ # org.logo_query(format: "eps", style: "default") # matching logo variants
78
+ # org.logo(format: "eps", style: "default") # one logo
79
+ #
80
+ # @param abbreviation [String]
81
+ # @return [Relaton::Sdo::Organization, nil]
82
+ def self.organization(abbreviation)
83
+ Sdo::Store.instance.organization(abbreviation)
84
+ end
43
85
  end
44
86
 
45
87
  require "relaton/db"