relaton 0.2.5 → 0.2.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 +4 -4
- data/Gemfile.lock +19 -19
- data/lib/relaton/db.rb +75 -63
- data/lib/relaton/db_cache.rb +111 -0
- data/lib/relaton/processor.rb +4 -0
- data/lib/relaton/version.rb +1 -1
- data/relaton.gemspec +10 -9
- data/spec/relaton/relaton_spec.rb +31 -54
- data/spec/support/gb_t_20223_2006.xml +33 -0
- data/spec/support/iso_111111119115_1.xml +0 -0
- data/spec/support/iso_19115_1.xml +115 -0
- data/spec/support/iso_19115_2.xml +95 -0
- data/spec/support/list_entries.xml +197 -200
- data/spec/support/rfc_8341.xml +46 -0
- metadata +25 -22
- data/spec/support/gb_t_20223_2006 +0 -0
- data/spec/support/iso_111111119115_1 +0 -1
- data/spec/support/iso_19115_1 +0 -0
- data/spec/support/iso_19115_2 +0 -0
- data/spec/support/rfc_8341 +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b1872ecb2665f86758a05dd822d450d6daf37cf7865f0faf17878a494e1e17c
|
4
|
+
data.tar.gz: 464054cbb8b6d3475ff016ce8748bc88105cced709187751421cba7124943d0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62ed5b9d6a9002d748e9069651b7dda734d8e61b7f09aff340fabf563f4daef4c60b61131634dcad8f3d4faa174b64b873e3cb3e074279013807e8c89168eede
|
7
|
+
data.tar.gz: a389d31e90fd4a6b238a554998f9936e34324abfa41c21669212d3a20800cb538e37116a7b6d731a14a1920c46fdd366579aa2df736fbb65a52da30c0a644e56
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
relaton (0.2.
|
4
|
+
relaton (0.2.6)
|
5
5
|
algoliasearch
|
6
|
-
gbbib (~> 0.
|
7
|
-
iecbib (~> 0.
|
8
|
-
ietfbib (~> 0.4.
|
9
|
-
iso-bib-item (~> 0.
|
10
|
-
isobib (~> 0.
|
6
|
+
gbbib (~> 0.4.0)
|
7
|
+
iecbib (~> 0.2.0)
|
8
|
+
ietfbib (~> 0.4.2)
|
9
|
+
iso-bib-item (~> 0.4.1)
|
10
|
+
isobib (~> 0.4.0)
|
11
11
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
@@ -28,10 +28,10 @@ GEM
|
|
28
28
|
ffi (1.9.25)
|
29
29
|
formatador (0.2.5)
|
30
30
|
gb-agencies (0.0.3)
|
31
|
-
gbbib (0.
|
31
|
+
gbbib (0.4.0)
|
32
32
|
cnccs (~> 0.1.1)
|
33
33
|
gb-agencies (~> 0.0.1)
|
34
|
-
iso-bib-item (~> 0.
|
34
|
+
iso-bib-item (~> 0.4.1)
|
35
35
|
guard (2.14.2)
|
36
36
|
formatador (>= 0.2.4)
|
37
37
|
listen (>= 2.7, < 4.0)
|
@@ -47,19 +47,19 @@ GEM
|
|
47
47
|
guard-compat (~> 1.1)
|
48
48
|
rspec (>= 2.99.0, < 4.0)
|
49
49
|
httpclient (2.8.3)
|
50
|
-
iecbib (0.
|
50
|
+
iecbib (0.2.0)
|
51
51
|
addressable
|
52
|
-
iso-bib-item (~> 0.
|
53
|
-
ietfbib (0.4.
|
54
|
-
iso-bib-item (~> 0.
|
55
|
-
iso-bib-item (0.
|
52
|
+
iso-bib-item (~> 0.4.0)
|
53
|
+
ietfbib (0.4.2)
|
54
|
+
iso-bib-item (~> 0.4.1)
|
55
|
+
iso-bib-item (0.4.1)
|
56
56
|
isoics (~> 0.1.6)
|
57
57
|
nokogiri (~> 1.8.4)
|
58
58
|
ruby_deep_clone (~> 0.8.0)
|
59
|
-
isobib (0.
|
59
|
+
isobib (0.4.0)
|
60
60
|
algoliasearch
|
61
|
-
iecbib (~> 0.
|
62
|
-
iso-bib-item (~> 0.
|
61
|
+
iecbib (~> 0.2.0)
|
62
|
+
iso-bib-item (~> 0.4.0)
|
63
63
|
isoics (0.1.7)
|
64
64
|
jaro_winkler (1.5.1)
|
65
65
|
json (2.1.0)
|
@@ -71,7 +71,7 @@ GEM
|
|
71
71
|
method_source (0.9.0)
|
72
72
|
mini_portile2 (2.3.0)
|
73
73
|
nenv (0.3.0)
|
74
|
-
nokogiri (1.8.
|
74
|
+
nokogiri (1.8.5)
|
75
75
|
mini_portile2 (~> 2.3.0)
|
76
76
|
notiffany (0.1.1)
|
77
77
|
nenv (~> 0.1)
|
@@ -98,7 +98,7 @@ GEM
|
|
98
98
|
rspec-mocks (~> 3.8.0)
|
99
99
|
rspec-core (3.8.0)
|
100
100
|
rspec-support (~> 3.8.0)
|
101
|
-
rspec-expectations (3.8.
|
101
|
+
rspec-expectations (3.8.2)
|
102
102
|
diff-lcs (>= 1.2.0, < 2.0)
|
103
103
|
rspec-support (~> 3.8.0)
|
104
104
|
rspec-mocks (3.8.0)
|
@@ -144,4 +144,4 @@ DEPENDENCIES
|
|
144
144
|
timecop (~> 0.9)
|
145
145
|
|
146
146
|
BUNDLED WITH
|
147
|
-
1.16.
|
147
|
+
1.16.6
|
data/lib/relaton/db.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require "pstore"
|
1
|
+
# require "pstore"
|
2
2
|
require_relative "registry"
|
3
|
+
require_relative 'db_cache'
|
3
4
|
|
4
5
|
module Relaton
|
5
6
|
class RelatonError < StandardError; end
|
@@ -7,31 +8,31 @@ module Relaton
|
|
7
8
|
class Db
|
8
9
|
SUPPORTED_GEMS = %w[isobib ietfbib gbbib iecbib].freeze
|
9
10
|
|
10
|
-
# @param global_cache [String]
|
11
|
-
# @param local_cache [String]
|
11
|
+
# @param global_cache [String] directory of global DB
|
12
|
+
# @param local_cache [String] directory of local DB
|
12
13
|
def initialize(global_cache, local_cache)
|
13
14
|
register_gems
|
15
|
+
@registry = Relaton::Registry.instance
|
14
16
|
@db = open_cache_biblio(global_cache)
|
15
17
|
@local_db = open_cache_biblio(local_cache, global: false)
|
16
18
|
@db_name = global_cache
|
17
19
|
@local_db_name = local_cache
|
18
|
-
@registry = Relaton::Registry.instance
|
19
20
|
end
|
20
21
|
|
21
22
|
def register_gems
|
22
|
-
puts "[relaton] detecting backends:"
|
23
|
+
puts "[relaton] Info: detecting backends:"
|
23
24
|
SUPPORTED_GEMS.each do |b|
|
24
|
-
puts b
|
25
|
+
# puts b
|
25
26
|
begin
|
26
27
|
require b
|
27
28
|
rescue LoadError
|
28
|
-
puts "[relaton] backend #{b} not present"
|
29
|
+
puts "[relaton] Error: backend #{b} not present"
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
# The class of reference requested is determined by the prefix of the code:
|
34
|
-
# GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib,
|
35
|
+
# GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib,
|
35
36
|
# @param code [String] the ISO standard Code to look up (e.g. "ISO 9000")
|
36
37
|
# @param year [String] the year the standard was published (optional)
|
37
38
|
# @param opts [Hash] options; restricted to :all_parts if all-parts reference is required
|
@@ -63,10 +64,10 @@ module Relaton
|
|
63
64
|
# @return [Hash]
|
64
65
|
def load_entry(key)
|
65
66
|
unless @local_db.nil?
|
66
|
-
entry = @local_db
|
67
|
+
entry = @local_db[key]
|
67
68
|
return entry if entry
|
68
69
|
end
|
69
|
-
@db
|
70
|
+
@db[key]
|
70
71
|
end
|
71
72
|
|
72
73
|
# @param key [String]
|
@@ -74,29 +75,29 @@ module Relaton
|
|
74
75
|
# @option value [Date] "fetched"
|
75
76
|
# @option value [IsoBibItem::IsoBibliographicItem] "bib"
|
76
77
|
def save_entry(key, value)
|
77
|
-
@db.nil?
|
78
|
-
@local_db.nil?
|
78
|
+
@db.nil? || (@db[key] = value)
|
79
|
+
@local_db.nil? || (@local_db[key] = value)
|
79
80
|
end
|
80
81
|
|
81
82
|
# list all entries as a serialization
|
83
|
+
# @return [String]
|
82
84
|
def to_xml
|
83
85
|
db = @local_db || @db || return
|
84
|
-
|
85
|
-
|
86
|
-
xml.
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
end.to_xml
|
91
|
-
end
|
86
|
+
Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
87
|
+
xml.documents do
|
88
|
+
xml.parent.add_child db.all.join(" ")
|
89
|
+
end
|
90
|
+
end.to_xml
|
92
91
|
end
|
93
92
|
|
94
93
|
private
|
95
94
|
|
95
|
+
# @param code [String] code of standard
|
96
|
+
# @return [Symbol] standard class name
|
96
97
|
def standard_class(code)
|
97
98
|
@registry.processors.each do |name, processor|
|
98
99
|
return name if /^#{processor.prefix}/.match(code) ||
|
99
|
-
|
100
|
+
processor.defaultprefix.match(code)
|
100
101
|
end
|
101
102
|
allowed = @registry.processors.reduce([]) do |m, (_k, v)|
|
102
103
|
m << v.prefix
|
@@ -106,6 +107,12 @@ module Relaton
|
|
106
107
|
end
|
107
108
|
|
108
109
|
# TODO: i18n
|
110
|
+
# Fofmat ID
|
111
|
+
# @param code [String]
|
112
|
+
# @param year [String]
|
113
|
+
# @param opts [Hash]
|
114
|
+
# @param stdClass [Symbol]
|
115
|
+
# @return [Array]
|
109
116
|
def std_id(code, year, opts, stdclass)
|
110
117
|
prefix, code = strip_id_wrapper(code, stdclass)
|
111
118
|
ret = code
|
@@ -114,14 +121,18 @@ module Relaton
|
|
114
121
|
["#{prefix}(#{ret})", code]
|
115
122
|
end
|
116
123
|
|
124
|
+
# Find prefix and clean code
|
125
|
+
# @param code [String]
|
126
|
+
# @param stdClass [Symbol]
|
127
|
+
# @return [Array]
|
117
128
|
def strip_id_wrapper(code, stdclass)
|
118
129
|
prefix = @registry.processors[stdclass].prefix
|
119
130
|
code = code.sub(/^#{prefix}\((.+)\)$/, "\\1")
|
120
131
|
[prefix, code]
|
121
132
|
end
|
122
133
|
|
123
|
-
def bib_retval(entry)
|
124
|
-
entry
|
134
|
+
def bib_retval(entry, stdclass)
|
135
|
+
entry =~ /^not_found/ ? nil : @registry.processors[stdclass].from_xml(entry)
|
125
136
|
end
|
126
137
|
|
127
138
|
# @param code [String]
|
@@ -132,21 +143,17 @@ module Relaton
|
|
132
143
|
id, searchcode = std_id(code, year, opts, stdclass)
|
133
144
|
db = @local_db || @db
|
134
145
|
altdb = @local_db && @db ? @db : nil
|
135
|
-
return bib_retval(new_bib_entry(searchcode, year, opts, stdclass)) if db.nil?
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
else
|
146
|
-
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass)
|
147
|
-
bib_retval(db[id])
|
148
|
-
end
|
146
|
+
return bib_retval(new_bib_entry(searchcode, year, opts, stdclass), stdclass) if db.nil?
|
147
|
+
|
148
|
+
db.delete(id) unless db.valid_entry?(id, year)
|
149
|
+
if altdb
|
150
|
+
db[id] ||= altdb[id]
|
151
|
+
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass)
|
152
|
+
altdb[id] = db[id] if !altdb.valid_entry?(id, year)
|
153
|
+
else
|
154
|
+
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass)
|
149
155
|
end
|
156
|
+
bib_retval(db[id], stdclass)
|
150
157
|
end
|
151
158
|
|
152
159
|
# hash uses => , because the hash is imported from JSON
|
@@ -157,51 +164,56 @@ module Relaton
|
|
157
164
|
# @return [Hash]
|
158
165
|
def new_bib_entry(code, year, opts, stdclass)
|
159
166
|
bib = @registry.processors[stdclass].get(code, year, opts)
|
160
|
-
bib = "not_found" if bib.nil?
|
161
|
-
|
167
|
+
bib = "not_found #{Date.today}" if bib.nil? || bib.empty?
|
168
|
+
bib
|
162
169
|
end
|
163
170
|
|
164
171
|
# if cached reference is undated, expire it after 60 days
|
165
172
|
# @param bib [Hash]
|
166
173
|
# @param year [String]
|
167
|
-
def valid_bib_entry?(bib, year)
|
168
|
-
|
169
|
-
|
170
|
-
end
|
174
|
+
# def valid_bib_entry?(bib, year)
|
175
|
+
# bib&.is_a?(Hash) && bib&.has_key?("bib") && bib&.has_key?("fetched") &&
|
176
|
+
# (year || Date.today - bib["fetched"] < 60)
|
177
|
+
# end
|
171
178
|
|
172
|
-
# @param
|
179
|
+
# @param dir [String] DB directory
|
173
180
|
# @param global [TrueClass, FalseClass]
|
174
181
|
# @return [PStore]
|
175
|
-
def open_cache_biblio(
|
176
|
-
return nil if
|
177
|
-
db =
|
178
|
-
if File.exist?
|
182
|
+
def open_cache_biblio(dir, global: true)
|
183
|
+
return nil if dir.nil?
|
184
|
+
db = DbCache.new dir
|
185
|
+
if File.exist? dir
|
179
186
|
if global
|
180
|
-
unless
|
181
|
-
|
187
|
+
unless db.check_version?
|
188
|
+
FileUtils.rm_rf dir + '/.'
|
182
189
|
warn "Global cache version is obsolete and cleared."
|
183
190
|
end
|
184
|
-
|
185
|
-
elsif
|
191
|
+
db.set_version
|
192
|
+
elsif db.check_version? then db
|
186
193
|
else
|
187
194
|
warn "Local cache version is obsolete."
|
188
195
|
nil
|
189
196
|
end
|
190
|
-
else
|
191
|
-
set_cache_version db
|
197
|
+
else db.set_version
|
192
198
|
end
|
193
199
|
end
|
194
200
|
|
195
|
-
|
196
|
-
|
197
|
-
|
201
|
+
# Check if version of the DB match to the gem version.
|
202
|
+
# @param cache_db [String] DB directory
|
203
|
+
# @return [TrueClass, FalseClass]
|
204
|
+
# def check_cache_version(cache_db)
|
205
|
+
# cache_db.transaction { cache_db[:version] == VERSION }
|
206
|
+
# end
|
198
207
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
208
|
+
# Set version of the DB to the gem version.
|
209
|
+
# @param cache_db [String] DB directory
|
210
|
+
# @return [Pstore]
|
211
|
+
# def set_cache_version(cache_db)
|
212
|
+
# unless File.exist? cache_db.path
|
213
|
+
# cache_db.transaction { cache_db[:version] = VERSION }
|
214
|
+
# end
|
215
|
+
# cache_db
|
216
|
+
# end
|
205
217
|
|
206
218
|
# @param enstry [String] entry in XML format
|
207
219
|
# @return [IsoBibItem::IsoBibliographicItem]
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Relaton
|
2
|
+
class DbCache
|
3
|
+
# @return [String]
|
4
|
+
attr_reader :dir
|
5
|
+
|
6
|
+
# @param dir [String] DB directory
|
7
|
+
def initialize(dir)
|
8
|
+
@dir = dir
|
9
|
+
Dir.mkdir @dir unless Dir.exist? @dir
|
10
|
+
fiele_version = "#{@dir}/version"
|
11
|
+
File.write fiele_version, VERSION unless File.exist? fiele_version
|
12
|
+
end
|
13
|
+
|
14
|
+
# Save item
|
15
|
+
# @param key [String]
|
16
|
+
# @param value [String] Bibitem xml serialization
|
17
|
+
def []=(key, value)
|
18
|
+
return if value.nil?
|
19
|
+
prefix_dir = "#{@dir}/#{prefix(key)}"
|
20
|
+
Dir.mkdir prefix_dir unless Dir.exist? prefix_dir
|
21
|
+
File.write filename(key), value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Read item
|
25
|
+
# @param key [String]
|
26
|
+
# @return [String]
|
27
|
+
def [](key)
|
28
|
+
file = filename key
|
29
|
+
return unless File.exist? file
|
30
|
+
|
31
|
+
File.read(file)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return fetched date
|
35
|
+
# @param key [String]
|
36
|
+
# @return [String]
|
37
|
+
def fetched(key)
|
38
|
+
value = self[key]
|
39
|
+
return unless value
|
40
|
+
if value =~ /^not_found/
|
41
|
+
value.match(/\d{4}-\d{2}-\d{2}/).to_s
|
42
|
+
else
|
43
|
+
doc = Nokogiri::XML value
|
44
|
+
doc.at('/bibitem/fetched').text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns all items
|
49
|
+
# @return [Array<Hash>]
|
50
|
+
def all
|
51
|
+
Dir.glob("testcache/**/*.xml").sort.map do |f|
|
52
|
+
File.read(f)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Delete item
|
57
|
+
# @param key [String]
|
58
|
+
def delete(key)
|
59
|
+
file = filename key
|
60
|
+
File.delete file if File.exist? file
|
61
|
+
end
|
62
|
+
|
63
|
+
# Check if version of the DB match to the gem version.
|
64
|
+
# @return [TrueClass, FalseClass]
|
65
|
+
def check_version?
|
66
|
+
v = File.read @dir + "/version"
|
67
|
+
v == VERSION
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set version of the DB to the gem version.
|
71
|
+
# @return [Relaton::DbCache]
|
72
|
+
def set_version
|
73
|
+
File.write @dir + "/version", VERSION
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
# if cached reference is undated, expire it after 60 days
|
78
|
+
# @param key [String]
|
79
|
+
# @param year [String]
|
80
|
+
def valid_entry?(key, year)
|
81
|
+
datestr = fetched key
|
82
|
+
return false unless datestr
|
83
|
+
date = Date.parse datestr
|
84
|
+
year || Date.today - date < 60
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Return item's file name
|
90
|
+
# @param key [String]
|
91
|
+
# @return [String]
|
92
|
+
def filename(key)
|
93
|
+
prefcode = key.downcase.match /^(?<prefix>[^\(]+)\((?<code>[^\)]+)/
|
94
|
+
if prefcode
|
95
|
+
"#{@dir}/#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/]/, '_')}.xml"
|
96
|
+
else
|
97
|
+
"#{@dir}/#{key.gsub(/[-:\s]/, '_')}.xml"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Return item's subdir
|
102
|
+
# @param key [String]
|
103
|
+
# @return [String]
|
104
|
+
def prefix(key)
|
105
|
+
# @registry.processors.detect do |_n, p|
|
106
|
+
# /^#{p.prefix}/.match(key) || processor.defaultprefix.match(key)
|
107
|
+
# end[1].prefix.downcase
|
108
|
+
key.downcase.match(/^[^\(]+(?=\()/).to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|