relaton-cli 1.5.0 → 1.6.pre1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 421e4a675216ae65860c59a257d87c10262528a5236e5658a59de0c22187848d
4
- data.tar.gz: ee4355d9c9667991305a7ff65ce5f4f922c229fb07a5de8e9148ca27eade0a47
3
+ metadata.gz: ed63f43a96203a951be4ea86d97e9c8de8310a033fb9e7a209614c6697dc67cd
4
+ data.tar.gz: fe90f7f4a81a6b876e6c33d2f3211faab8665ace18114a9374b7a44449e6e59b
5
5
  SHA512:
6
- metadata.gz: 9121a5b70e059c108d010a9b5a51355d61d505d0454cfbbff9bbe8142aee0972bf5490f9d85a96c27380feab2b618c911cd113c20b49859daec0f1bcb05a67f2
7
- data.tar.gz: 65f2e8638b2802e4d72cbfdfbd7a7f378ed33fafbf9ce4d75ae1fa5863d12883c96f4450100b7e846cd5c865aea15fb28c2d9976ace0671a39abed22aa58ae26
6
+ metadata.gz: 34f44eb739fbace9b3c1fa05433416ed123f7dbf0ca5915c240f9bf6ca5d4fd89dd3e3e6b68550282b7088578fe3383a85495e2e9aa9f08e4a827c66e56976c0
7
+ data.tar.gz: 93dde4b12124fa01e5d6a6da86a61dc0456b9e3ecb6f109dfa95dd4d248d460b3541245a2c7f831dde7bc86a22cf851ac543c1b45ca0c77dfc5c584f2e525a5e
@@ -26,6 +26,8 @@ jobs:
26
26
  - name: Update gems
27
27
  run: |
28
28
  sudo gem install bundler --force
29
+ ruby -v | grep 2.5 && bundle config set build.debase --with-cflags="-Wno-error=implicit-function-declaration"
30
+ ruby -v | grep 2.5 && bundle config set build.ruby-debug-ide --with-cflags="-Wno-error=implicit-function-declaration"
29
31
  bundle install --jobs 4 --retry 3
30
32
  - name: Run specs
31
33
  run: |
@@ -50,8 +50,7 @@ Fetch the Relaton XML entry corresponding to the document identifier `CODE`.
50
50
 
51
51
  * `YEAR` is optional, and specifies the year of publication of the standard.
52
52
  * `FORMAT` is optional, and specifies the output format; the recognised values for `FORMAT` are `xml` (default), `bibtex`.
53
- * `TYPE` specifies the standards class library to be used, that the identifier is part of; the recognised
54
- values for `TYPE` are `isobib`, `ietfbib`, `iecbib`, `gbbib`.
53
+ * `TYPE` specifies the standards class library to be used, that the identifier is part of. The recognised values for `TYPE` are `BIPM`, `CC`, `CN`, `IEC`, `IEEE`, `IETF`, `IHO`, `ISO`, `ITU`, `NIST`, `OGC`, `OMG`, `UN`, `W3C`.
55
54
 
56
55
  === relaton extract
57
56
 
@@ -217,3 +216,94 @@ $ relaton convert XML -f FORMAT -o OUTPUT-FILE
217
216
  ----
218
217
 
219
218
  Convert a Relaton XML document into YAML, AsciiBib, or BibTex format. Allowed -f or --format options are yaml, asciibib, bibtex. If the option -o or --output is omitted then a new file will be created in the folder where the original file is, with the same name but another appropriated extension.
219
+
220
+ === relaton collection
221
+
222
+ The `relaton collection` is a set of subcommands for collections manipulations.
223
+
224
+ ==== relaton collection create
225
+
226
+ ----
227
+ $ relaton collection create COLLECTION -d DIRECTORY --author AUTHOR --title TITLE --doctype DOCTYPE
228
+ ----
229
+
230
+ Create new empty collection with name `COLLECTION`.
231
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
232
+ * `AUTHOR`, `TITLE`, and `DOCTYPE` are optional.
233
+
234
+ ==== relaton collection info
235
+
236
+ ----
237
+ $ relaton collection info COLLECTION -d DIRECTORY
238
+ ----
239
+
240
+ Show information about `COLLECTION` (number of items, file size of collection, last updated, name, metadata).
241
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
242
+
243
+ ==== relaton collection list
244
+
245
+ ----
246
+ $ relaton collection list -d DIRECTORY -e
247
+ ----
248
+
249
+ List all collections.
250
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
251
+ * When parametr `-e` is defined the id of each entry id will be listed.
252
+
253
+ ==== relaton collection get
254
+
255
+ ----
256
+ $ relaton collection get CODE -c COLLECTION -d DIRECTORY -f FORMAT -o FILE
257
+ ----
258
+
259
+ Get a document matched to `CODE` from `COLLECTION`.
260
+
261
+ * `COLLECTION` is optional name of collection. If undefined then fetch the first match across all collections in `DIRECTORY`.
262
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
263
+ * `FORMAT` is optional. If udefined then print documern in a human-readable form. Allowed values are `abb` (AsciiBib) or `xml` (XML).
264
+ * `FILE` is optional. When it's defined then save document with given file name. File's extension defines format of the file. Possible extensions are `abb` (AsciiBib) or `xml` (XML).
265
+
266
+ ==== relaton collection find
267
+
268
+ ----
269
+ $ relaton collection find TEXT -c COLLECTION -d DIRECTORY
270
+ ----
271
+
272
+ Full-text search through a collection or all collections.
273
+
274
+ * `COLLECTION` is optional name of collection. If udefined then search across all collections.
275
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
276
+
277
+ ==== relaton collection fetch
278
+
279
+ ----
280
+ $ relaton collection fetch CODE -t TYPE -y YEAR -c COLLECTION -d DIRECTORY
281
+ ----
282
+
283
+ Fetch the Relaton XML entry corresponding to the document identifier `CODE` and save it into `COLLECTION`.
284
+
285
+ * `TYPE` specifies the standards class library to be used, that the identifier is part of. The recognised values for `TYPE` are `BIPM`, `CC`, `CN`, `IEC`, `IEEE`, `IETF`, `IHO`, `ISO`, `ITU`, `NIST`, `OGC`, `OMG`, `UN`, `W3C`.
286
+ * `YEAR` is optional, and specifies the year of publication of the standard.
287
+ * `COLLECTION` is a name of collection.
288
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
289
+
290
+ ==== relaton collection export
291
+
292
+ ----
293
+ $ relaton collection export COLLECTION -d DIRECTORY
294
+ ----
295
+
296
+ Export `COLLECTION` into XML file.
297
+
298
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
299
+
300
+ ==== relaton collection import
301
+
302
+ ----
303
+ $ relaton collection import FILE -c COLLECTION -d DIRECTORY
304
+ ----
305
+
306
+ Import document or collection from XML `FILE` into `COLLECTION`.
307
+
308
+ * `COLLECTION` is optional. If collection doesn't exist then it will be created.
309
+ * `DIRECTORY` is optional, and specifies path to a directory with collections. Default is `$HOME/.relaton/collections`.
@@ -8,36 +8,34 @@ module Relaton
8
8
 
9
9
  attr_accessor *ATTRIBS
10
10
 
11
- # rubocop:disable Metrics/MethodLength
12
-
11
+ # @param options [Hash]
13
12
  def initialize(options)
14
- self.items = []
15
13
  ATTRIBS.each do |k|
16
14
  value = options[k] || options[k.to_s]
17
15
  send("#{k}=", value)
18
16
  end
19
- self.items = (items || []).reduce([]) do |acc, item|
20
- acc << if item.is_a?(Bibcollection) || item.is_a?(Bibdata)
21
- item
22
- else new_bib_item_class(item)
23
- end
24
- end
17
+ reduce_items
25
18
  end
26
- # rubocop:enable Metrics/MethodLength
27
19
 
28
20
  # arbitrary number, must sort after all bib items
29
21
  def doc_number
30
22
  9999999
31
23
  end
32
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
+
33
31
  # rubocop:disable Metrics/MethodLength
34
32
 
35
33
  # @param source [Nokogiri::XML::Element]
36
34
  def self.from_xml(source)
37
35
  title = find_text("./relaton-collection/title", source)
38
36
  author = find_text(
39
- "./relaton-collection/contributor[role/@type='author']/organization/name",
40
- source,
37
+ "./relaton-collection/contributor[role/@type='author']/organization/"\
38
+ "name", source
41
39
  )
42
40
 
43
41
  items = find_xpath("./relaton-collection/relation", source)&.map do |item|
@@ -48,29 +46,8 @@ module Relaton
48
46
 
49
47
  new(title: title, author: author, items: items)
50
48
  end
51
- # rubocop:enable Metrics/MethodLength
52
-
53
- def new_bib_item_class(options)
54
- if options.is_a?(Hash) && options["items"]
55
- ::Relaton::Bibcollection.new(options)
56
- else
57
- ::Relaton::Bibdata.new(options)
58
- end
59
- end
60
-
61
- def items_flattened
62
- items.sort_by! &:docnumber
63
-
64
- items.reduce([]) do |acc,item|
65
- acc << if item.is_a? ::Relaton::Bibcollection
66
- item.items_flattened
67
- else
68
- item
69
- end
70
- end
71
- end
72
49
 
73
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
50
+ # rubocop:disable Metrics/AbcSize
74
51
 
75
52
  # @param opts [Hash]
76
53
  # @return [String] XML
@@ -98,7 +75,37 @@ module Relaton
98
75
  end
99
76
  ret += "</relaton-collection>\n"
100
77
  end
101
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
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
102
109
 
103
110
  def to_yaml
104
111
  to_h.to_yaml
@@ -116,5 +123,16 @@ module Relaton
116
123
 
117
124
  { "root" => a }
118
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
119
137
  end
120
138
  end
@@ -4,8 +4,10 @@ module Relaton
4
4
  class Bibdata
5
5
  URL_TYPES = %i[uri xml pdf doc html rxl txt].freeze
6
6
 
7
+ # @return [RelatonBib::BibliographicItem]
7
8
  attr_reader :bibitem
8
9
 
10
+ # @param bibitem [RelatonBib::BibliographicItem]
9
11
  def initialize(bibitem)
10
12
  @bibitem = bibitem
11
13
  end
@@ -16,40 +16,58 @@ module Relaton
16
16
  end
17
17
  end
18
18
 
19
- def self.start(arguments)
20
- Relaton::Cli::Command.start(arguments)
21
- end
19
+ class << self
20
+ def start(arguments)
21
+ Relaton::Cli::Command.start(arguments)
22
+ end
22
23
 
23
- # Relaton
24
- #
25
- # Based on current setup, we need to initiate a Db instance to
26
- # register all of it's supported processor backends. To make it
27
- # easier we have added it as a class method so we can use this
28
- # whenever necessary.
29
- #
30
- def self.relaton
31
- RelatonDb.instance.db
32
- end
24
+ # Relaton
25
+ #
26
+ # Based on current setup, we need to initiate a Db instance to
27
+ # register all of it's supported processor backends. To make it
28
+ # easier we have added it as a class method so we can use this
29
+ # whenever necessary.
30
+ #
31
+ def relaton
32
+ RelatonDb.instance.db
33
+ end
33
34
 
34
- # @param content [Nokogiri::XML::Document]
35
- # @return [RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliongraphicItem]
36
- def self.parse_xml(doc)
37
- if (proc = Cli.processor(doc))
38
- proc.from_xml(doc.to_s)
39
- else
40
- RelatonBib::XMLParser.from_xml(doc.to_s)
35
+ # @param content [Nokogiri::XML::Document]
36
+ # @return [RelatonBib::BibliographicItem,
37
+ # RelatonIsoBib::IsoBibliongraphicItem]
38
+ def parse_xml(doc)
39
+ if (proc = Cli.processor(doc))
40
+ proc.from_xml(doc.to_s)
41
+ else
42
+ RelatonBib::XMLParser.from_xml(doc.to_s)
43
+ end
41
44
  end
42
- end
43
45
 
44
- # @param doc [Nokogiri::XML::Element]
45
- # @return [String] Type prefix
46
- def self.processor(doc)
47
- docid = doc.at "docidentifier"
48
- if docid && docid[:type]
49
- proc = Relaton::Registry.instance.by_type(docid[:type])
46
+ # @param doc [Nokogiri::XML::Element]
47
+ # @return [RelatonIso::Processor, RelatonIec::Processor,
48
+ # RelatonNist::Processor, RelatonIetf::Processot,
49
+ # RelatonItu::Processor, RelatonGb::Processor,
50
+ # RelatonOgc::Processor, RelatonCalconnect::Processor]
51
+ def processor(doc)
52
+ docid = doc.at "docidentifier"
53
+ proc = get_proc docid
50
54
  return proc if proc
55
+
56
+ Relaton::Registry.instance.by_type(docid&.text&.match(/^\w+/)&.to_s)
57
+ end
58
+
59
+ private
60
+
61
+ # @param doc [Nokogiri::XML::Element]
62
+ # @return [RelatonIso::Processor, RelatonIec::Processor,
63
+ # RelatonNist::Processor, RelatonIetf::Processot,
64
+ # RelatonItu::Processor, RelatonGb::Processor,
65
+ # RelatonOgc::Processor, RelatonCalconnect::Processor]
66
+ def get_proc(docid)
67
+ return unless docid && docid[:type]
68
+
69
+ Relaton::Registry.instance.by_type(docid[:type])
51
70
  end
52
- Relaton::Registry.instance.by_type(docid&.text&.match(/^\w+/)&.to_s)
53
71
  end
54
72
  end
55
73
  end
@@ -52,7 +52,7 @@ module Relaton
52
52
  Relaton::Cli::XmlToHtmlRenderer.render(
53
53
  xml_content(file),
54
54
  stylesheet: options[:style],
55
- liquid_dir: options[:template],
55
+ liquid_dir: options[:template]
56
56
  )
57
57
  end
58
58
 
@@ -1,93 +1,128 @@
1
1
  require "relaton/cli/relaton_file"
2
2
  require "relaton/cli/xml_convertor"
3
3
  require "relaton/cli/yaml_convertor"
4
+ require "relaton/cli/subcommand_collection"
4
5
  require "fcntl"
5
6
 
6
7
  module Relaton
7
8
  module Cli
8
9
  class Command < Thor
9
10
  desc "fetch CODE", "Fetch Relaton XML for Standard identifier CODE"
10
- option :type, aliases: :t, required: true, desc: "Type of standard to get bibliographic entry for"
11
- option :format, aliases: :f, desc: "Output format (xml, bibtex). Default xml."
12
- option :year, aliases: :y, type: :numeric, desc: "Year the standard was published"
11
+ option :type, aliases: :t, required: true, desc: "Type of standard to "\
12
+ "get bibliographic entry for"
13
+ option :format, aliases: :f, desc: "Output format (xml, bibtex). "\
14
+ "Default xml."
15
+ option :year, aliases: :y, type: :numeric, desc: "Year the standard was "\
16
+ "published"
13
17
 
14
18
  def fetch(code)
15
19
  Relaton.db
16
- io = IO.new(STDOUT.fcntl(::Fcntl::F_DUPFD), mode: 'w:UTF-8')
20
+ io = IO.new(STDOUT.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
17
21
  io.puts(fetch_document(code, options) || supported_type_message)
18
22
  end
19
23
 
20
- desc "extract Metanorma-XML-File / Directory Relaton-XML-Directory", "Extract Relaton XML from Metanorma XML file / directory"
21
- option :extension, aliases: :x, default: "rxl", desc: "File extension of Relaton XML files, defaults to 'rxl'"
24
+ desc "extract Metanorma-XML-File / Directory Relaton-XML-Directory",
25
+ "Extract Relaton XML from Metanorma XML file / directory"
26
+ option :extension, aliases: :x, default: "rxl", desc: "File extension "\
27
+ "of Relaton XML files, defaults to 'rxl'"
22
28
 
23
29
  def extract(source_dir, outdir)
24
30
  Relaton::Cli::RelatonFile.extract(source_dir, outdir, options)
25
31
  end
26
32
 
27
- desc "concatenate SOURCE-DIR COLLECTION-FILE", "Concatenate entries in DIRECTORY (containing Relaton-XML or YAML) into a Relaton Collection"
33
+ desc "concatenate SOURCE-DIR COLLECTION-FILE", "Concatenate entries in "\
34
+ "DIRECTORY (containing Relaton-XML or YAML) into a Relaton Collection"
28
35
  option :title, aliases: :t, desc: "Title of resulting Relaton collection"
29
- option :organization, aliases: :g, desc: "Organization owner of Relaton collection"
30
- option :new, aliases: :n, type: :boolean, desc: "Use the new Relaton YAML format"
31
- option :extension, aliases: :x, desc: "File extension of destination Relaton file, defaults to 'rxl'"
36
+ option :organization, aliases: :g, desc: "Organization owner of Relaton "\
37
+ "collection"
38
+ option :new, aliases: :n, type: :boolean, desc: "Use the new Relaton "\
39
+ "YAML format"
40
+ option :extension, aliases: :x, desc: "File extension of destination "\
41
+ "Relaton file, defaults to 'rxl'"
32
42
 
33
43
  def concatenate(source_dir, outfile)
34
44
  Relaton::Cli::RelatonFile.concatenate(source_dir, outfile, options)
35
45
  end
36
46
 
37
- desc "split Relaton-Collection-File Relaton-XML-Directory", "Split a Relaton Collection into multiple files"
38
- option :extension, aliases: :x, default: "rxl", desc: "File extension of Relaton XML files, defaults to 'rxl'"
39
- option :new, aliases: :n, type: :boolean, desc: "Use the new Relaton YAML format"
47
+ desc "split Relaton-Collection-File Relaton-XML-Directory", "Split a "\
48
+ "Relaton Collection into multiple files"
49
+ option :extension, aliases: :x, default: "rxl", desc: "File extension "\
50
+ "of Relaton XML files, defaults to 'rxl'"
51
+ option :new, aliases: :n, type: :boolean, desc: "Use the new Relaton "\
52
+ "YAML format"
40
53
 
41
54
  def split(source, outdir)
42
55
  Relaton::Cli::RelatonFile.split(source, outdir, options)
43
56
  end
44
57
 
45
- desc "yaml2xml YAML", "Convert Relaton YAML into Relaton Collection XML or separate files"
46
- option :extension, aliases: :x, default: "rxl", desc: "File extension of Relaton XML files, defaults to 'rxl'"
47
- option :prefix, aliases: :p, desc: "Filename prefix of individual Relaton XML files, defaults to empty"
48
- option :outdir, aliases: :o, desc: "Output to the specified directory with individual Relaton Bibdata XML files"
49
- option :require, aliases: :r, type: :array, desc: "Require LIBRARY prior to execution"
50
- option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
58
+ desc "yaml2xml YAML", "Convert Relaton YAML into Relaton Collection XML "\
59
+ "or separate files"
60
+ option :extension, aliases: :x, default: "rxl", desc: "File extension "\
61
+ "of Relaton XML files, defaults to 'rxl'"
62
+ option :prefix, aliases: :p, desc: "Filename prefix of individual "\
63
+ "Relaton XML files, defaults to empty"
64
+ option :outdir, aliases: :o, desc: "Output to the specified directory "\
65
+ "with individual Relaton Bibdata XML files"
66
+ option :require, aliases: :r, type: :array, desc: "Require LIBRARY "\
67
+ "prior to execution"
68
+ option :overwrite, aliases: :f, type: :boolean, default: false,
69
+ desc: "Overwrite the existing file"
51
70
 
52
71
  def yaml2xml(filename)
53
72
  Relaton::Cli::YAMLConvertor.to_xml(filename, options)
54
73
  end
55
74
 
56
- desc "xml2yaml XML", "Convert Relaton XML into Relaton Bibdata / Bibcollection YAML (and separate files)"
57
- option :extension, aliases: :x, default: "yaml", desc: "File extension of Relaton YAML files, defaults to 'yaml'"
58
- option :prefix, aliases: :p, desc: "Filename prefix of Relaton XML files, defaults to empty"
59
- option :outdir, aliases: :o, desc: "Output to the specified directory with individual Relaton Bibdata YAML files"
60
- option :require, aliases: :r, type: :array, desc: "Require LIBRARY prior to execution"
61
- option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
75
+ desc "xml2yaml XML", "Convert Relaton XML into Relaton Bibdata / "\
76
+ "Bibcollection YAML (and separate files)"
77
+ option :extension, aliases: :x, default: "yaml", desc: "File extension "\
78
+ "of Relaton YAML files, defaults to 'yaml'"
79
+ option :prefix, aliases: :p, desc: "Filename prefix of Relaton XML "\
80
+ "files, defaults to empty"
81
+ option :outdir, aliases: :o, desc: "Output to the specified directory "\
82
+ "with individual Relaton Bibdata YAML files"
83
+ option :require, aliases: :r, type: :array, desc: "Require LIBRARY "\
84
+ "prior to execution"
85
+ option :overwrite, aliases: :f, type: :boolean, default: false,
86
+ desc: "Overwrite the existing file"
62
87
 
63
88
  def xml2yaml(filename)
64
89
  Relaton::Cli::XMLConvertor.to_yaml(filename, options)
65
90
  end
66
91
 
67
- desc "xml2html RELATON-INDEX-XML", "Convert Relaton Collection XML into HTML"
68
- option :stylesheet, aliases: :s, desc: "Stylesheet file path for rendering HTML index"
69
- option :templatedir, aliases: :t, desc: "Liquid template directory for rendering Relaton items and collection"
70
- option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
92
+ desc "xml2html RELATON-INDEX-XML", "Convert Relaton Collection XML into "\
93
+ "HTML"
94
+ option :stylesheet, aliases: :s, desc: "Stylesheet file path for "\
95
+ "rendering HTML index"
96
+ option :templatedir, aliases: :t, desc: "Liquid template directory for "\
97
+ "rendering Relaton items and collection"
98
+ option :overwrite, aliases: :f, type: :boolean, default: false,
99
+ desc: "Overwrite the existing file"
71
100
 
72
101
  def xml2html(file, style = nil, template = nil)
73
102
  Relaton::Cli::XMLConvertor.to_html(file, style, template)
74
103
  end
75
104
 
76
- desc "yaml2html RELATON-INDEX-YAML", "Concatenate Relaton Collection YAML into HTML"
77
- option :stylesheet, aliases: :s, desc: "Stylesheet file path for rendering HTML index"
78
- option :templatedir, aliases: :t, desc: "Liquid template directory for rendering Relaton items and collection"
79
- option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
105
+ desc "yaml2html RELATON-INDEX-YAML", "Concatenate Relaton Collection "\
106
+ "YAML into HTML"
107
+ option :stylesheet, aliases: :s, desc: "Stylesheet file path for "\
108
+ "rendering HTML index"
109
+ option :templatedir, aliases: :t, desc: "Liquid template directory for "\
110
+ "rendering Relaton items and collection"
111
+ option :overwrite, aliases: :f, type: :boolean, default: false,
112
+ desc: "Overwrite the existing file"
80
113
 
81
114
  def yaml2html(file, style = nil, template = nil)
82
115
  Relaton::Cli::YAMLConvertor.to_html(file, style, template)
83
116
  end
84
117
 
85
118
  desc "convert XML", "Convert Relaton XML document"
86
- option :format, aliases: :f, required: true, desc: "Output format (yaml, bibtex, asciibib)"
119
+ option :format, aliases: :f, required: true, desc: "Output format "\
120
+ "(yaml, bibtex, asciibib)"
87
121
  option :output, aliases: :o, desc: "Output to the specified file"
88
122
 
89
- def convert(file)
90
- item = Relaton::Cli.parse_xml Nokogiri::XML(File.read(file, encoding: "UTF-8"))
123
+ def convert(file) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
124
+ xml = Nokogiri::XML(File.read(file, encoding: "UTF-8"))
125
+ item = Relaton::Cli.parse_xml xml
91
126
  result = if /yaml|yml/.match?(options[:format])
92
127
  item.to_hash.to_yaml
93
128
  else item.send "to_#{options[:format]}"
@@ -101,6 +136,9 @@ module Relaton
101
136
  File.write output, result, encoding: "UTF-8"
102
137
  end
103
138
 
139
+ desc "collection SUBCOMMAND", "Collection manipulations"
140
+ subcommand "collection", SubcommandCollection
141
+
104
142
  private
105
143
 
106
144
  # @param code [String]
@@ -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
@@ -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.6.pre1".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)
@@ -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]
@@ -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
@@ -32,9 +32,11 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "rspec-core", "~> 3.4"
33
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
38
  spec.add_runtime_dependency "liquid"
37
- spec.add_runtime_dependency "relaton", "~> 1.5.0"
39
+ spec.add_runtime_dependency "relaton", "~> 1.6.pre"
38
40
  spec.add_runtime_dependency "thor"
39
41
  # spec.add_runtime_dependency 'byebug'
40
42
  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>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-09 00:00:00.000000000 Z
11
+ date: 2020-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -150,6 +150,34 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: vcr
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: webmock
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: liquid
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +198,14 @@ dependencies:
170
198
  requirements:
171
199
  - - "~>"
172
200
  - !ruby/object:Gem::Version
173
- version: 1.5.0
201
+ version: 1.6.pre
174
202
  type: :runtime
175
203
  prerelease: false
176
204
  version_requirements: !ruby/object:Gem::Requirement
177
205
  requirements:
178
206
  - - "~>"
179
207
  - !ruby/object:Gem::Version
180
- version: 1.5.0
208
+ version: 1.6.pre
181
209
  - !ruby/object:Gem::Dependency
182
210
  name: thor
183
211
  requirement: !ruby/object:Gem::Requirement
@@ -225,7 +253,9 @@ files:
225
253
  - lib/relaton/cli.rb
226
254
  - lib/relaton/cli/base_convertor.rb
227
255
  - lib/relaton/cli/command.rb
256
+ - lib/relaton/cli/full_text_search.rb
228
257
  - lib/relaton/cli/relaton_file.rb
258
+ - lib/relaton/cli/subcommand_collection.rb
229
259
  - lib/relaton/cli/version.rb
230
260
  - lib/relaton/cli/xml_convertor.rb
231
261
  - lib/relaton/cli/xml_to_html_renderer.rb
@@ -250,9 +280,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
250
280
  version: 2.4.0
251
281
  required_rubygems_version: !ruby/object:Gem::Requirement
252
282
  requirements:
253
- - - ">="
283
+ - - ">"
254
284
  - !ruby/object:Gem::Version
255
- version: '0'
285
+ version: 1.3.1
256
286
  requirements: []
257
287
  rubygems_version: 3.0.6
258
288
  signing_key: