relaton-cli 1.20.5 → 1.20.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9532812554990a4cc11d27d32a940db3ae908343c7154de1268deec1cefa55fb
4
- data.tar.gz: 4bcfe71b907f013cee3e4f07751083016b23321cad540b1340f323051927946c
3
+ metadata.gz: 7ff8803a958b14fe70492cc25af28bfa118794bccc3228ae36212123209c2ab0
4
+ data.tar.gz: db4c4530d596210a187b2ddd2f750fef9c19cc10a07c7f19ecd8ab663485ad05
5
5
  SHA512:
6
- metadata.gz: f1679a4108b0bdb582b3ce78dd5eb8b13ee5e08194d9906e529e15ed394cc6d0d8a0f82ca53c6700d7cbe2e5137a6d86bb9c0356ee5b5ed004acd04c2f751d32
7
- data.tar.gz: 6e5051f654b4c48a8c9d08ca5a4e95e0960bfb893711dae1d124463f1dd5da251d7ffe70acf51bd9895cd5c986a74e6d122d4fb518670c47ad57a84f8ea40e6f
6
+ metadata.gz: 1f577e86bfc2f730ada8e74220dc37523837b0e6d286df337a4a1e5bb33501cbbcf783867c27fad946f1726c727ccbbf1493116ac6c8957b5031ac06792eeaed
7
+ data.tar.gz: c4ac8ee7cc37f9ac217d451a34bcee4bee6b4efe7036e92c160db6dd30d88b1f845ccb07d27f53a8b6e5a597663683f5537e3e1d85bde8942ac336f0c2128df3
data/.gitignore CHANGED
@@ -15,3 +15,4 @@
15
15
  .byebug_history
16
16
  Gemfile.lock
17
17
  .DS_Store
18
+ .claude/
data/CLAUDE.md ADDED
@@ -0,0 +1,96 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ relaton-cli is a Ruby CLI tool for managing bibliographic references to standards (ISO, IEC, IETF, NIST, etc.). It provides commands to fetch, convert, and organize standards metadata in XML, YAML, BibTeX, and HTML formats. Part of the broader Relaton/Metanorma ecosystem.
8
+
9
+ ## Common Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ bundle install
14
+
15
+ # Run all tests
16
+ bundle exec rspec
17
+
18
+ # Run a single test file
19
+ bundle exec rspec spec/relaton/cli/command_spec.rb
20
+
21
+ # Run a specific test by line number
22
+ bundle exec rspec spec/relaton/cli/command_spec.rb:42
23
+
24
+ # Build the gem
25
+ bundle exec rake build
26
+
27
+ # Lint (RuboCop, inherits from Ribose OSS guide)
28
+ bundle exec rubocop
29
+ bundle exec rubocop -a # auto-fix
30
+ ```
31
+
32
+ ## Architecture
33
+
34
+ ### Entry Point & CLI Framework
35
+
36
+ The executable `exe/relaton` calls `Relaton::Cli.start(ARGV)` which routes to `Relaton::Cli::Command`, a Thor-based command class. Thor handles argument parsing, option definitions, and subcommand routing.
37
+
38
+ ### Command Structure
39
+
40
+ - `lib/relaton/cli/command.rb` — Main Thor command class with top-level commands (fetch, extract, concatenate, split, yaml2xml, xml2yaml, xml2html, yaml2html, convert, fetch-data)
41
+ - `lib/relaton/cli/subcommand_collection.rb` — `relaton collection` subcommands (create, info, list, get, find, fetch, import, export)
42
+ - `lib/relaton/cli/subcommand_db.rb` — `relaton db` subcommands (create, mv, clear, fetch, fetch_all, doctype)
43
+
44
+ ### Option Forwarding Pattern
45
+
46
+ `Command#fetch` and `SubcommandDb#fetch` use the shared `fetch_document` helper (in `Relaton::Cli` private methods at the bottom of `command.rb`). This helper transforms Thor's kebab-case option keys to snake_case symbols via `gsub("-", "_").to_sym` and splats them as `**dup_opts` to `Relaton.db.fetch` / `Relaton.db.fetch_std`. Adding a new Thor option to these commands automatically forwards it to the underlying library with no method changes needed.
47
+
48
+ `SubcommandCollection#fetch` calls `Relaton.db.fetch` directly (not through `fetch_document`), so new options must be explicitly forwarded there.
49
+
50
+ Current fetch options that use this pattern: `--no-cache`, `--all-parts`, `--keep-year`, `--publication-date-before`, `--publication-date-after`.
51
+
52
+ ### Core Data Classes
53
+
54
+ - `lib/relaton/bibdata.rb` — `Relaton::Bibdata` wraps `RelatonBib::BibliographicItem`, adding URL type handling and serialization to XML/YAML/Hash. Uses `method_missing` to delegate to the underlying bibitem.
55
+ - `lib/relaton/bibcollection.rb` — `Relaton::Bibcollection` represents a collection of bibliographic items with title/author/doctype metadata. Handles XML/YAML round-tripping.
56
+ - `lib/relaton/element_finder.rb` — Mixin providing XPath utilities with namespace handling.
57
+
58
+ ### Converters (Template Method Pattern)
59
+
60
+ - `lib/relaton/cli/base_convertor.rb` — Abstract base defining the conversion flow (convert_and_write, write_to_file_collection)
61
+ - `lib/relaton/cli/xml_convertor.rb` — XML → YAML conversion
62
+ - `lib/relaton/cli/yaml_convertor.rb` — YAML → XML conversion (includes processor detection via doctype)
63
+ - `lib/relaton/cli/xml_to_html_renderer.rb` — Renders XML/YAML to HTML using Liquid templates from `templates/`
64
+
65
+ ### File Operations
66
+
67
+ `lib/relaton/cli/relaton_file.rb` — Static methods for extract (pull bibdata from Metanorma XML), concatenate (combine files into a collection), and split (break a collection into individual files).
68
+
69
+ ### Database (Singleton)
70
+
71
+ `Relaton::Cli::RelatonDb` (in `lib/relaton/cli.rb`) is a Singleton managing a `Relaton::Db` instance. DB path is persisted in `~/.relaton/dbpath`. The `relaton` gem's registry auto-discovers 30+ standard-body processors.
72
+
73
+ ### Processor Detection
74
+
75
+ `Relaton::Cli.processor(doc)` and `.parse_xml(doc)` detect the correct processor (ISO, IEC, IETF, etc.) from a document's `docidentifier` element type attribute, falling back to prefix matching.
76
+
77
+ ## Test Structure
78
+
79
+ - `spec/acceptance/` — End-to-end CLI integration tests using `rspec-command`
80
+ - `spec/relaton/cli/` — Unit tests for command, converters, subcommands, DB
81
+ - `spec/relaton/` — Unit tests for Bibcollection and Bibdata
82
+ - `spec/support/` — Test setup: SimpleCov, WebMock, VCR, equivalent-xml matchers
83
+ - `spec/fixtures/` and `spec/vcr_cassettes/` — Test data and recorded HTTP responses
84
+
85
+ Tests use VCR cassettes to replay HTTP interactions with standards registries. WebMock blocks real HTTP requests in tests.
86
+
87
+ ## Key Dependencies
88
+
89
+ - `relaton ~> 1.20.0` — Core library providing DB, registry, and all standard-body processors
90
+ - `thor` / `thor-hollaback` — CLI framework
91
+ - `liquid ~> 5` — HTML template rendering
92
+ - `nokogiri` (transitive via relaton) — XML parsing
93
+
94
+ ## Ruby Version
95
+
96
+ Requires Ruby >= 3.0.0 (set in gemspec and `.rubocop.yml`).
data/docs/README.adoc CHANGED
@@ -42,7 +42,7 @@ suports an additional `-x` or `--extension` options to use different extension.
42
42
 
43
43
  [source,console]
44
44
  ----
45
- $ relaton fetch CODE -t TYPE -f FORMAT -y YEAR -r RETRIES --all-parts --keep-year --no-cache
45
+ $ relaton fetch CODE -t TYPE -f FORMAT -y YEAR -r RETRIES --all-parts --keep-year --no-cache --publication-date-before DATE --publication-date-after DATE
46
46
  ----
47
47
 
48
48
  Fetch the Relaton XML entry corresponding to the document identifier `CODE`.
@@ -54,6 +54,8 @@ Fetch the Relaton XML entry corresponding to the document identifier `CODE`.
54
54
  * `--all-parts` fetch all parts.
55
55
  * `--keep-year` undated reference should return an actual reference with year.
56
56
  * `--no-cache` do not use cache.
57
+ * `--publication-date-before DATE` fetch only documents published before the specified date. Accepted formats: `YYYY`, `YYYY-MM`, `YYYY-MM-DD`.
58
+ * `--publication-date-after DATE` fetch only documents published after the specified date. Accepted formats: `YYYY`, `YYYY-MM`, `YYYY-MM-DD`.
57
59
 
58
60
  === relaton fetch-data
59
61
 
@@ -358,7 +360,7 @@ Full-text search through a collection or all collections.
358
360
  ==== relaton collection fetch
359
361
 
360
362
  ----
361
- $ relaton collection fetch CODE -t TYPE -y YEAR -c COLLECTION -d DIRECTORY
363
+ $ relaton collection fetch CODE -t TYPE -y YEAR -c COLLECTION -d DIRECTORY --publication-date-before DATE --publication-date-after DATE
362
364
  ----
363
365
 
364
366
  Fetch the Relaton XML entry corresponding to the document identifier `CODE` and save it into `COLLECTION`.
@@ -367,6 +369,8 @@ Fetch the Relaton XML entry corresponding to the document identifier `CODE` and
367
369
  * `YEAR` is optional, and specifies the year of publication of the standard.
368
370
  * `COLLECTION` - a name of a collection.
369
371
  * `DIRECTORY` - optional, and specifies a path to a directory with collections. The default value is `$HOME/.relaton/collections`.
372
+ * `--publication-date-before DATE` fetch only documents published before the specified date. Accepted formats: `YYYY`, `YYYY-MM`, `YYYY-MM-DD`.
373
+ * `--publication-date-after DATE` fetch only documents published after the specified date. Accepted formats: `YYYY`, `YYYY-MM`, `YYYY-MM-DD`.
370
374
 
371
375
  ==== relaton collection export
372
376
 
@@ -1,3 +1,4 @@
1
+ require "date"
1
2
  require "relaton/cli/relaton_file"
2
3
  require "relaton/cli/xml_convertor"
3
4
  require "relaton/cli/yaml_convertor"
@@ -31,6 +32,12 @@ module Relaton
31
32
  option :retries, aliases: :r, type: :numeric,
32
33
  desc: "Number of network retries. Default 1."
33
34
  option :"no-cache", type: :boolean, desc: "Ignore cache"
35
+ option :"publication-date-before",
36
+ desc: "Fetch only documents published before the specified date " \
37
+ "(e.g. 2008, 2008-02, or 2008-02-02)"
38
+ option :"publication-date-after",
39
+ desc: "Fetch only documents published after the specified date " \
40
+ "(e.g. 2002, 2002-01, or 2002-01-01)"
34
41
 
35
42
  def fetch(code)
36
43
  io = IO.new($stdout.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
@@ -174,6 +181,30 @@ module Relaton
174
181
 
175
182
  private
176
183
 
184
+ DATE_FILTER_FORMAT = /\A\d{4}(-\d{2}(-\d{2})?)?\z/
185
+
186
+ def parse_date_option(value, name)
187
+ return unless value
188
+
189
+ unless value.match?(DATE_FILTER_FORMAT)
190
+ raise ArgumentError,
191
+ "Invalid #{name}: #{value.inspect}. Expected YYYY, YYYY-MM, or YYYY-MM-DD."
192
+ end
193
+ parts = value.split("-").map(&:to_i)
194
+ Date.new(*parts.concat([1] * (3 - parts.size)))
195
+ rescue Date::Error
196
+ raise ArgumentError,
197
+ "Invalid #{name}: #{value.inspect}. Date components are out of range."
198
+ end
199
+
200
+ def validate_date_range(date_after, date_before)
201
+ return unless date_after && date_before
202
+ return if date_after < date_before
203
+
204
+ raise ArgumentError,
205
+ "Invalid date range: --publication-date-after (#{date_after}) must be before --publication-date-before (#{date_before})."
206
+ end
207
+
177
208
  # @param code [String]
178
209
  # @param options [Hash]
179
210
  # @option options [String] :type
@@ -183,6 +214,10 @@ module Relaton
183
214
  def fetch_document(code, options) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize,Metrics/MethodLength
184
215
  year = options[:year]&.to_s
185
216
  dup_opts = options.dup.transform_keys { |k| k.to_s.gsub("-", "_").to_sym }
217
+ %i[publication_date_before publication_date_after].each do |key|
218
+ dup_opts[key] = parse_date_option(dup_opts[key], key.to_s.tr("_", "-").prepend("--")) if dup_opts[key]
219
+ end
220
+ validate_date_range dup_opts[:publication_date_after], dup_opts[:publication_date_before]
186
221
  if (processor = Relaton::Registry.instance.by_type options[:type]&.upcase)
187
222
  doc = Relaton.db.fetch_std code, year, processor.short, **dup_opts
188
223
  elsif options[:type] then return
@@ -102,13 +102,27 @@ module Relaton
102
102
  desc: "Type of standard to get bibliographic entry for"
103
103
  option :year, aliases: :y, type: :numeric,
104
104
  desc: "Year the standard was published"
105
+ option :"publication-date-before",
106
+ desc: "Fetch only documents published before the specified date " \
107
+ "(e.g. 2008, 2008-02, or 2008-02-02)"
108
+ option :"publication-date-after",
109
+ desc: "Fetch only documents published after the specified date " \
110
+ "(e.g. 2002, 2002-01, or 2002-01-01)"
105
111
  option :collection, aliases: :c, required: true,
106
112
  desc: "Collection to store a document"
107
113
  option :dir, aliases: :d, desc: "Directory with collections. Default is " \
108
114
  "$HOME/.relaton/collections."
109
115
 
110
116
  def fetch(code) # rubocop:disable Metrics/AbcSize
111
- doc = Relaton.db.fetch(code, options[:year]&.to_s)
117
+ opts = {}
118
+ if options[:"publication-date-before"]
119
+ opts[:publication_date_before] = parse_date_option(options[:"publication-date-before"], "--publication-date-before")
120
+ end
121
+ if options[:"publication-date-after"]
122
+ opts[:publication_date_after] = parse_date_option(options[:"publication-date-after"], "--publication-date-after")
123
+ end
124
+ validate_date_range opts[:publication_date_after], opts[:publication_date_before]
125
+ doc = Relaton.db.fetch(code, options[:year]&.to_s, **opts)
112
126
  if doc
113
127
  colfile = File.join directory, options[:collection]
114
128
  coll = read_collection colfile
@@ -40,6 +40,12 @@ module Relaton
40
40
  "Default xml."
41
41
  option :year, aliases: :y, type: :numeric, desc: "Year the standard " \
42
42
  "was published"
43
+ option :"publication-date-before",
44
+ desc: "Fetch only documents published before the specified date " \
45
+ "(e.g. 2008, 2008-02, or 2008-02-02)"
46
+ option :"publication-date-after",
47
+ desc: "Fetch only documents published after the specified date " \
48
+ "(e.g. 2002, 2002-01, or 2002-01-01)"
43
49
 
44
50
  def fetch(code)
45
51
  io = IO.new($stdout.fcntl(::Fcntl::F_DUPFD), mode: "w:UTF-8")
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Cli
3
- VERSION = "1.20.5".freeze
3
+ VERSION = "1.20.6".freeze
4
4
  end
5
5
  end
data/relaton-cli.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.required_ruby_version = ">= 3.0.0"
24
24
 
25
25
  spec.add_runtime_dependency "liquid", "~> 5"
26
- spec.add_runtime_dependency "relaton", "~> 1.20.0"
26
+ spec.add_runtime_dependency "relaton", "~> 1.20.2"
27
27
  spec.add_runtime_dependency "thor"
28
28
  spec.add_runtime_dependency "thor-hollaback"
29
29
 
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.20.5
4
+ version: 1.20.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-24 00:00:00.000000000 Z
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.20.0
33
+ version: 1.20.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.20.0
40
+ version: 1.20.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: thor
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -97,6 +97,7 @@ files:
97
97
  - ".rspec"
98
98
  - ".rubocop.yml"
99
99
  - CHANGELOG.md
100
+ - CLAUDE.md
100
101
  - Gemfile
101
102
  - LICENSE
102
103
  - Rakefile