relaton-cli 1.4.0 → 1.7.pre3

Sign up to get free protection for your applications and to get access to all the features.
@@ -150,7 +150,7 @@ module Relaton
150
150
  mem << bibdata_instance(doc, xml[:file])
151
151
  else mem
152
152
  end
153
- end.uniq &:id
153
+ end
154
154
  end
155
155
 
156
156
  def concatenate_and_write_to_files
@@ -0,0 +1,221 @@
1
+ require "relaton/cli/full_text_search"
2
+
3
+ module Relaton
4
+ module Cli
5
+ class SubcommandCollection < Thor
6
+ desc "create COLLECTION", "Create collection"
7
+ option :dir, aliases: :d, desc: "Directory to store collection. Default "\
8
+ "is $HOME/.relaton/collections."
9
+ option :author, desc: "Author"
10
+ option :title, desc: "Title"
11
+ option :doctype, desc: "Documents type"
12
+
13
+ def create(file)
14
+ dir = directory
15
+ file_path = File.join dir, file
16
+ col = Relaton::Bibcollection.new options
17
+ if File.exist? file_path
18
+ warn "Collection #{file} aready exist"
19
+ else
20
+ Dir.mkdir dir unless Dir.exist? dir
21
+ File.write file_path, col.to_yaml, encoding: "UTF-8"
22
+ end
23
+ end
24
+
25
+ desc "info COLLECTION", "View collection information"
26
+ option :dir, aliases: :d, desc: "Directory to store collection. Default "\
27
+ "is $HOME/.relaton/collections."
28
+
29
+ def info(file) # rubocop:disable Metrics/AbcSize
30
+ path = File.join directory, file
31
+ puts "Collection: #{File.basename path}"
32
+ puts "Last updated: #{File.mtime path}"
33
+ puts "File size: #{File.size path}"
34
+ col = Relaton::Bibcollection.new YAML.load_file(path)["root"]
35
+ puts "Number of items: #{col.items.size}"
36
+ puts "Author: #{col.author}"
37
+ puts "Title: #{col.title}"
38
+ end
39
+
40
+ desc "list", "List collections"
41
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
42
+ "$HOME/.relaton/collections."
43
+ option :entries, aliases: :e, type: :boolean, desc: "Show entries"
44
+
45
+ def list
46
+ Dir[File.join(directory, "*")].each do |f|
47
+ yml = read_yaml f
48
+ if yml && yml["root"]
49
+ puts File.basename f
50
+ puts_entries yml
51
+ end
52
+ end
53
+ end
54
+
55
+ map ls: :list
56
+
57
+ desc "get CODE", "Fetch document from collection by ID"
58
+ option :collection, aliases: :c, desc: "Collection to fetch document. "\
59
+ "By default fetch the first match across all collections."
60
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
61
+ "$HOME/.relaton/collections."
62
+ option :format, aliases: :f, desc: "Output format (xml, abb). "\
63
+ "If not defined the output in a human-readable form."
64
+ option :output, aliases: :o, desc: "Output to the specified file. The "\
65
+ " file's extension (abb, xml) defines output format."
66
+
67
+ def get(docid)
68
+ collections.each do |col|
69
+ col[:collection].items.each do |item|
70
+ if item.docidentifier == docid
71
+ output_item(item)
72
+ return
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ desc "find TEXT", "Full-text search"
79
+ option :collection, aliases: :c, desc: "Collection to search text. "\
80
+ "By default search across all collections."
81
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
82
+ "$HOME/.relaton/collections."
83
+
84
+ def find(text)
85
+ collections.each do |col|
86
+ searcher = Relaton::FullTextSeatch.new(col[:collection])
87
+ searcher.search text
88
+ if searcher.any?
89
+ puts "Collection: #{File.basename(col[:file])}"
90
+ searcher.print_results
91
+ end
92
+ end
93
+ end
94
+
95
+ map search: :find
96
+
97
+ desc "fetch CODE", "Fetch a document and store it into a collection"
98
+ option :type, aliases: :t, required: true, desc: "Type of standard to "\
99
+ "get bibliographic entry for"
100
+ option :year, aliases: :y, type: :numeric, desc: "Year the standard was "\
101
+ "published"
102
+ option :collection, aliases: :c, required: true, desc: "Collection "\
103
+ "to store a document"
104
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
105
+ "$HOME/.relaton/collections."
106
+
107
+ def fetch(code)
108
+ doc = Relaton.db.fetch(code, options[:year]&.to_s)
109
+ if doc
110
+ colfile = File.join directory, options[:collection]
111
+ coll = read_collection colfile
112
+ coll << doc
113
+ File.write colfile, coll.to_yaml, encoding: "UTF-8"
114
+ else warn "No matching bibliographic entry found"
115
+ end
116
+ end
117
+
118
+ desc "import FILE", "Import document or collection from an XML file "\
119
+ "into another collection"
120
+ option :collection, aliases: :c, required: true, desc: "Collection "\
121
+ "to store a document. If collection doesn't exist then it'll be created."
122
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
123
+ "$HOME/.relaton/collections."
124
+
125
+ def import(file) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
126
+ collfile = File.join directory, options[:collection]
127
+ coll = read_collection collfile
128
+ xml = Nokogiri::XML File.read(file, encoding: "UTF-8")
129
+ if xml.at "relaton-collection"
130
+ if coll
131
+ coll << Relaton::Bibcollection.from_xml(xml)
132
+ else
133
+ coll = Relaton::Bibcollection.from_xml(xml)
134
+ end
135
+ else
136
+ coll ||= Relaton::Bibcollection.new({})
137
+ coll << Relaton::Bibdata.from_xml(xml)
138
+ end
139
+ File.write collfile, coll.to_yaml, encoding: "UTF-8"
140
+ end
141
+
142
+ desc "export COLLECTION", "Export collection into XML file"
143
+ option :dir, aliases: :d, desc: "Directory with collections. Default is "\
144
+ "$HOME/.relaton/collections."
145
+
146
+ def export(file)
147
+ coll = read_collection File.join(directory, file)
148
+ outfile = file.sub(/\.\w+$/, "") + ".xml"
149
+ File.write outfile, coll.to_xml(bibdata: true), encoding: "UTF-8"
150
+ end
151
+
152
+ private
153
+
154
+ # @return [String]
155
+ def directory
156
+ options.fetch :dir, File.join(Dir.home, ".relaton/collections")
157
+ end
158
+
159
+ # @param file [String]
160
+ # @return [Hash]
161
+ def read_yaml(file)
162
+ YAML.load_file file if File.file? file
163
+ rescue Psych::SyntaxError
164
+ warn "[relaton-cli] WARNING: the file #{file} isn't a collection."
165
+ end
166
+
167
+ # @param file [String]
168
+ # @return [Relaton::Bibcollection, nil]
169
+ def read_collection(file)
170
+ return unless File.file?(file)
171
+
172
+ Relaton::Bibcollection.new YAML.load_file(file)["root"]
173
+ end
174
+
175
+ # @return [Array<Hash>]
176
+ def collections
177
+ file = options.fetch :collection, "*"
178
+ Dir[File.join directory, file].reduce([]) do |m, f|
179
+ yml = read_yaml f
180
+ if yml && yml["root"]
181
+ m << { collection: Relaton::Bibcollection.new(yml["root"]),
182
+ file: f }
183
+ end
184
+ m
185
+ end
186
+ end
187
+
188
+ # Puts document IDs for each item in tthe cokllection
189
+ # @param hash [Hash] Relaton collection
190
+ def puts_entries(hash)
191
+ return unless options[:entries]
192
+
193
+ Relaton::Bibcollection.new(hash["root"]).items.each do |b|
194
+ puts " " + b.docidentifier
195
+ end
196
+ end
197
+
198
+ # @param item [Relaton::Bibdata]
199
+ def output_item(item)
200
+ case options[:format]
201
+ when "xml" then puts item.to_xml bibdata: true
202
+ when "abb" then puts item.to_asciibib
203
+ else puts_human_readable_item item
204
+ end
205
+ out = case options[:output]
206
+ when /\.abb$/ then item.to_asciibib
207
+ when /\.xml$/ then item.to_xml bibitem: true
208
+ end
209
+ File.write options[:output], out, encoding: "UTF-8" if out
210
+ end
211
+
212
+ # @param item [Relaton::Bibdata]
213
+ def puts_human_readable_item(item) # rubocop:disable Metrics/AbcSize
214
+ puts "Document identifier: #{item.docidentifier}"
215
+ puts "Title: #{item.title.first.title.content}"
216
+ puts "Status: #{item.status.stage}"
217
+ item.date.each { |d| puts "Date #{d.type}: #{d.on || d.from}" }
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,73 @@
1
+ module Relaton
2
+ module Cli
3
+ class SubcommandDb < Thor
4
+ include Relaton::Cli
5
+
6
+ desc "create DIR", "Create new cache DB. Default DIR is "\
7
+ "/home/user/.relaon/cache/"
8
+
9
+ def create(dir = nil)
10
+ db = Relaton.db (dir && File.expand_path(dir))
11
+ path = db.instance_variable_get(:@db).dir
12
+ warn "Cache DB is in \"#{path}\""
13
+ end
14
+
15
+ desc "mv DIR", "Move cache DB to a new directory"
16
+
17
+ def mv(dir)
18
+ new_path = File.expand_path dir
19
+ path = Relaton.db.mv new_path
20
+ if path
21
+ File.write Cli::RelatonDb::DBCONF, path, encoding: "UTF-8"
22
+ warn "Cache DB is moved to \"#{path}\""
23
+ end
24
+ end
25
+
26
+ desc "clear", "Clear cache DB"
27
+
28
+ def clear
29
+ Relaton.db.clear
30
+ warn "Cache DB is cleared"
31
+ end
32
+
33
+ desc "fetch CODE", "Fetch Relaton XML for Standard identifier CODE from "\
34
+ "cache DB"
35
+ option :type, aliases: :t, desc: "Type of standard to "\
36
+ "get bibliographic entry for"
37
+ option :format, aliases: :f, desc: "Output format (xml, yaml, bibtex). "\
38
+ "Default xml."
39
+ option :year, aliases: :y, type: :numeric, desc: "Year the standard was "\
40
+ "published"
41
+
42
+ def fetch(code)
43
+ io = IO.new($stdout.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
44
+ opts = options.merge(fetch_db: true)
45
+ io.puts(fetch_document(code, opts) || supported_type_message)
46
+ end
47
+
48
+ desc "fetch_all TEXT", "Query for all documents in a cache DB for a "\
49
+ "certain string"
50
+ option :edition, aliases: :e, desc: "Filter entries by edition"
51
+ option :year, aliases: :y, desc: "Filter entries by year"
52
+ option :format, aliases: :f, desc: "Output format (xml, yaml, bibtex). "\
53
+ "Default xml."
54
+
55
+ def fetch_all(text = nil) # rubocop:disable Metrics/AbcSize
56
+ io = IO.new($stdout.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
57
+ opts = options.each_with_object({}) do |(k, v), o|
58
+ o[k.to_sym] = v unless k == "format"
59
+ end
60
+ Relaton.db.fetch_all(text, **opts).each do |doc|
61
+ io.puts serialize(doc, options[:format])
62
+ end
63
+ end
64
+
65
+ desc "doctype REF", "Detect document type from REF"
66
+
67
+ def doctype(ref)
68
+ io = IO.new($stdout.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
69
+ io.puts Relaton.db.docid_type(ref)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Cli
3
- VERSION = "1.4.0".freeze
3
+ VERSION = "1.7.pre3".freeze
4
4
  end
5
5
  end
@@ -13,9 +13,9 @@ module Relaton::Cli
13
13
  # @param index_xml [String] Relaton XML
14
14
  # @return [String] HTML
15
15
  def render(index_xml)
16
- Liquid::Template.
17
- parse(template).
18
- render(build_liquid_document(index_xml))
16
+ Liquid::Template
17
+ .parse(template)
18
+ .render(build_liquid_document(index_xml))
19
19
  end
20
20
 
21
21
  def uri_for_extension(uri, extension)
@@ -32,7 +32,7 @@ module Relaton::Cli
32
32
  # @param options [Hash]
33
33
  # @return [String] HTML
34
34
  def self.render(file, options)
35
- new(options).render(file)
35
+ new(**options).render(file)
36
36
  end
37
37
 
38
38
  private
@@ -43,16 +43,23 @@ module Relaton::Cli
43
43
  File.read(file, encoding: "utf-8")
44
44
  end
45
45
 
46
+ # rubocop:disable Metrics/MethodLength
46
47
  # @param source [String] Relaton XML
47
48
  def build_liquid_document(source)
48
49
  bibcollection = build_bibcollection(source)
49
-
50
+ begin
51
+ mnv = `metanorma -v`
52
+ rescue Errno::ENOENT
53
+ mnv = ""
54
+ end
50
55
  hash_to_liquid(
51
56
  depth: 2,
52
57
  css: stylesheet,
53
58
  title: bibcollection.title,
59
+ date: Date.today.to_s,
60
+ metanorma_v: mnv.lines.first&.strip,
54
61
  author: bibcollection.author,
55
- documents: document_items(bibcollection),
62
+ documents: document_items(bibcollection)
56
63
  )
57
64
  end
58
65
 
@@ -63,7 +70,7 @@ module Relaton::Cli
63
70
  Liquid::Template.file_system = file_system
64
71
  end
65
72
 
66
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
73
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
74
 
68
75
  # TODO: This should be recursive, but it's not
69
76
  # @param hash [Hash]
@@ -37,7 +37,7 @@ module Relaton
37
37
  processor.hash_to_bib content
38
38
  else
39
39
  RelatonBib::BibliographicItem.new(
40
- RelatonBib::HashConverter::hash_to_bib(content)
40
+ **RelatonBib::HashConverter::hash_to_bib(content)
41
41
  )
42
42
  end
43
43
  end
@@ -15,11 +15,11 @@ module Relaton
15
15
  end
16
16
 
17
17
  def apply_namespace(xpath)
18
- xpath.
19
- gsub(%r{/([a-zA-Z])}, "/xmlns:\\1").
20
- gsub(%r{::([a-zA-Z])}, "::xmlns:\\1").
21
- gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
22
- gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
18
+ xpath
19
+ .gsub(%r{/([a-zA-Z])}, "/xmlns:\\1")
20
+ .gsub(%r{::([a-zA-Z])}, "::xmlns:\\1")
21
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
22
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
23
23
  end
24
24
  end
25
25
  end
data/relaton-cli.gemspec CHANGED
@@ -23,18 +23,19 @@ Gem::Specification.new do |spec|
23
23
  spec.required_ruby_version = ">= 2.4.0"
24
24
 
25
25
  spec.add_development_dependency "byebug", "~> 11.0"
26
- spec.add_development_dependency "debase"
26
+ # spec.add_development_dependency "debase"
27
27
  spec.add_development_dependency "equivalent-xml", "~> 0.6"
28
28
  spec.add_development_dependency "pry"
29
- spec.add_development_dependency "rake", "~> 12.0"
29
+ spec.add_development_dependency "rake"
30
30
  spec.add_development_dependency "rspec", "~> 3.0"
31
31
  spec.add_development_dependency "rspec-command", "~> 1.0.3"
32
32
  spec.add_development_dependency "rspec-core", "~> 3.4"
33
- spec.add_development_dependency "ruby-debug-ide"
33
+ # spec.add_development_dependency "ruby-debug-ide"
34
34
  spec.add_development_dependency "simplecov"
35
+ spec.add_development_dependency "vcr"
36
+ spec.add_development_dependency "webmock"
35
37
 
36
- spec.add_runtime_dependency "liquid"
37
- spec.add_runtime_dependency "relaton", "~> 1.4.0"
38
+ spec.add_runtime_dependency "liquid", "~> 4"
39
+ spec.add_runtime_dependency "relaton", "1.7.pre7"
38
40
  spec.add_runtime_dependency "thor"
39
- # spec.add_runtime_dependency 'byebug'
40
41
  end
@@ -17,7 +17,12 @@
17
17
  <body>
18
18
  <header>
19
19
  <div id="topbar-inner">
20
- <div id="title-bar"><span>{{ author }}</span></div>
20
+ <div id="title-bar">
21
+ <div class="doc-access">
22
+ Generated: {{ date }}{% if metanorma_v != nil %} {{ metanorma_v }}{% endif %}
23
+ </div>
24
+ <span>{{ author }}</span>
25
+ </div>
21
26
  </div>
22
27
  <div class="title-section">
23
28
  <div class="coverpage">
@@ -34,6 +39,9 @@
34
39
  </main>
35
40
  <footer>
36
41
  <div class="copyright">
42
+ <div class="doc-access">
43
+ Generated: {{ date }}{% if metanorma_v != nil %} {{ metanorma_v }}{% endif %}
44
+ </div>
37
45
  <p class="year">&copy; {{ author }}</p>
38
46
  <p class="message">All rights reserved. Unless otherwise specified, no part of this publication may be reproduced or utilized otherwise in any form or by any means, electronic or mechanical, including photocopying, or posting on the internet or an intranet, without prior written permission.</p>
39
47
  </div>