relaton 3.0.7 → 3.0.8

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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/bin/relaton +20 -0
  3. data/lib/relaton/bib/model/docidentifier.rb +17 -2
  4. data/lib/relaton/bibcollection.rb +146 -0
  5. data/lib/relaton/bibdata.rb +92 -0
  6. data/lib/relaton/bipm/data_outcomes_parser.rb +6 -1
  7. data/lib/relaton/cli/base_convertor.rb +134 -0
  8. data/lib/relaton/cli/command.rb +390 -0
  9. data/lib/relaton/cli/data_fetcher.rb +20 -0
  10. data/lib/relaton/cli/frontend/dist/404.html +18 -0
  11. data/lib/relaton/cli/frontend/dist/app.iife.js +1 -0
  12. data/lib/relaton/cli/frontend/dist/style.css +3 -0
  13. data/lib/relaton/cli/frontend/index.html +14 -0
  14. data/lib/relaton/cli/frontend/package-lock.json +2945 -0
  15. data/lib/relaton/cli/frontend/package.json +29 -0
  16. data/lib/relaton/cli/frontend/public/404.html +18 -0
  17. data/lib/relaton/cli/frontend/src/App.test.ts +501 -0
  18. data/lib/relaton/cli/frontend/src/App.vue +506 -0
  19. data/lib/relaton/cli/frontend/src/app.ts +90 -0
  20. data/lib/relaton/cli/frontend/src/components/DocumentDetail.test.ts +142 -0
  21. data/lib/relaton/cli/frontend/src/components/DocumentDetail.vue +228 -0
  22. data/lib/relaton/cli/frontend/src/components/DocumentRow.vue +88 -0
  23. data/lib/relaton/cli/frontend/src/components/Icon.test.ts +44 -0
  24. data/lib/relaton/cli/frontend/src/components/Icon.vue +55 -0
  25. data/lib/relaton/cli/frontend/src/components/Pagination.vue +26 -0
  26. data/lib/relaton/cli/frontend/src/dev/main.ts +100 -0
  27. data/lib/relaton/cli/frontend/src/dev/sample-data.json +71 -0
  28. data/lib/relaton/cli/frontend/src/lib/filter.test.ts +88 -0
  29. data/lib/relaton/cli/frontend/src/lib/filter.ts +95 -0
  30. data/lib/relaton/cli/frontend/src/lib/hydrate.test.ts +102 -0
  31. data/lib/relaton/cli/frontend/src/lib/hydrate.ts +55 -0
  32. data/lib/relaton/cli/frontend/src/lib/shards.test.ts +319 -0
  33. data/lib/relaton/cli/frontend/src/lib/shards.ts +183 -0
  34. data/lib/relaton/cli/frontend/src/lib/types.ts +148 -0
  35. data/lib/relaton/cli/frontend/src/lib/url.test.ts +151 -0
  36. data/lib/relaton/cli/frontend/src/lib/url.ts +111 -0
  37. data/lib/relaton/cli/frontend/src/shims-vue.d.ts +5 -0
  38. data/lib/relaton/cli/frontend/src/styles/index.css +27 -0
  39. data/lib/relaton/cli/frontend/src/test/fetch.ts +58 -0
  40. data/lib/relaton/cli/frontend/tsconfig.json +20 -0
  41. data/lib/relaton/cli/frontend/vite.config.ts +42 -0
  42. data/lib/relaton/cli/frontend/vitest.config.ts +11 -0
  43. data/lib/relaton/cli/frontend_assets.rb +58 -0
  44. data/lib/relaton/cli/full_text_search.rb +98 -0
  45. data/lib/relaton/cli/i18n.yaml +1 -0
  46. data/lib/relaton/cli/index_item_normalizer.rb +380 -0
  47. data/lib/relaton/cli/index_site_generator.rb +1015 -0
  48. data/lib/relaton/cli/relaton_file.rb +290 -0
  49. data/lib/relaton/cli/subcommand_collection.rb +263 -0
  50. data/lib/relaton/cli/subcommand_db.rb +81 -0
  51. data/lib/relaton/cli/templates/_document.liquid +111 -0
  52. data/lib/relaton/cli/templates/_index.liquid +61 -0
  53. data/lib/relaton/cli/templates/index/page.liquid +20 -0
  54. data/lib/relaton/cli/templates/index-style.css +1017 -0
  55. data/lib/relaton/cli/util.rb +8 -0
  56. data/lib/relaton/cli/version.rb +11 -0
  57. data/lib/relaton/cli/xml_convertor.rb +47 -0
  58. data/lib/relaton/cli/xml_to_html_renderer.rb +117 -0
  59. data/lib/relaton/cli/yaml_convertor.rb +102 -0
  60. data/lib/relaton/cli.rb +113 -0
  61. data/lib/relaton/doi/CLAUDE.md +1 -1
  62. data/lib/relaton/element_finder.rb +29 -0
  63. data/lib/relaton/gb/CLAUDE.md +1 -1
  64. data/lib/relaton/ietf/CLAUDE.md +1 -1
  65. data/lib/relaton/iho/CLAUDE.md +3 -3
  66. data/lib/relaton/iho/bibliography.rb +41 -27
  67. data/lib/relaton/iho/processor.rb +3 -2
  68. data/lib/relaton/nist/CLAUDE.md +11 -1
  69. data/lib/relaton/nist/README.adoc +7 -1
  70. data/lib/relaton/nist/hit_collection.rb +25 -1
  71. data/lib/relaton/nist/mods_parser.rb +32 -8
  72. data/lib/relaton/nist/pubs_export.rb +69 -11
  73. data/lib/relaton/ogc/CLAUDE.md +1 -1
  74. data/lib/relaton/omg/CLAUDE.md +1 -1
  75. data/lib/relaton/plateau/CLAUDE.md +1 -1
  76. data/lib/relaton/render/general.rb +319 -0
  77. data/lib/relaton/render/iso690/csl_import.rb +129 -0
  78. data/lib/relaton/render/iso690/element.rb +153 -0
  79. data/lib/relaton/render/iso690/elements/access.rb +44 -0
  80. data/lib/relaton/render/iso690/elements/authorizer.rb +45 -0
  81. data/lib/relaton/render/iso690/elements/citeid.rb +39 -0
  82. data/lib/relaton/render/iso690/elements/component_part.rb +97 -0
  83. data/lib/relaton/render/iso690/elements/creator.rb +267 -0
  84. data/lib/relaton/render/iso690/elements/edition.rb +97 -0
  85. data/lib/relaton/render/iso690/elements/extent.rb +71 -0
  86. data/lib/relaton/render/iso690/elements/identifier.rb +46 -0
  87. data/lib/relaton/render/iso690/elements/location.rb +73 -0
  88. data/lib/relaton/render/iso690/elements/medium.rb +32 -0
  89. data/lib/relaton/render/iso690/elements/numeration.rb +26 -0
  90. data/lib/relaton/render/iso690/elements/production.rb +111 -0
  91. data/lib/relaton/render/iso690/elements/pub_date.rb +63 -0
  92. data/lib/relaton/render/iso690/elements/series.rb +66 -0
  93. data/lib/relaton/render/iso690/elements/size.rb +45 -0
  94. data/lib/relaton/render/iso690/elements/status.rb +30 -0
  95. data/lib/relaton/render/iso690/elements/stddoc.rb +40 -0
  96. data/lib/relaton/render/iso690/elements/title.rb +56 -0
  97. data/lib/relaton/render/iso690/elements/updated.rb +38 -0
  98. data/lib/relaton/render/iso690/elements.rb +67 -0
  99. data/lib/relaton/render/iso690/fields.rb +142 -0
  100. data/lib/relaton/render/iso690/i18n/en.yml +48 -0
  101. data/lib/relaton/render/iso690/i18n/fr.yml +14 -0
  102. data/lib/relaton/render/iso690/i18n/ja.yml +38 -0
  103. data/lib/relaton/render/iso690/i18n.rb +83 -0
  104. data/lib/relaton/render/iso690/identifier_kinds.rb +29 -0
  105. data/lib/relaton/render/iso690/index_renderer.rb +57 -0
  106. data/lib/relaton/render/iso690/kinds.rb +53 -0
  107. data/lib/relaton/render/iso690/renderer.rb +150 -0
  108. data/lib/relaton/render/iso690/rules/bipm.rb +186 -0
  109. data/lib/relaton/render/iso690/rules/jis.rb +103 -0
  110. data/lib/relaton/render/iso690/rules/nist.rb +384 -0
  111. data/lib/relaton/render/iso690/rules.rb +227 -0
  112. data/lib/relaton/render/iso690/style/locale.rb +59 -0
  113. data/lib/relaton/render/iso690/style/name_form.rb +87 -0
  114. data/lib/relaton/render/iso690/style/scheme.rb +33 -0
  115. data/lib/relaton/render/iso690/style/sort_rule.rb +25 -0
  116. data/lib/relaton/render/iso690/style/template_map.rb +40 -0
  117. data/lib/relaton/render/iso690/style/type_template.rb +45 -0
  118. data/lib/relaton/render/iso690/style.rb +227 -0
  119. data/lib/relaton/render/iso690/styles/apa.yml +45 -0
  120. data/lib/relaton/render/iso690/styles/author-date.yml +31 -0
  121. data/lib/relaton/render/iso690/styles/chicago.yml +49 -0
  122. data/lib/relaton/render/iso690/styles/ieee-sa.yml +45 -0
  123. data/lib/relaton/render/iso690/styles/jis-en.yml +68 -0
  124. data/lib/relaton/render/iso690/styles/jis-ja.yml +67 -0
  125. data/lib/relaton/render/iso690/styles/lncs.yml +54 -0
  126. data/lib/relaton/render/iso690/styles/mla.yml +56 -0
  127. data/lib/relaton/render/iso690/template.rb +248 -0
  128. data/lib/relaton/render/iso690.rb +28 -0
  129. data/lib/relaton/render/version.rb +5 -0
  130. data/lib/relaton/un/CLAUDE.md +1 -1
  131. data/lib/relaton/version.rb +1 -1
  132. data/lib/relaton-cli.rb +17 -0
  133. data/lib/relaton-render.rb +13 -0
  134. metadata +192 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5d527c7af0e73aafd66151377b063b5dee1aabc862847f463a3e2e6064851fa
4
- data.tar.gz: c07269ae1bf1b52ec8d5c6cf9e1ab3e697328327df7b4b125e0b2db70241d5ef
3
+ metadata.gz: c2d44cf8ad434afddc1e4b0b2b4ce979970271e7ce871c48a2bb436e42eccfee
4
+ data.tar.gz: '07891a8f6deafa0d294519798a4576e7de997d0faead9d02077d9ab840c5d2ab'
5
5
  SHA512:
6
- metadata.gz: 6a602b0c6e67dfdb52ba5778ca98fd5370c9f54d9f53f649d235a16a19e40130c093bf1104d11c7bf0b9ca10b0872c3a7eee14e1706058da4ddc9e24ed9ac36f
7
- data.tar.gz: 2ed59dd8053ee02f22f5fc4adcba23dcc472779d78535bb41ce7fa79b591c8a792ffd9e5033b4779a8e71dbeae3a0ba450c5196fd2738f5fca2d7bba7e7bac48
6
+ metadata.gz: 5ca0eb885107187f7881e2fd42e665cebc70b6e9154f3b52cfeb8597037f5543dd9d921cb698a17e86723c86b592cef6bc19979051cc2bff7b4898c981c45840
7
+ data.tar.gz: ed359c58cb0ef93f972c0a30e8d89aed165841a9b392664241fa15f08d638fbf72a9e50c29994acc4bb5de3a7c0b0394c8bf9d801cf99c217c06b282e75089a3
data/bin/relaton ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # resolve bin path, ignoring symlinks
5
+ require "pathname"
6
+ bin_file = Pathname.new(__FILE__).realpath
7
+
8
+ # add self to libpath
9
+ $:.unshift File.expand_path("../../lib", bin_file)
10
+
11
+ # Fixes https://github.com/rubygems/rubygems/issues/1420
12
+ require "rubygems/specification"
13
+
14
+ class Gem::Specification
15
+ def this; self; end
16
+ end
17
+
18
+ require "relaton-cli"
19
+
20
+ Relaton::Cli.start(ARGV)
@@ -66,7 +66,7 @@ module Relaton
66
66
  "BSI" => :Bsi,
67
67
  }.freeze
68
68
 
69
- FORMS = %i[external internal].freeze
69
+ FORMS = %i[external internal slug].freeze
70
70
 
71
71
  # The parsed identifier. A pubid-backed flavor subclass overrides it.
72
72
  def pubid; end
@@ -94,7 +94,22 @@ module Relaton
94
94
  def form_content(form)
95
95
  flavor = FORM_PUBID[type]
96
96
  id = flavor && (pubid || parse_form_pubid(flavor))
97
- id ? id.to_s(with_publisher: form == :external) : content
97
+ return content unless id
98
+
99
+ return slug_form(id) if form == :slug
100
+
101
+ id.to_s(with_publisher: form == :external)
102
+ end
103
+
104
+ # The pubid-scheme slug (relaton#441): the URN in HTTP-path
105
+ # clothes, bijective with Pubid.from_slug. A flavor whose
106
+ # pubid-scheme schema has not landed yet degrades to the stored
107
+ # content, like a form pubid cannot parse.
108
+ def slug_form(id)
109
+ require "pubid"
110
+ ::Pubid.to_slug(id)
111
+ rescue ::Pubid::Errors::InvalidInputError, NameError
112
+ content
98
113
  end
99
114
 
100
115
  def parse_form_pubid(flavor)
@@ -0,0 +1,146 @@
1
+ require "relaton/element_finder"
2
+
3
+ module Relaton
4
+ class Bibcollection
5
+ extend Relaton::ElementFinder
6
+
7
+ ATTRIBS = %i[title items doctype author].freeze
8
+
9
+ attr_accessor(*ATTRIBS)
10
+
11
+ # @param options [Hash]
12
+ def initialize(options)
13
+ ATTRIBS.each do |k|
14
+ value = options[k] || options[k.to_s]
15
+ send("#{k}=", value)
16
+ end
17
+ reduce_items
18
+ end
19
+
20
+ # arbitrary number, must sort after all bib items
21
+ def doc_number
22
+ 9999999
23
+ end
24
+
25
+ # Add a dcoument to the collection
26
+ # @param item [RelatonBib::BibliographicItem]
27
+ def <<(item)
28
+ items << new_bib_item_class(item)
29
+ end
30
+
31
+ # rubocop:disable Metrics/MethodLength
32
+
33
+ # @param source [Nokogiri::XML::Element]
34
+ def self.from_xml(source)
35
+ title = find_html("./relaton-collection/title", source)
36
+ author = find_html(
37
+ "./relaton-collection/contributor[role/@type='author']/organization/"\
38
+ "name", source
39
+ )
40
+
41
+ items = find_xpath("./relaton-collection/relation", source)&.map do |item|
42
+ bibdata = find("./bibdata|./bibitem", item)
43
+ klass = bibdata ? Bibdata : Bibcollection
44
+ klass.from_xml(bibdata || item)
45
+ end
46
+
47
+ new(title: title, author: author, items: items)
48
+ end
49
+
50
+ # rubocop:disable Metrics/AbcSize
51
+
52
+ # @param opts [Hash]
53
+ # @return [String] XML
54
+ def to_xml(opts = {})
55
+ items.sort_by! &:doc_number
56
+
57
+ collection_type = if doctype
58
+ "type=\"#{doctype}\""
59
+ else
60
+ 'xmlns="https://open.ribose.com/relaton-xml"'
61
+ end
62
+
63
+ ret = "<relaton-collection #{collection_type}>"
64
+ ret += "<title>#{xml_escape(title)}</title>" if title
65
+ if author
66
+ ret += "<contributor><role type='author'/><organization><name>"\
67
+ "#{xml_escape(author)}</name></organization></contributor>"
68
+ end
69
+ unless items.empty?
70
+ items.each do |item|
71
+ ret += "<relation type='partOf'>"
72
+ ret += item.to_xml(opts)
73
+ ret += "</relation>\n"
74
+ end
75
+ end
76
+ ret += "</relaton-collection>\n"
77
+ end
78
+ # rubocop:enable Metrics/AbcSize
79
+
80
+ # @param item [Hash, RelatonBib::BibliographicItem, Relatin::Bibdata,
81
+ # Relaton::Bibcollection]
82
+ # @return [Relaton::Bibdata, Relaton::Bibcollection]
83
+ def new_bib_item_class(item)
84
+ if item.is_a?(Hash)
85
+ if item["items"]
86
+ ::Relaton::Bibcollection.new(item)
87
+ else
88
+ bibitem = ::Relaton::Cli::YAMLConvertor.convert_single_file item
89
+ ::Relaton::Bibdata.new bibitem
90
+ end
91
+ elsif item.is_a?(Relaton::Bibdata) || item.is_a?(Relaton::Bibcollection)
92
+ item
93
+ else ::Relaton::Bibdata.new(item)
94
+ end
95
+ end
96
+ # rubocop:enable Metrics/MethodLength
97
+
98
+ def items_flattened
99
+ items.sort_by! &:doc_number
100
+
101
+ items.reduce([]) do |acc, item|
102
+ acc << if item.is_a? ::Relaton::Bibcollection
103
+ item.items_flattened
104
+ else
105
+ item
106
+ end
107
+ end
108
+ end
109
+
110
+ def to_yaml
111
+ to_h.to_yaml
112
+ end
113
+
114
+ def to_h
115
+ items.sort_by! &:doc_number
116
+
117
+ a = ATTRIBS.reduce({}) do |acc, k|
118
+ acc[k.to_s] = send(k)
119
+ acc
120
+ end
121
+
122
+ a["items"] = a["items"].map(&:to_h)
123
+
124
+ { "root" => a }
125
+ end
126
+
127
+ private
128
+
129
+ def reduce_items
130
+ self.items = (items || []).reduce([]) do |acc, item|
131
+ acc << if item.is_a?(Bibcollection) || item.is_a?(Bibdata)
132
+ item
133
+ else new_bib_item_class(item)
134
+ end
135
+ end
136
+ end
137
+
138
+ # Escape bare & in content for XML serialization, leaving already-encoded
139
+ # entity references (&amp;, &#123;, &#x1f;) and inline markup (<em> etc.)
140
+ # untouched. This prevents invalid XML when plain-text values (e.g. from
141
+ # YAML) contain literal ampersands.
142
+ def xml_escape(str)
143
+ str.gsub(/&(?![a-zA-Z][a-zA-Z0-9]*;|#[0-9]+;|#x[0-9a-fA-F]+;)/, "&amp;")
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,92 @@
1
+ require "date"
2
+
3
+ module Relaton
4
+ class Bibdata
5
+ URL_TYPES = %i[uri xml pdf doc html rxl txt].freeze
6
+
7
+ # @return [RelatonBib::BibliographicItem]
8
+ attr_reader :bibitem
9
+
10
+ # @param bibitem [RelatonBib::BibliographicItem]
11
+ def initialize(bibitem)
12
+ @bibitem = bibitem
13
+ end
14
+
15
+ def docidentifier
16
+ @bibitem.docidentifier.first&.content&.to_s
17
+ end
18
+
19
+ # def doctype
20
+ # @bibitem.type
21
+ # end
22
+
23
+ # From http://gavinmiller.io/2016/creating-a-secure-sanitization-function/
24
+ FILENAME_BAD_CHARS = ["/", '\\', "?", "%", "*", ":", "|", '"', "<", ">",
25
+ ".", " "].freeze
26
+
27
+ def docidentifier_code
28
+ return "" if docidentifier.nil?
29
+
30
+ FILENAME_BAD_CHARS.reduce(docidentifier.downcase) do |result, bad_char|
31
+ result.gsub(bad_char, "-")
32
+ end
33
+ end
34
+
35
+ DOC_NUMBER_REGEX = /([\w\/]+)\s+(\d+):?(\d*)/.freeze
36
+ def doc_number
37
+ docidentifier&.match(DOC_NUMBER_REGEX) ? $2.to_i : 999999
38
+ end
39
+
40
+ def self.from_xml(source)
41
+ bi = Relaton::Cli.parse_xml(source)
42
+ new(bi) if bi
43
+ end
44
+
45
+ def to_xml(opts = {})
46
+ options = { bibdata: true, date_format: :full }.merge(
47
+ opts.select { |k, _v| k.is_a? Symbol },
48
+ )
49
+ @bibitem.to_xml(**options)
50
+ end
51
+
52
+ def to_h
53
+ URL_TYPES.each_with_object(YAML.safe_load(@bibitem.to_yaml)) do |t, h|
54
+ value = send t
55
+ h[t.to_s] = value if value
56
+ end
57
+ end
58
+
59
+ def to_yaml
60
+ to_h.to_yaml
61
+ end
62
+
63
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
64
+ # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Style/MissingRespondToMissing
65
+
66
+ def method_missing(meth, *args)
67
+ if @bibitem.respond_to?(meth)
68
+ @bibitem.send meth, *args
69
+ elsif URL_TYPES.include? meth
70
+ source = (@bibitem.source || []).detect do |l|
71
+ l.type == meth.to_s || (meth == :uri && l.type.nil?)
72
+ end
73
+ source&.content&.to_s
74
+ elsif URL_TYPES.include? meth.match(/^\w+(?==)/).to_s.to_sym
75
+ /^(?<type>\w+)/ =~ meth
76
+ @bibitem.source ||= []
77
+ source = @bibitem.source.detect do |l|
78
+ l.type == type || (type == "uri" && l.type.nil?)
79
+ end
80
+ if source
81
+ source.content = args[0]
82
+ else
83
+ @bibitem.source << Relaton::Bib::Uri.new(type: type, content: args[0])
84
+ end
85
+ else
86
+ super
87
+ end
88
+ end
89
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
90
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity, Style/MissingRespondToMissing
91
+ end
92
+ end
@@ -94,9 +94,14 @@ module Relaton::Bipm
94
94
  @data_fetcher.write_file path, has_part_item, warn_duplicate: false
95
95
  path = File.join dir, "#{num}-#{part}.#{@data_fetcher.ext}"
96
96
  elsif part
97
- hash[:title].each { |t| t.content.sub!(/\s\(.+\)$/, "") }
97
+ # The part item keeps the full titles ("… (Session I)"); the base
98
+ # item's titles drop the parenthetical. Assign the stripped form -
99
+ # `Title#content` exposes the source metadata string, and a
100
+ # mutating `sub!` would strip the part item's title too (the two
101
+ # share the string object).
98
102
  h = meeting_bibitem body: body, type: type, en: en_md, fr: fr_md, num: num, src: src, pdf: en["pdf"]
99
103
  add_part h, body, type, num, part
104
+ hash[:title].each { |t| t.content = t.content.sub(/\s\(.+\)$/, "") }
100
105
  part_item = ItemData.new(**h)
101
106
  part_item_path = File.join dir, "#{num}-#{part}.#{@data_fetcher.ext}"
102
107
  @data_fetcher.write_file part_item_path, part_item
@@ -0,0 +1,134 @@
1
+ require "fileutils"
2
+ require "relaton/bibdata"
3
+ require "relaton/bibcollection"
4
+ require "relaton/cli/xml_to_html_renderer"
5
+
6
+ module Relaton
7
+ module Cli
8
+ class BaseConvertor
9
+ def initialize(file, options = {})
10
+ @file = file
11
+ @options = options
12
+ @outdir = options.fetch(:outdir, nil)
13
+ @writable = options.fetch(:write, true)
14
+ @overwrite = options.fetch(:overwrite, true)
15
+ @default_filelabel = 0
16
+
17
+ install_dependencies(options[:require] || [])
18
+ end
19
+
20
+ # @return [String] HTML
21
+ def to_html
22
+ content = convert_to_html
23
+ write_to_a_file(content)
24
+ end
25
+
26
+ # Convert to HTML
27
+ #
28
+ # This interface expect us to provide Relaton collection XML
29
+ # as XML/RXL, and necessary styels / templates then it will be
30
+ # used convert that collection to HTML.
31
+ #
32
+ # @param file [String] Relaton collection file path
33
+ # @param style [String] Stylesheet file path for styles
34
+ # @param template [String] The liquid tempalte directory
35
+ #
36
+ # @return [String] HTML
37
+ def self.to_html(file, style = nil, template = nil)
38
+ new(
39
+ file,
40
+ style: style || File.join(File.dirname(__FILE__), "templates/index-style.css"),
41
+ template: template || File.join(File.dirname(__FILE__), "templates/"),
42
+ extension: "html"
43
+ ).to_html
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :file, :outdir, :options, :writable, :overwrite
49
+
50
+ # @return [String] HTML
51
+ def convert_to_html
52
+ Relaton::Cli::XmlToHtmlRenderer.render(
53
+ xml_content(file),
54
+ stylesheet: options[:style],
55
+ liquid_dir: options[:template]
56
+ )
57
+ end
58
+
59
+ # @param file [String] path to a file
60
+ # @return [String] the file's content
61
+ # @return [String] HTML
62
+ def xml_content(file)
63
+ File.read(file, encoding: "utf-8")
64
+ end
65
+
66
+ def install_dependencies(dependencies)
67
+ dependencies.each { |dependency| require(dependency) }
68
+ end
69
+
70
+ def item_output(content, format)
71
+ case format.to_sym
72
+ when :to_yaml then content.to_yaml
73
+ when :to_xml then content.to_xml(date_format: :full, bibdata: true)
74
+ end
75
+ end
76
+
77
+ def convert_and_write(content, format)
78
+ content = convert_content(content)
79
+ write_to_a_file(item_output(content, format))
80
+ write_to_file_collection(content, format.to_sym)
81
+ end
82
+
83
+ def write_to_a_file(content, outfile = nil)
84
+ outfile ||= Pathname.new(file).sub_ext(extension).to_s
85
+
86
+ if !File.exist?(outfile) || overwrite
87
+ File.open(outfile, "w:utf-8") do |file|
88
+ file.write(content)
89
+ end
90
+ end
91
+ end
92
+
93
+ def write_to_file_collection(content, format)
94
+ if outdir && content.is_a?(Relaton::Bibcollection)
95
+ FileUtils.mkdir_p(outdir)
96
+ content.items_flattened.each do |item|
97
+ collection = collection_filename(extract_docid(item))
98
+ write_to_a_file(item_output(item, format), collection)
99
+ end
100
+ end
101
+ end
102
+
103
+ def extract_docid(item)
104
+ @default_filelabel += 1
105
+ item.docidentifier.nil? && (return @default_filelabel.to_s)
106
+ # item.docidentifier.is_a?(Array) or return @default_filelabel.to_s
107
+ item.docidentifier.empty? && (return @default_filelabel.to_s)
108
+ docidentifier_code(item.docidentifier)
109
+ end
110
+
111
+ # From http://gavinmiller.io/2016/creating-a-secure-sanitization-function/
112
+ FILENAME_BAD_CHARS = ["/", '\\', "?", '%", "*", ":', "|", '"', "<", ">",
113
+ ".", " "].freeze
114
+
115
+ def docidentifier_code(docidentifier)
116
+ return "" if docidentifier.nil?
117
+
118
+ FILENAME_BAD_CHARS.reduce(docidentifier.downcase) do |result, bad_char|
119
+ result.gsub(bad_char, "-")
120
+ end
121
+ end
122
+
123
+ def extension
124
+ @extension ||= [".", options.fetch(:extension, default_ext)].join
125
+ end
126
+
127
+ def collection_filename(identifier)
128
+ File.join(
129
+ outdir, [@options[:prefix], identifier, extension].compact.join("")
130
+ )
131
+ end
132
+ end
133
+ end
134
+ end