Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/rake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ name: rake

on:
push:
branches: [ master, main ]
branches: [ master, main, lutaml-integration ]
tags: [ v* ]
pull_request:
workflow_dispatch:

jobs:
rake:
Expand Down
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ require: rubocop-rails
inherit_from:
- https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
AllCops:
TargetRubyVersion: 3.0
TargetRubyVersion: 3.2
Rails:
Enabled: true
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ source "https://rubygems.org"
# Specify your gem's dependencies in gemspec
gemspec



gem "byebug", "~> 11.0"
gem "equivalent-xml", "~> 0.6"
gem "pry"
Expand All @@ -15,3 +17,4 @@ gem "simplecov"
gem "vcr"
gem "webmock"
gem "debug"
gem "fiddle"
424 changes: 169 additions & 255 deletions docs/README.adoc

Large diffs are not rendered by default.

16 changes: 12 additions & 4 deletions lib/relaton/bibcollection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def <<(item)

# @param source [Nokogiri::XML::Element]
def self.from_xml(source)
title = find_text("./relaton-collection/title", source)
author = find_text(
title = find_html("./relaton-collection/title", source)
author = find_html(
"./relaton-collection/contributor[role/@type='author']/organization/"\
"name", source
)
Expand Down Expand Up @@ -61,10 +61,10 @@ def to_xml(opts = {})
end

ret = "<relaton-collection #{collection_type}>"
ret += "<title>#{title}</title>" if title
ret += "<title>#{xml_escape(title)}</title>" if title
if author
ret += "<contributor><role type='author'/><organization><name>"\
"#{author}</name></organization></contributor>"
"#{xml_escape(author)}</name></organization></contributor>"
end
unless items.empty?
items.each do |item|
Expand Down Expand Up @@ -134,5 +134,13 @@ def reduce_items
end
end
end

# Escape bare & in content for XML serialization, leaving already-encoded
# entity references (&amp;, &#123;, &#x1f;) and inline markup (<em> etc.)
# untouched. This prevents invalid XML when plain-text values (e.g. from
# YAML) contain literal ampersands.
def xml_escape(str)
str.gsub(/&(?![a-zA-Z][a-zA-Z0-9]*;|#[0-9]+;|#x[0-9a-fA-F]+;)/, "&amp;")
end
end
end
20 changes: 10 additions & 10 deletions lib/relaton/bibdata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def initialize(bibitem)
end

def docidentifier
@bibitem.docidentifier.first&.id
@bibitem.docidentifier.first&.content&.to_s
end

# def doctype
Expand Down Expand Up @@ -50,10 +50,9 @@ def to_xml(opts = {})
end

def to_h
URL_TYPES.reduce(@bibitem.to_hash) do |h, t|
URL_TYPES.each_with_object(YAML.safe_load(@bibitem.to_yaml)) do |t, h|
value = send t
h[t.to_s] = value
h
h[t.to_s] = value if value
end
end

Expand All @@ -68,19 +67,20 @@ def method_missing(meth, *args)
if @bibitem.respond_to?(meth)
@bibitem.send meth, *args
elsif URL_TYPES.include? meth
link = @bibitem.link.detect do |l|
source = (@bibitem.source || []).detect do |l|
l.type == meth.to_s || (meth == :uri && l.type.nil?)
end
link&.content&.to_s
source&.content&.to_s
elsif URL_TYPES.include? meth.match(/^\w+(?==)/).to_s.to_sym
/^(?<type>\w+)/ =~ meth
link = @bibitem.link.detect do |l|
@bibitem.source ||= []
source = @bibitem.source.detect do |l|
l.type == type || (type == "uri" && l.type.nil?)
end
if link
link.content = args[0]
if source
source.content = args[0]
else
@bibitem.link << RelatonBib::TypedUri.new(type: type, content: args[0])
@bibitem.source << Relaton::Bib::Uri.new(type: type, content: args[0])
end
else
super
Expand Down
20 changes: 9 additions & 11 deletions lib/relaton/cli.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "fileutils"
require "thor"
require "thor/hollaback"
require_relative "cli/version"
Expand All @@ -19,6 +20,7 @@ class RelatonDb
# @return [Relaton::Db]
def db(dir)
if dir
FileUtils.mkdir_p File.dirname(DBCONF)
File.write DBCONF, dir, encoding: "UTF-8"
@db = Relaton::Db.new dir, nil
else
Expand All @@ -39,19 +41,14 @@ def dbpath

class << self
def version
require "relaton_bib"
require "relaton_iso_bib"
require "relaton/bib"
registry = Relaton::Registry.instance
puts "CLI => #{Relaton::Cli::VERSION}"
puts "relaton => #{Relaton::VERSION}"
puts "relaton-bib => #{RelatonBib::VERSION}"
puts "relaton-iso-bib => #{RelatonIsoBib::VERSION}"
puts "relaton => #{Gem.loaded_specs['relaton'].version}"
puts "relaton-bib => #{Gem.loaded_specs['relaton-bib'].version}"
registry.processors.each_key do |k|
require k.to_s
klass = registry.send(:camel_case, k.to_s)
klass = "#{klass}::VERSION"
version = Kernel.const_get(klass)
puts "#{k.to_s.sub('_', '-')} => #{version}"
name = k.to_s.sub("_", "-")
puts "#{name} => #{Gem.loaded_specs[name].version}"
end
end

Expand All @@ -76,10 +73,11 @@ def relaton(dir)
# @return [RelatonBib::BibliographicItem,
# RelatonIsoBib::IsoBibliongraphicItem]
def parse_xml(doc)
doc.remove_namespaces! if doc.respond_to?(:remove_namespaces!)
if (proc = Cli.processor(doc))
proc.from_xml(doc.to_s)
else
RelatonBib::XMLParser.from_xml(doc.to_s)
Relaton::Bib::Item.from_xml(doc.to_s) rescue nil
end
end

Expand Down
8 changes: 4 additions & 4 deletions lib/relaton/cli/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def convert(file) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
xml = Nokogiri::XML(File.read(file, encoding: "UTF-8"))
item = Relaton::Cli.parse_xml xml
result = if /yaml|yml/.match?(options[:format])
item.to_hash.to_yaml
item.to_yaml
else item.send "to_#{options[:format]}"
end
ext = case options[:format]
Expand Down Expand Up @@ -226,16 +226,16 @@ def fetch_document(code, options) # rubocop:disable Metrics/CyclomaticComplexity
return "No matching bibliographic entry found" unless doc

serialize doc, options[:format]
rescue RelatonBib::RequestError => e
rescue Relaton::RequestError => e
e.message
end

# @param doc [RelatonBib::BibliographicItem]
# @param doc [Relaton::Bib::ItemData]
# @param format [String]
# @return [String]
def serialize(doc, format)
case format
when "yaml", "yml" then doc.to_hash.to_yaml
when "yaml", "yml" then doc.to_yaml
when "bibtex" then doc.to_bibtex
else doc.to_xml bibdata: true
end
Expand Down
25 changes: 16 additions & 9 deletions lib/relaton/cli/full_text_search.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# require "forwardable"
require "set"

module Relaton
class FullTextSeatch
# extend Forwardable

# def_delegators :@collections, :<<
# Instance variables added by lutaml-model that form back-references
# (cycles) when a model is serialized. Skipping them keeps recursive
# traversal of a bibitem's object graph finite.
INTERNAL_IVARS = %i[
@using_default @lutaml_register @lutaml_parent @lutaml_root @register_records
].freeze

# @return Regexp
attr_reader :regex
Expand All @@ -19,8 +22,7 @@ def initialize(collection)
def search(text)
@regex = %{(.*?)(.{0,20})(#{text})(.{0,20})(.*)}
@matches = @collection.items.reduce({}) do |m, item|
# m + results(col, rgx)
res = result item
res = result item, Set.new
m[item.id] = res if res.any?
m
end
Expand Down Expand Up @@ -58,19 +60,24 @@ def print_attrs(attrs, indent)
end

# @param item [Relaton::Bibdata]
# @param seen [Set<Integer>] object_ids already visited on this path
# @return [Hash]
def result(item)
def result(item, seen)
if item.is_a? String
message $~ if item.match regex
elsif item.respond_to? :reduce
item.reduce([]) do |m, i|
res = result i
res = result i, seen
m << res if res && !res.empty?
m
end
else
return {} unless seen.add?(item.object_id)

item.instance_variables.reduce({}) do |m, var|
res = result item.instance_variable_get(var)
next m if INTERNAL_IVARS.include?(var)

res = result item.instance_variable_get(var), seen
m[var.to_s.tr(":@", "")] = res if res && !res.empty?
m
end
Expand Down
12 changes: 6 additions & 6 deletions lib/relaton/cli/relaton_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ def extract_and_write_to_files # rubocop:disable Metrics/AbcSize, Metrics/Method
if (bib = xml.at("//bibdata"))
bib = nokogiri_document(bib.to_xml)
elsif (rfc = xml.at("//rfc"))
require "relaton_ietf/bibxml_parser"
ietf = RelatonIetf::BibXMLParser.fetch_rfc rfc
require "relaton/ietf"
require "relaton/ietf/bibxml_parser"
ietf = Relaton::Ietf::BibXMLParser.parse_rfc rfc.to_xml
bib = nokogiri_document(ietf.to_xml(bibdata: true))
else
next
end

bib.remove_namespaces!
bib.root.add_namespace(nil, "xmlns")

bibdata = Relaton::Bibdata.from_xml(bib.root)
if bibdata
Expand All @@ -147,8 +147,9 @@ def concatenate_files
xml_files.flatten.reduce([]) do |mem, xml|
doc = nokogiri_document(xml[:content])
if (rfc = doc.at("/rfc"))
require "relaton_ietf/bibxml_parser"
ietf = RelatonIetf::BibXMLParser.fetch_rfc rfc
require "relaton/ietf"
require "relaton/ietf/bibxml_parser"
ietf = Relaton::Ietf::BibXMLParser.parse_rfc rfc.to_xml
d = nokogiri_document ietf.to_xml(bibdata: true)
mem << bibdata_instance(d, xml[:file])
elsif %w[bibitem bibdata].include? doc&.root&.name
Expand Down Expand Up @@ -231,7 +232,6 @@ def build_bibdata_relaton(bibdata, file)
# @return [Nokogiri::XML::Document]
def clean_nokogiri_document(document)
document.remove_namespaces!
document.root.add_namespace(nil, "xmlns")
nokogiri_document(document.to_xml)
end

Expand Down
26 changes: 22 additions & 4 deletions lib/relaton/cli/subcommand_collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,13 @@ def import(file) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
collfile = File.join directory, options[:collection]
coll = read_collection collfile
xml = Nokogiri::XML File.read(file, encoding: "UTF-8")
xml.remove_namespaces!
if xml.at "relaton-collection"
imported = import_collection(xml)
if coll
coll << Relaton::Bibcollection.from_xml(xml)
coll << imported
else
coll = Relaton::Bibcollection.from_xml(xml)
coll = imported
end
else
coll ||= Relaton::Bibcollection.new({})
Expand All @@ -169,6 +171,22 @@ def export(file)

private

# Parse a namespace-free collection XML document.
# Bibcollection.from_xml expects namespaced docs (via apply_namespace),
# so we use plain XPath on the namespace-stripped document instead.
def import_collection(xml)
title = xml.at("relaton-collection/title")&.text
author = xml.at_xpath(
"./relaton-collection/contributor[role/@type='author']"\
"/organization/name",
)&.text
items = xml.xpath("relaton-collection/relation").map do |rel|
el = rel.at("bibdata") || rel.at("bibitem")
Relaton::Bibdata.from_xml(el || rel)
end.compact
Relaton::Bibcollection.new(title: title, author: author, items: items)
end

# @return [String]
def directory
options.fetch :dir, File.join(Dir.home, ".relaton/collections")
Expand Down Expand Up @@ -231,9 +249,9 @@ def output_item(item)
# @param item [Relaton::Bibdata]
def puts_human_readable_item(item) # rubocop:disable Metrics/AbcSize
puts "Document identifier: #{item.docidentifier}"
puts "Title: #{item.title.first.title.content}"
puts "Title: #{item.title.first.content}"
puts "Status: #{item.status.stage}"
item.date.each { |d| puts "Date #{d.type}: #{d.on || d.from}" }
item.date.each { |d| puts "Date #{d.type}: #{d.at || d.from}" }
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/relaton/cli/util.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Relaton
module Cli
module Util
extend RelatonBib::Util
extend Relaton::Bib::Util
PROGNAME = "relaton-cli".freeze
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/relaton/cli/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Relaton
module Cli
VERSION = "1.20.6".freeze
VERSION = "2.1.2".freeze
end
end
13 changes: 7 additions & 6 deletions lib/relaton/cli/xml_to_html_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ def hash_to_liquid(hash)
elsif value.is_a?(Hash) then v = value["content"]
else v = value
end
when "docid"
v = if value.is_a?(Array)
value.detect { |did| did["id"] !~ /^(http|https):\/\// } ||
value.first
else value
end
when "docidentifier"
did = if value.is_a?(Array)
value.detect { |d| (d["id"] || d["content"]).to_s !~ /^(http|https):\/\// } ||
value.first
else value
end
v = did
else v = value
end
[key.to_s, empty2nil(v)]
Expand Down
Loading