lib/relaton/db.rb in relaton-0.2.5 vs lib/relaton/db.rb in relaton-0.2.6

- old
+ new

@@ -1,39 +1,40 @@ -require "pstore" +# require "pstore" require_relative "registry" +require_relative 'db_cache' module Relaton class RelatonError < StandardError; end class Db SUPPORTED_GEMS = %w[isobib ietfbib gbbib iecbib].freeze - # @param global_cache [String] filename of global DB - # @param local_cache [String] filename of local DB + # @param global_cache [String] directory of global DB + # @param local_cache [String] directory of local DB def initialize(global_cache, local_cache) register_gems + @registry = Relaton::Registry.instance @db = open_cache_biblio(global_cache) @local_db = open_cache_biblio(local_cache, global: false) @db_name = global_cache @local_db_name = local_cache - @registry = Relaton::Registry.instance end def register_gems - puts "[relaton] detecting backends:" + puts "[relaton] Info: detecting backends:" SUPPORTED_GEMS.each do |b| - puts b + # puts b begin require b rescue LoadError - puts "[relaton] backend #{b} not present" + puts "[relaton] Error: backend #{b} not present" end end end # The class of reference requested is determined by the prefix of the code: - # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib, + # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib, # @param code [String] the ISO standard Code to look up (e.g. "ISO 9000") # @param year [String] the year the standard was published (optional) # @param opts [Hash] options; restricted to :all_parts if all-parts reference is required # @return [String] Relaton XML serialisation of reference def fetch(code, year = nil, opts = {}) @@ -61,148 +62,159 @@ # @param key [String] # @return [Hash] def load_entry(key) unless @local_db.nil? - entry = @local_db.transaction { @local_db[key] } + entry = @local_db[key] return entry if entry end - @db.transaction { @db[key] } + @db[key] end # @param key [String] # @param value [Hash] # @option value [Date] "fetched" # @option value [IsoBibItem::IsoBibliographicItem] "bib" def save_entry(key, value) - @db.nil? or @db.transaction { @db[key] = value } - @local_db.nil? or @local_db.transaction { @local_db[key] = value } + @db.nil? || (@db[key] = value) + @local_db.nil? || (@local_db[key] = value) end # list all entries as a serialization + # @return [String] def to_xml db = @local_db || @db || return - db.transaction do - Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml.documents do - db.roots.reject { |key| key == :version }. - each { |key| db[key]&.fetch("bib")&.to_xml(xml, {}) } - end - end.to_xml - end + Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| + xml.documents do + xml.parent.add_child db.all.join(" ") + end + end.to_xml end private + # @param code [String] code of standard + # @return [Symbol] standard class name def standard_class(code) @registry.processors.each do |name, processor| return name if /^#{processor.prefix}/.match(code) || - processor.defaultprefix.match(code) + processor.defaultprefix.match(code) end allowed = @registry.processors.reduce([]) do |m, (_k, v)| m << v.prefix end warn "#{code} does not have a recognised prefix: #{allowed.join(', ')}" nil end # TODO: i18n + # Fofmat ID + # @param code [String] + # @param year [String] + # @param opts [Hash] + # @param stdClass [Symbol] + # @return [Array] def std_id(code, year, opts, stdclass) prefix, code = strip_id_wrapper(code, stdclass) ret = code ret += ":#{year}" if year ret += " (all parts)" if opts[:all_parts] ["#{prefix}(#{ret})", code] end + # Find prefix and clean code + # @param code [String] + # @param stdClass [Symbol] + # @return [Array] def strip_id_wrapper(code, stdclass) prefix = @registry.processors[stdclass].prefix code = code.sub(/^#{prefix}\((.+)\)$/, "\\1") [prefix, code] end - def bib_retval(entry) - entry["bib"] == "not_found" ? nil : entry["bib"] + def bib_retval(entry, stdclass) + entry =~ /^not_found/ ? nil : @registry.processors[stdclass].from_xml(entry) end # @param code [String] # @param year [String] # @param opts [Hash] # @param stdclass [Symbol] def check_bibliocache(code, year, opts, stdclass) id, searchcode = std_id(code, year, opts, stdclass) db = @local_db || @db altdb = @local_db && @db ? @db : nil - return bib_retval(new_bib_entry(searchcode, year, opts, stdclass)) if db.nil? - db.transaction do - db.delete(id) unless valid_bib_entry?(db[id], year) - if altdb - altdb.transaction do - db[id] ||= altdb[id] - db[id] ||= new_bib_entry(searchcode, year, opts, stdclass) - altdb[id] = db[id] if !valid_bib_entry?(altdb[id], year) - bib_retval(db[id]) - end - else - db[id] ||= new_bib_entry(searchcode, year, opts, stdclass) - bib_retval(db[id]) - end + return bib_retval(new_bib_entry(searchcode, year, opts, stdclass), stdclass) if db.nil? + + db.delete(id) unless db.valid_entry?(id, year) + if altdb + db[id] ||= altdb[id] + db[id] ||= new_bib_entry(searchcode, year, opts, stdclass) + altdb[id] = db[id] if !altdb.valid_entry?(id, year) + else + db[id] ||= new_bib_entry(searchcode, year, opts, stdclass) end + bib_retval(db[id], stdclass) end # hash uses => , because the hash is imported from JSON # @param code [String] # @param year [String] # @param opts [Hash] # @param stdclass [Symbol] # @return [Hash] def new_bib_entry(code, year, opts, stdclass) bib = @registry.processors[stdclass].get(code, year, opts) - bib = "not_found" if bib.nil? - { "fetched" => Date.today, "bib" => bib } + bib = "not_found #{Date.today}" if bib.nil? || bib.empty? + bib end # if cached reference is undated, expire it after 60 days # @param bib [Hash] # @param year [String] - def valid_bib_entry?(bib, year) - bib&.is_a?(Hash) && bib&.has_key?("bib") && bib&.has_key?("fetched") && - (year || Date.today - bib["fetched"] < 60) - end + # def valid_bib_entry?(bib, year) + # bib&.is_a?(Hash) && bib&.has_key?("bib") && bib&.has_key?("fetched") && + # (year || Date.today - bib["fetched"] < 60) + # end - # @param filename [String] DB filename + # @param dir [String] DB directory # @param global [TrueClass, FalseClass] # @return [PStore] - def open_cache_biblio(filename, global: true) - return nil if filename.nil? - db = PStore.new filename - if File.exist? filename + def open_cache_biblio(dir, global: true) + return nil if dir.nil? + db = DbCache.new dir + if File.exist? dir if global - unless check_cache_version(db) - File.delete filename + unless db.check_version? + FileUtils.rm_rf dir + '/.' warn "Global cache version is obsolete and cleared." end - set_cache_version db - elsif check_cache_version(db) then db + db.set_version + elsif db.check_version? then db else warn "Local cache version is obsolete." nil end - else - set_cache_version db + else db.set_version end end - def check_cache_version(cache_db) - cache_db.transaction { cache_db[:version] == VERSION } - end + # Check if version of the DB match to the gem version. + # @param cache_db [String] DB directory + # @return [TrueClass, FalseClass] + # def check_cache_version(cache_db) + # cache_db.transaction { cache_db[:version] == VERSION } + # end - def set_cache_version(cache_db) - unless File.exist? cache_db.path - cache_db.transaction { cache_db[:version] = VERSION } - end - cache_db - end + # Set version of the DB to the gem version. + # @param cache_db [String] DB directory + # @return [Pstore] + # def set_cache_version(cache_db) + # unless File.exist? cache_db.path + # cache_db.transaction { cache_db[:version] = VERSION } + # end + # cache_db + # end # @param enstry [String] entry in XML format # @return [IsoBibItem::IsoBibliographicItem] # def from_xml(entry) # IsoBibItem.from_xml entry # will be unmarshaller