relaton 3.0.7 → 3.1.0

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 (240) hide show
  1. checksums.yaml +4 -4
  2. data/bin/relaton +20 -0
  3. data/lib/relaton/3gpp/processor.rb +1 -1
  4. data/lib/relaton/3gpp.rb +3 -3
  5. data/lib/relaton/adobe/processor.rb +1 -1
  6. data/lib/relaton/adobe.rb +3 -3
  7. data/lib/relaton/bib/item_data.rb +2 -2
  8. data/lib/relaton/bib/model/docidentifier.rb +17 -2
  9. data/lib/relaton/bib.rb +2 -2
  10. data/lib/relaton/bibcollection.rb +146 -0
  11. data/lib/relaton/bibdata.rb +92 -0
  12. data/lib/relaton/bipm/data_outcomes_parser.rb +6 -1
  13. data/lib/relaton/bipm/processor.rb +1 -1
  14. data/lib/relaton/bipm.rb +3 -3
  15. data/lib/relaton/bsi/processor.rb +1 -1
  16. data/lib/relaton/bsi.rb +1 -1
  17. data/lib/relaton/calconnect/data_fetcher.rb +2 -2
  18. data/lib/relaton/calconnect/model/item.rb +1 -1
  19. data/lib/relaton/calconnect/processor.rb +1 -1
  20. data/lib/relaton/calconnect.rb +2 -2
  21. data/lib/relaton/ccsds/data/fetcher.rb +1 -1
  22. data/lib/relaton/ccsds/model/item.rb +1 -1
  23. data/lib/relaton/ccsds/processor.rb +1 -1
  24. data/lib/relaton/ccsds/util.rb +1 -1
  25. data/lib/relaton/ccsds.rb +1 -1
  26. data/lib/relaton/cen/processor.rb +1 -1
  27. data/lib/relaton/cen.rb +2 -2
  28. data/lib/relaton/cie/data_fetcher.rb +3 -3
  29. data/lib/relaton/cie/processor.rb +1 -1
  30. data/lib/relaton/cie.rb +2 -2
  31. data/lib/relaton/cli/base_convertor.rb +134 -0
  32. data/lib/relaton/cli/command.rb +396 -0
  33. data/lib/relaton/cli/data_fetcher.rb +20 -0
  34. data/lib/relaton/cli/frontend/dist/404.html +18 -0
  35. data/lib/relaton/cli/frontend/dist/app.iife.js +1 -0
  36. data/lib/relaton/cli/frontend/dist/style.css +3 -0
  37. data/lib/relaton/cli/frontend/index.html +14 -0
  38. data/lib/relaton/cli/frontend/package-lock.json +2945 -0
  39. data/lib/relaton/cli/frontend/package.json +29 -0
  40. data/lib/relaton/cli/frontend/public/404.html +18 -0
  41. data/lib/relaton/cli/frontend/src/App.test.ts +501 -0
  42. data/lib/relaton/cli/frontend/src/App.vue +506 -0
  43. data/lib/relaton/cli/frontend/src/app.ts +90 -0
  44. data/lib/relaton/cli/frontend/src/components/DocumentDetail.test.ts +142 -0
  45. data/lib/relaton/cli/frontend/src/components/DocumentDetail.vue +228 -0
  46. data/lib/relaton/cli/frontend/src/components/DocumentRow.vue +88 -0
  47. data/lib/relaton/cli/frontend/src/components/Icon.test.ts +44 -0
  48. data/lib/relaton/cli/frontend/src/components/Icon.vue +55 -0
  49. data/lib/relaton/cli/frontend/src/components/Pagination.vue +26 -0
  50. data/lib/relaton/cli/frontend/src/dev/main.ts +100 -0
  51. data/lib/relaton/cli/frontend/src/dev/sample-data.json +71 -0
  52. data/lib/relaton/cli/frontend/src/lib/filter.test.ts +88 -0
  53. data/lib/relaton/cli/frontend/src/lib/filter.ts +95 -0
  54. data/lib/relaton/cli/frontend/src/lib/hydrate.test.ts +102 -0
  55. data/lib/relaton/cli/frontend/src/lib/hydrate.ts +55 -0
  56. data/lib/relaton/cli/frontend/src/lib/shards.test.ts +319 -0
  57. data/lib/relaton/cli/frontend/src/lib/shards.ts +183 -0
  58. data/lib/relaton/cli/frontend/src/lib/types.ts +148 -0
  59. data/lib/relaton/cli/frontend/src/lib/url.test.ts +151 -0
  60. data/lib/relaton/cli/frontend/src/lib/url.ts +111 -0
  61. data/lib/relaton/cli/frontend/src/shims-vue.d.ts +5 -0
  62. data/lib/relaton/cli/frontend/src/styles/index.css +27 -0
  63. data/lib/relaton/cli/frontend/src/test/fetch.ts +58 -0
  64. data/lib/relaton/cli/frontend/tsconfig.json +20 -0
  65. data/lib/relaton/cli/frontend/vite.config.ts +42 -0
  66. data/lib/relaton/cli/frontend/vitest.config.ts +11 -0
  67. data/lib/relaton/cli/frontend_assets.rb +58 -0
  68. data/lib/relaton/cli/full_text_search.rb +98 -0
  69. data/lib/relaton/cli/i18n.yaml +1 -0
  70. data/lib/relaton/cli/index_item_normalizer.rb +380 -0
  71. data/lib/relaton/cli/index_site_generator.rb +1043 -0
  72. data/lib/relaton/cli/relaton_file.rb +290 -0
  73. data/lib/relaton/cli/subcommand_collection.rb +263 -0
  74. data/lib/relaton/cli/subcommand_db.rb +81 -0
  75. data/lib/relaton/cli/templates/_document.liquid +111 -0
  76. data/lib/relaton/cli/templates/_index.liquid +61 -0
  77. data/lib/relaton/cli/templates/index/page.liquid +20 -0
  78. data/lib/relaton/cli/templates/index-style.css +1017 -0
  79. data/lib/relaton/cli/util.rb +8 -0
  80. data/lib/relaton/cli/xml_convertor.rb +47 -0
  81. data/lib/relaton/cli/xml_to_html_renderer.rb +117 -0
  82. data/lib/relaton/cli/yaml_convertor.rb +102 -0
  83. data/lib/relaton/cli.rb +103 -0
  84. data/lib/relaton/core/processor.rb +1 -1
  85. data/lib/relaton/core.rb +1 -1
  86. data/lib/relaton/db/registry.rb +1 -1
  87. data/lib/relaton/db.rb +1 -1
  88. data/lib/relaton/doi/CLAUDE.md +1 -1
  89. data/lib/relaton/doi/parser.rb +2 -1
  90. data/lib/relaton/doi/processor.rb +1 -1
  91. data/lib/relaton/doi.rb +4 -4
  92. data/lib/relaton/easc/processor.rb +1 -1
  93. data/lib/relaton/easc.rb +3 -3
  94. data/lib/relaton/ecma/data_fetcher.rb +1 -1
  95. data/lib/relaton/ecma/processor.rb +1 -1
  96. data/lib/relaton/ecma.rb +2 -2
  97. data/lib/relaton/element_finder.rb +29 -0
  98. data/lib/relaton/etsi/data_fetcher.rb +2 -2
  99. data/lib/relaton/etsi/item.rb +1 -1
  100. data/lib/relaton/etsi/processor.rb +2 -2
  101. data/lib/relaton/etsi.rb +1 -1
  102. data/lib/relaton/evs/processor.rb +1 -1
  103. data/lib/relaton/evs.rb +2 -2
  104. data/lib/relaton/gb/CLAUDE.md +1 -1
  105. data/lib/relaton/gb/bibliography.rb +1 -1
  106. data/lib/relaton/gb/processor.rb +1 -1
  107. data/lib/relaton/gb.rb +2 -2
  108. data/lib/relaton/gost/processor.rb +1 -1
  109. data/lib/relaton/gost.rb +3 -3
  110. data/lib/relaton/iala/processor.rb +1 -1
  111. data/lib/relaton/iala.rb +3 -3
  112. data/lib/relaton/iana/data_fetcher.rb +1 -1
  113. data/lib/relaton/iana/processor.rb +1 -1
  114. data/lib/relaton/iana.rb +2 -2
  115. data/lib/relaton/iec/data_fetcher.rb +1 -1
  116. data/lib/relaton/iec/processor.rb +1 -1
  117. data/lib/relaton/iec.rb +2 -2
  118. data/lib/relaton/ieee/processor.rb +1 -1
  119. data/lib/relaton/ieee.rb +2 -2
  120. data/lib/relaton/ietf/CLAUDE.md +1 -1
  121. data/lib/relaton/ietf/data_fetcher.rb +1 -1
  122. data/lib/relaton/ietf/processor.rb +1 -1
  123. data/lib/relaton/ietf.rb +2 -2
  124. data/lib/relaton/iho/CLAUDE.md +3 -3
  125. data/lib/relaton/iho/bibliography.rb +41 -27
  126. data/lib/relaton/iho/hash_parser_v1.rb +1 -1
  127. data/lib/relaton/iho/processor.rb +4 -3
  128. data/lib/relaton/iho.rb +2 -2
  129. data/lib/relaton/index.rb +1 -1
  130. data/lib/relaton/isbn/processor.rb +1 -1
  131. data/lib/relaton/isbn.rb +1 -1
  132. data/lib/relaton/iso/hash_parser_v1.rb +1 -1
  133. data/lib/relaton/iso/processor.rb +1 -1
  134. data/lib/relaton/iso.rb +3 -3
  135. data/lib/relaton/itu/processor.rb +1 -1
  136. data/lib/relaton/itu.rb +3 -3
  137. data/lib/relaton/jcgm/processor.rb +1 -1
  138. data/lib/relaton/jcgm.rb +2 -2
  139. data/lib/relaton/jis/processor.rb +1 -1
  140. data/lib/relaton/jis.rb +2 -2
  141. data/lib/relaton/nist/CLAUDE.md +11 -1
  142. data/lib/relaton/nist/README.adoc +7 -1
  143. data/lib/relaton/nist/hit_collection.rb +25 -1
  144. data/lib/relaton/nist/mods_parser.rb +32 -8
  145. data/lib/relaton/nist/processor.rb +1 -1
  146. data/lib/relaton/nist/pubs_export.rb +69 -11
  147. data/lib/relaton/nist.rb +2 -2
  148. data/lib/relaton/oasis/processor.rb +1 -1
  149. data/lib/relaton/oasis.rb +2 -2
  150. data/lib/relaton/ogc/CLAUDE.md +1 -1
  151. data/lib/relaton/ogc/processor.rb +1 -1
  152. data/lib/relaton/ogc.rb +2 -2
  153. data/lib/relaton/oiml/processor.rb +1 -1
  154. data/lib/relaton/oiml.rb +2 -2
  155. data/lib/relaton/omg/CLAUDE.md +1 -1
  156. data/lib/relaton/omg/processor.rb +1 -1
  157. data/lib/relaton/omg.rb +1 -1
  158. data/lib/relaton/plateau/CLAUDE.md +1 -1
  159. data/lib/relaton/plateau/data_fetcher.rb +1 -1
  160. data/lib/relaton/plateau/processor.rb +1 -1
  161. data/lib/relaton/plateau.rb +2 -2
  162. data/lib/relaton/render/general.rb +319 -0
  163. data/lib/relaton/render/iso690/csl_import.rb +129 -0
  164. data/lib/relaton/render/iso690/element.rb +153 -0
  165. data/lib/relaton/render/iso690/elements/access.rb +44 -0
  166. data/lib/relaton/render/iso690/elements/authorizer.rb +45 -0
  167. data/lib/relaton/render/iso690/elements/citeid.rb +39 -0
  168. data/lib/relaton/render/iso690/elements/component_part.rb +97 -0
  169. data/lib/relaton/render/iso690/elements/creator.rb +267 -0
  170. data/lib/relaton/render/iso690/elements/edition.rb +97 -0
  171. data/lib/relaton/render/iso690/elements/extent.rb +71 -0
  172. data/lib/relaton/render/iso690/elements/identifier.rb +46 -0
  173. data/lib/relaton/render/iso690/elements/location.rb +73 -0
  174. data/lib/relaton/render/iso690/elements/medium.rb +32 -0
  175. data/lib/relaton/render/iso690/elements/numeration.rb +26 -0
  176. data/lib/relaton/render/iso690/elements/production.rb +111 -0
  177. data/lib/relaton/render/iso690/elements/pub_date.rb +63 -0
  178. data/lib/relaton/render/iso690/elements/series.rb +66 -0
  179. data/lib/relaton/render/iso690/elements/size.rb +45 -0
  180. data/lib/relaton/render/iso690/elements/status.rb +30 -0
  181. data/lib/relaton/render/iso690/elements/stddoc.rb +40 -0
  182. data/lib/relaton/render/iso690/elements/title.rb +56 -0
  183. data/lib/relaton/render/iso690/elements/updated.rb +38 -0
  184. data/lib/relaton/render/iso690/elements.rb +67 -0
  185. data/lib/relaton/render/iso690/fields.rb +142 -0
  186. data/lib/relaton/render/iso690/i18n/en.yml +48 -0
  187. data/lib/relaton/render/iso690/i18n/fr.yml +14 -0
  188. data/lib/relaton/render/iso690/i18n/ja.yml +38 -0
  189. data/lib/relaton/render/iso690/i18n.rb +83 -0
  190. data/lib/relaton/render/iso690/identifier_kinds.rb +29 -0
  191. data/lib/relaton/render/iso690/index_renderer.rb +57 -0
  192. data/lib/relaton/render/iso690/kinds.rb +53 -0
  193. data/lib/relaton/render/iso690/renderer.rb +150 -0
  194. data/lib/relaton/render/iso690/rules/bipm.rb +186 -0
  195. data/lib/relaton/render/iso690/rules/jis.rb +103 -0
  196. data/lib/relaton/render/iso690/rules/nist.rb +384 -0
  197. data/lib/relaton/render/iso690/rules.rb +227 -0
  198. data/lib/relaton/render/iso690/style/locale.rb +59 -0
  199. data/lib/relaton/render/iso690/style/name_form.rb +87 -0
  200. data/lib/relaton/render/iso690/style/scheme.rb +33 -0
  201. data/lib/relaton/render/iso690/style/sort_rule.rb +25 -0
  202. data/lib/relaton/render/iso690/style/template_map.rb +40 -0
  203. data/lib/relaton/render/iso690/style/type_template.rb +45 -0
  204. data/lib/relaton/render/iso690/style.rb +227 -0
  205. data/lib/relaton/render/iso690/styles/apa.yml +45 -0
  206. data/lib/relaton/render/iso690/styles/author-date.yml +31 -0
  207. data/lib/relaton/render/iso690/styles/chicago.yml +49 -0
  208. data/lib/relaton/render/iso690/styles/ieee-sa.yml +45 -0
  209. data/lib/relaton/render/iso690/styles/jis-en.yml +68 -0
  210. data/lib/relaton/render/iso690/styles/jis-ja.yml +67 -0
  211. data/lib/relaton/render/iso690/styles/lncs.yml +54 -0
  212. data/lib/relaton/render/iso690/styles/mla.yml +56 -0
  213. data/lib/relaton/render/iso690/template.rb +248 -0
  214. data/lib/relaton/render/iso690.rb +28 -0
  215. data/lib/relaton/sae/CLAUDE.md +89 -0
  216. data/lib/relaton/sae/bibdata.rb +8 -0
  217. data/lib/relaton/sae/bibitem.rb +8 -0
  218. data/lib/relaton/sae/bibliography.rb +128 -0
  219. data/lib/relaton/sae/data_fetcher.rb +219 -0
  220. data/lib/relaton/sae/doi_code.rb +83 -0
  221. data/lib/relaton/sae/item.rb +10 -0
  222. data/lib/relaton/sae/item_data.rb +6 -0
  223. data/lib/relaton/sae/processor.rb +62 -0
  224. data/lib/relaton/sae/util.rb +9 -0
  225. data/lib/relaton/sae.rb +37 -0
  226. data/lib/relaton/un/CLAUDE.md +1 -1
  227. data/lib/relaton/un/processor.rb +1 -1
  228. data/lib/relaton/un.rb +1 -1
  229. data/lib/relaton/version.rb +1 -1
  230. data/lib/relaton/w3c/bibliography.rb +1 -1
  231. data/lib/relaton/w3c/data_fetcher.rb +1 -1
  232. data/lib/relaton/w3c/processor.rb +1 -1
  233. data/lib/relaton/w3c.rb +2 -2
  234. data/lib/relaton/xsf/data_fetcher.rb +1 -1
  235. data/lib/relaton/xsf/processor.rb +1 -1
  236. data/lib/relaton/xsf.rb +2 -2
  237. data/lib/relaton-cli.rb +17 -0
  238. data/lib/relaton-render.rb +12 -0
  239. data/lib/relaton.rb +3 -2
  240. metadata +203 -23
@@ -0,0 +1,8 @@
1
+ module Relaton
2
+ module Cli
3
+ module Util
4
+ extend Relaton::Bib::Util
5
+ PROGNAME = "relaton-cli".freeze
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,47 @@
1
+ require "nokogiri"
2
+ require_relative "base_convertor"
3
+
4
+ module Relaton
5
+ module Cli
6
+ class XMLConvertor < Relaton::Cli::BaseConvertor
7
+ def to_yaml
8
+ convert_and_write(file_content, :to_yaml)
9
+ end
10
+
11
+ # Convert to YAML
12
+ #
13
+ # This interface allow us to convert any XML file to YAML.
14
+ # It only require us to provide a valid XML file and it can
15
+ # do converstion using default attributes, but it also allow
16
+ # us to provide custom options to customize this converstion
17
+ # process.
18
+ #
19
+ # @param file [File] The complete path to a XML file
20
+ # @param options [Hash] Options as hash key, value pairs.
21
+ #
22
+ def self.to_yaml(file, options = {})
23
+ new(file, options).to_yaml
24
+ end
25
+
26
+ private
27
+
28
+ def default_ext
29
+ "yaml"
30
+ end
31
+
32
+ # @param content [Nokogiri::XML::Document]
33
+ # @return [Hash]
34
+ def convert_content(content)
35
+ if %w[bibitem bibdata].include? content.root.name
36
+ Bibdata.from_xml(content)
37
+ else
38
+ Bibcollection.from_xml(content)
39
+ end
40
+ end
41
+
42
+ def file_content
43
+ Nokogiri::XML(File.read(file, encoding: "utf-8"))
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,117 @@
1
+ require "nokogiri"
2
+ require "liquid"
3
+
4
+ module Relaton::Cli
5
+ class XmlToHtmlRenderer
6
+ def initialize(liquid_dir: nil, stylesheet: nil)
7
+ @liquid_dir = liquid_dir
8
+ @stylesheet = read_file(stylesheet)
9
+ init_liquid_template_and_filesystem
10
+ end
11
+
12
+ # @param index_xml [String] Relaton XML
13
+ # @return [String] HTML
14
+ def render(index_xml)
15
+ Liquid::Template
16
+ .parse(template)
17
+ .render(build_liquid_document(index_xml))
18
+ end
19
+
20
+ def uri_for_extension(uri, extension)
21
+ uri&.sub(/\.[^.]+$/, ".#{extension}")
22
+ end
23
+
24
+ # Render HTML
25
+ #
26
+ # This interface allow us to convert a Relaton XML to HTML
27
+ # using the specified liquid template and stylesheets. It
28
+ # also do some minor clean during this conversion.
29
+ #
30
+ # @param file [String] Relaton XML
31
+ # @param options [Hash]
32
+ # @return [String] HTML
33
+ def self.render(file, options)
34
+ new(**options).render(file)
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :stylesheet, :liquid_dir, :template
40
+
41
+ def read_file(file)
42
+ File.read(file, encoding: "utf-8")
43
+ end
44
+
45
+ # rubocop:disable Metrics/MethodLength
46
+ # @param source [String] Relaton XML
47
+ def build_liquid_document(source)
48
+ bibcollection = build_bibcollection(source)
49
+ hash_to_liquid(
50
+ depth: 2,
51
+ css: stylesheet,
52
+ title: bibcollection.title,
53
+ date: DateTime.now.to_s,
54
+ author: bibcollection.author,
55
+ documents: document_items(bibcollection)
56
+ )
57
+ end
58
+
59
+ def init_liquid_template_and_filesystem
60
+ file_system = Liquid::LocalFileSystem.new(liquid_dir)
61
+ @template = read_file(file_system.full_path("index"))
62
+
63
+ Liquid::Template.file_system = file_system
64
+ end
65
+
66
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
+
68
+ # TODO: This should be recursive, but it's not
69
+ # @param hash [Hash]
70
+ # @option hash [Integer] :dept
71
+ # @option hash [String] :css path to stylesheet file
72
+ # @option hash [String] :title
73
+ # @option hash [String] :author
74
+ # @option hash [Array<Hash>] :documents
75
+ #
76
+ # @return [Hash]
77
+ def hash_to_liquid(hash)
78
+ hash.map do |key, value|
79
+ case key
80
+ when "title"
81
+ if value.is_a?(Array)
82
+ title = value.detect { |t| t["type"] == "main" } || value.first
83
+ v = title ? title["content"] : nil
84
+ elsif value.is_a?(Hash) then v = value["content"]
85
+ else v = value
86
+ end
87
+ when "docidentifier"
88
+ did = if value.is_a?(Array)
89
+ value.detect { |d| (d["id"] || d["content"]).to_s !~ /^(http|https):\/\// } ||
90
+ value.first
91
+ else value
92
+ end
93
+ v = did
94
+ else v = value
95
+ end
96
+ [key.to_s, empty2nil(v)]
97
+ end.to_h
98
+ end
99
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
100
+
101
+ def empty2nil(value)
102
+ value unless value.is_a?(String) && value.empty? && !value.nil?
103
+ end
104
+
105
+ # @param source [String] Relaton XML
106
+ # @return [Relaton::Bibcollection]
107
+ def build_bibcollection(source)
108
+ Relaton::Bibcollection.from_xml(Nokogiri::XML(source))
109
+ end
110
+
111
+ # @param bibcollection [Relaton::Bibcollection]
112
+ # @return [Array<Hash>]
113
+ def document_items(bibcollection)
114
+ bibcollection.to_h["root"]["items"].map { |item| hash_to_liquid(item) }
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,102 @@
1
+ require "yaml"
2
+ require_relative "base_convertor"
3
+ require_relative "../bib"
4
+
5
+ module Relaton
6
+ module Cli
7
+ class YAMLConvertor < Relaton::Cli::BaseConvertor
8
+ def to_xml
9
+ if writable
10
+ convert_and_write(file_content, :to_xml)
11
+ else
12
+ convert_content(file_content).to_xml date_format: :full, bibdata: true
13
+ end
14
+ end
15
+
16
+ class << self
17
+ # Convert to XML
18
+ #
19
+ # This interface allow us to convert any YAML file to XML.
20
+ # It only require us to provide a valid YAML file and it can
21
+ # do converstion using default attributes, but it also allow
22
+ # us to provide custom options to customize this converstion
23
+ # process.
24
+ #
25
+ # @param file [File] The complete path to a YAML file
26
+ # @param options [Hash] Options as hash key, value pairs.
27
+ #
28
+ def to_xml(file, options = {})
29
+ new(file, options).to_xml
30
+ end
31
+
32
+ # @param content [Hash] document in YAML format
33
+ # @return [RelatonBib::BibliographicItem,
34
+ # RelatonIso::IsoBiblioraphicItem]
35
+ def convert_single_file(content)
36
+ flavor = content.dig("ext", "flavor") || doctype(content["docidentifier"])
37
+ if (processor = Relaton::Db::Registry.instance.by_type(flavor))
38
+ begin
39
+ processor.from_yaml content.to_yaml
40
+ rescue RuntimeError
41
+ Relaton::Bib::Item.from_yaml(content.to_yaml)
42
+ end
43
+ else
44
+ Relaton::Bib::Item.from_yaml(content.to_yaml)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @param content [Hash]
51
+ # @return [String]
52
+ def doctype(docid)
53
+ did = docid.is_a?(Array) ? docid.fetch(0) : docid
54
+ return unless did
55
+
56
+ did["type"] || did.fetch("content")&.match(/^\w+/)&.to_s
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def default_ext
63
+ "rxl"
64
+ end
65
+
66
+ def file_content
67
+ date_to_string(YAML.load_file(file))
68
+ end
69
+
70
+ def date_to_string(obj)
71
+ if obj.is_a? Hash
72
+ obj.reduce({}) do |memo, (k, v)|
73
+ memo[k] = date_to_string(v)
74
+ memo
75
+ end
76
+ elsif obj.is_a? Array
77
+ obj.reduce([]) { |memo, v| memo << date_to_string(v) }
78
+ else
79
+ obj.is_a?(Date) ? obj.to_s : obj
80
+ end
81
+ end
82
+
83
+ def convert_collection(content)
84
+ if content.has_key?("root")
85
+ content["root"]["items"] = content["root"]["items"].map do |i|
86
+ # RelatonBib::HashConverter::hash_to_bib(i)
87
+ self.class.convert_single_file(i)
88
+ end
89
+ Relaton::Bibcollection.new(content["root"])
90
+ end
91
+ end
92
+
93
+ def xml_content(_raw_file)
94
+ convert_content(file_content).to_xml(date_format: :full, bibdata: true)
95
+ end
96
+
97
+ def convert_content(content)
98
+ convert_collection(content) || self.class.convert_single_file(content)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,103 @@
1
+ require "fileutils"
2
+ require "thor"
3
+ require "thor/hollaback"
4
+ require_relative "cli/util"
5
+ require_relative "cli/command"
6
+
7
+ module Relaton
8
+ def self.db(dir = nil)
9
+ Cli.relaton dir
10
+ end
11
+
12
+ module Cli
13
+ class RelatonDb
14
+ include Singleton
15
+
16
+ DBCONF = "#{Dir.home}/.relaton/dbpath".freeze
17
+
18
+ # @param dir [String, nil]
19
+ # @return [Relaton::Db]
20
+ def db(dir)
21
+ if dir
22
+ FileUtils.mkdir_p File.dirname(DBCONF)
23
+ File.write DBCONF, dir, encoding: "UTF-8"
24
+ @db = Relaton::Db.new dir, nil
25
+ else
26
+ @db ||= Relaton::Db.new dbpath, nil
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # @return [String] path to DB
33
+ def dbpath
34
+ if File.exist?(DBCONF)
35
+ File.read(DBCONF, encoding: "UTF-8")
36
+ else "#{Dir.home}/.relaton/cache"
37
+ end
38
+ end
39
+ end
40
+
41
+ class << self
42
+ def version
43
+ # One gem, one version.
44
+ puts "relaton => #{Relaton::VERSION}"
45
+ end
46
+
47
+ def start(arguments)
48
+ Relaton::Cli::Command.start(arguments)
49
+ end
50
+
51
+ # Relaton
52
+ #
53
+ # Based on current setup, we need to initiate a Db instance to
54
+ # register all of it's supported processor backends. To make it
55
+ # easier we have added it as a class method so we can use this
56
+ # whenever necessary.
57
+ #
58
+ # @param dir [String, nil]
59
+ # @return [Relaton::Db]
60
+ def relaton(dir)
61
+ RelatonDb.instance.db dir
62
+ end
63
+
64
+ # @param content [Nokogiri::XML::Document]
65
+ # @return [RelatonBib::BibliographicItem,
66
+ # RelatonIsoBib::IsoBibliongraphicItem]
67
+ def parse_xml(doc)
68
+ doc.remove_namespaces! if doc.respond_to?(:remove_namespaces!)
69
+ if (proc = Cli.processor(doc))
70
+ proc.from_xml(doc.to_s)
71
+ else
72
+ Relaton::Bib::Item.from_xml(doc.to_s) rescue nil
73
+ end
74
+ end
75
+
76
+ # @param doc [Nokogiri::XML::Element]
77
+ # @return [RelatonIso::Processor, RelatonIec::Processor,
78
+ # RelatonNist::Processor, RelatonIetf::Processot,
79
+ # RelatonItu::Processor, RelatonGb::Processor,
80
+ # RelatonOgc::Processor, RelatonCalconnect::Processor]
81
+ def processor(doc)
82
+ docid = doc.at "docidentifier"
83
+ proc = get_proc docid
84
+ return proc if proc
85
+
86
+ Relaton::Db::Registry.instance.by_type(docid&.text&.match(/^\w+/)&.to_s)
87
+ end
88
+
89
+ private
90
+
91
+ # @param doc [Nokogiri::XML::Element]
92
+ # @return [RelatonIso::Processor, RelatonIec::Processor,
93
+ # RelatonNist::Processor, RelatonIetf::Processot,
94
+ # RelatonItu::Processor, RelatonGb::Processor,
95
+ # RelatonOgc::Processor, RelatonCalconnect::Processor]
96
+ def get_proc(docid)
97
+ return unless docid && docid[:type]
98
+
99
+ Relaton::Db::Registry.instance.by_type(docid[:type])
100
+ end
101
+ end
102
+ end
103
+ end
@@ -69,7 +69,7 @@ module Relaton
69
69
  pubid_class&.parse(ref)
70
70
  rescue ArgumentError, ::Pubid::Errors::Error
71
71
  # relaton-bib carries the log facade; core specs load without it.
72
- require "relaton/bib"
72
+ require_relative "../bib"
73
73
  Relaton::Bib::Util.info "does not parse as this flavor's pubid; " \
74
74
  "passing the reference to the flavor as " \
75
75
  "written", "relaton-db", key: ref
data/lib/relaton/core.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "relaton/logger"
1
+ require_relative "logger"
2
2
 
3
3
  module Relaton
4
4
  # Registered here as well as in the root entry: flavor files and their
@@ -13,7 +13,7 @@ module Relaton
13
13
  relaton/oasis relaton/doi relaton/jis relaton/xsf
14
14
  relaton/ccsds relaton/etsi relaton/isbn relaton/plateau
15
15
  relaton/oiml relaton/jcgm relaton/easc relaton/gost relaton/adobe
16
- relaton/iala relaton/evs
16
+ relaton/iala relaton/evs relaton/sae
17
17
  ].freeze
18
18
 
19
19
  include Singleton
data/lib/relaton/db.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "relaton/bib"
1
+ require_relative "bib"
2
2
  require "yaml"
3
3
  require "net/http"
4
4
  require "moxml"
@@ -38,7 +38,7 @@ Key classes in `lib/relaton/doi/`:
38
38
  - **RSpec** with `expect` syntax only (monkey patching disabled)
39
39
  - **VCR** cassettes in `spec/vcr_cassettes/` record Crossref HTTP responses and are never auto-rerecorded (see root `CLAUDE.md`). Because Crossref rate-limits, **re-record this suite alone** — under parallel `rake spec` it answers 429 and the empty body gets recorded as if it were data.
40
40
  - **XML fixtures** in `spec/fixtures/` — expected output XML files. The `read_fixture` helper auto-substitutes today's date into `<fetched>` tags.
41
- - **equivalent-xml** gem for XML comparison in integration tests
41
+ - **canon** gem for XML comparison in integration tests
42
42
  - Integration tests in `spec/relaton/doi_spec.rb` cover 40+ document types via VCR cassettes
43
43
  - Unit tests in `spec/relaton/doi/parser_spec.rb` test Parser methods directly with hash inputs
44
44
 
@@ -731,7 +731,8 @@ module Relaton
731
731
  #
732
732
  def parse_relation # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
733
733
  rels = included_in_relation
734
- @src["relation"].each_with_object(rels) do |(k, v), a|
734
+ # Crossref leaves the key out of some records (SAE standards).
735
+ (@src["relation"] || {}).each_with_object(rels) do |(k, v), a|
735
736
  type, desc = relation_type k
736
737
  Array(v).each do |r|
737
738
  rel_item = Crossref.get_by_id r["id"]
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Doi
data/lib/relaton/doi.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "relaton/bipm"
4
- require "relaton/ietf"
5
- require "relaton/ieee"
6
- require "relaton/nist"
3
+ require_relative "bipm"
4
+ require_relative "ietf"
5
+ require_relative "ieee"
6
+ require_relative "nist"
7
7
  require_relative "version"
8
8
  require_relative "doi/util"
9
9
  require_relative "doi/parser"
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Easc
data/lib/relaton/easc.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "relaton/bib"
4
- require "relaton/index"
5
- require "relaton/version"
3
+ require_relative "bib"
4
+ require_relative "index"
5
+ require_relative "version"
6
6
  require "pubid"
7
7
 
8
8
  # Relaton::Easc is the EASC (Евразийский экономический совет /
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "English"
4
4
  require "mechanize"
5
- require "relaton/core"
5
+ require_relative "../core"
6
6
  require_relative "../ecma"
7
7
  require_relative "parser_common"
8
8
  require_relative "page_fetcher"
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Ecma
data/lib/relaton/ecma.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  # (The IANA/IHO/IALA/OGC form; spec/relaton/lazy_loading_spec.rb guards that
4
4
  # this file is not itself loaded when a Db is built.)
5
5
  require "pubid"
6
- require "relaton/index"
7
- require "relaton/bib"
6
+ require_relative "index"
7
+ require_relative "bib"
8
8
  require_relative "version"
9
9
  require_relative "ecma/util"
10
10
  require_relative "ecma/item_data"
@@ -0,0 +1,29 @@
1
+ module Relaton
2
+ module ElementFinder
3
+ attr_reader :document
4
+
5
+ def find_text(xpath, element = nil)
6
+ find(xpath, element)&.text
7
+ end
8
+
9
+ def find_html(xpath, element = nil)
10
+ find(xpath, element)&.inner_html
11
+ end
12
+
13
+ def find(xpath, element = nil)
14
+ (element || document).at(apply_namespace(xpath))
15
+ end
16
+
17
+ def find_xpath(xpath, element = nil)
18
+ element&.xpath(apply_namespace(xpath))
19
+ end
20
+
21
+ def apply_namespace(xpath)
22
+ xpath
23
+ .gsub(%r{/([a-zA-Z])}, "/xmlns:\\1")
24
+ .gsub(%r{::([a-zA-Z])}, "::xmlns:\\1")
25
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
26
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
27
+ end
28
+ end
29
+ end
@@ -1,8 +1,8 @@
1
1
  require "yeptris"
2
2
  require "date"
3
3
  require "mechanize"
4
- require "relaton/core"
5
- require "relaton/index"
4
+ require_relative "../core"
5
+ require_relative "../index"
6
6
  require_relative "../etsi"
7
7
  require_relative "data_parser"
8
8
 
@@ -1,4 +1,4 @@
1
- require "relaton/bib"
1
+ require_relative "../bib"
2
2
  require_relative "item_data"
3
3
  require_relative "ext"
4
4
  require_relative "status"
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Etsi
@@ -54,7 +54,7 @@ module Relaton
54
54
  # @return [String]
55
55
  def grammar_hash
56
56
  require "digest/md5" # not loaded by etsi.rb; needed on the cold path
57
- require "relaton/version"
57
+ require_relative "../version"
58
58
  Digest::MD5.hexdigest Relaton::VERSION
59
59
  end
60
60
 
data/lib/relaton/etsi.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "net/http"
4
4
  require "mechanize"
5
5
  require "pubid"
6
- require "relaton/index"
6
+ require_relative "index"
7
7
  require_relative "version"
8
8
  # require_relative "relaton_etsi/pubid"
9
9
  require_relative "etsi/bibitem"
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Evs
data/lib/relaton/evs.rb CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  require "digest/md5"
4
4
  require "mechanize"
5
- require "relaton/core"
5
+ require_relative "core"
6
6
  require "isoics"
7
7
  require "pubid"
8
- require "relaton/bib"
8
+ require_relative "bib"
9
9
  require_relative "version"
10
10
  require_relative "evs/util"
11
11
  require_relative "evs/model/item"
@@ -44,4 +44,4 @@ GB parses identifiers with `Pubid::Gb::Identifier`. It publishes no index, so it
44
44
 
45
45
  ## Testing
46
46
 
47
- RSpec with WebMock + VCR (cassettes in `spec/vcr_cassettes/`). Network is blocked via WebMock. SimpleCov and equivalent-xml are loaded via `spec/support/`. No index fixture — GB is scraped, not indexed; `spec/fixtures/` holds XML/YAML round-trip data.
47
+ RSpec with WebMock + VCR (cassettes in `spec/vcr_cassettes/`). Network is blocked via WebMock. SimpleCov and canon are loaded via `spec/support/`. No index fixture — GB is scraped, not indexed; `spec/fixtures/` holds XML/YAML round-trip data.
@@ -31,7 +31,7 @@ module Relaton
31
31
  TScraper.scrape_page ref
32
32
  else
33
33
  # Scrape sector standard.
34
- require "relaton/gb/sec_scraper"
34
+ require_relative "sec_scraper"
35
35
  SecScraper.scrape_page ref
36
36
  end
37
37
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "relaton/core/processor"
3
+ require_relative "../core/processor"
4
4
 
5
5
  module Relaton
6
6
  module Gb
data/lib/relaton/gb.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "digest/md5"
2
2
  require "mechanize"
3
- require "relaton/core"
4
- require "relaton/iso"
3
+ require_relative "core"
4
+ require_relative "iso"
5
5
  require "cnccs"
6
6
  require_relative "version"
7
7
  require_relative "gb/util"
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Gost
data/lib/relaton/gost.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "relaton/bib"
4
- require "relaton/index"
3
+ require_relative "bib"
4
+ require_relative "index"
5
5
  require "pubid"
6
- require "relaton/version"
6
+ require_relative "version"
7
7
 
8
8
  # Relaton::Gost is the GOST (Russian federal standards — Гостстандарт)
9
9
  # flavor of the unified relaton gem. Adds typed Ext fields (urn,
@@ -1,4 +1,4 @@
1
- require "relaton/core/processor"
1
+ require_relative "../core/processor"
2
2
 
3
3
  module Relaton
4
4
  module Iala