relaton-cli 1.5.0 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ # require "forwardable"
2
+
3
+ module Relaton
4
+ class FullTextSeatch
5
+ # extend Forwardable
6
+
7
+ # def_delegators :@collections, :<<
8
+
9
+ # @return Regexp
10
+ attr_reader :regex
11
+
12
+ # @param collection [Relaton::Bibcollection]
13
+ def initialize(collection)
14
+ @collection = collection
15
+ end
16
+
17
+ # @param text [String]
18
+ # @return [Array<Hash>]
19
+ def search(text)
20
+ @regex = %{(.*?)(.{0,20})(#{text})(.{0,20})(.*)}
21
+ @matches = @collection.items.reduce({}) do |m, item|
22
+ # m + results(col, rgx)
23
+ res = result item
24
+ m[item.id] = res if res.any?
25
+ m
26
+ end
27
+ end
28
+
29
+ def print_results
30
+ @matches.each do |docid, attrs|
31
+ puts " Document ID: #{docid}"
32
+ print_attrs attrs, 4
33
+ end
34
+ end
35
+
36
+ # @return [Boolean]
37
+ def any?
38
+ @matches.any?
39
+ end
40
+
41
+ private
42
+
43
+ # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
44
+ def print_attrs(attrs, indent)
45
+ ind = " " * indent
46
+ if attrs.is_a? String then puts ind + attrs
47
+ elsif attrs.is_a? Hash
48
+ attrs.each do |key, val|
49
+ pref = "#{ind}#{key}:"
50
+ if val.is_a? String then puts pref + " " + val
51
+ else
52
+ puts pref
53
+ print_attrs val, indent + 2
54
+ end
55
+ end
56
+ elsif attrs.is_a? Array then attrs.each { |v| print_attrs v, indent + 2 }
57
+ end
58
+ end
59
+
60
+ # @param item [Relaton::Bibdata]
61
+ # @return [Hash]
62
+ def result(item)
63
+ if item.is_a? String
64
+ message $~ if item.match regex
65
+ elsif item.respond_to? :reduce
66
+ item.reduce([]) do |m, i|
67
+ res = result i
68
+ m << res if res && !res.empty?
69
+ m
70
+ end
71
+ else
72
+ item.instance_variables.reduce({}) do |m, var|
73
+ res = result item.instance_variable_get(var)
74
+ m[var.to_s.tr(":@", "")] = res if res && !res.empty?
75
+ m
76
+ end
77
+ end
78
+ end
79
+ # rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
80
+
81
+ # @param match [MatchData]
82
+ # @return [String]
83
+ def message(match)
84
+ msg = ""
85
+ msg += "..." unless match[1].empty?
86
+ msg += "#{match[2]}\e[4m#{match[3]}\e[24m#{match[4]}"
87
+ msg += "..." unless match[5].empty?
88
+ msg
89
+ end
90
+ end
91
+ end
@@ -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 = Cli.relaton.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 "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
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Cli
3
- VERSION = "1.5.0".freeze
3
+ VERSION = "1.7.2".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.5.0"
38
+ spec.add_runtime_dependency "liquid", "~> 4"
39
+ spec.add_runtime_dependency "relaton", "~> 1.7.0"
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>