lib/ro_crate/reader.rb in ro-crate-0.5.1 vs lib/ro_crate/reader.rb in ro-crate-0.5.2
- old
+ new
@@ -7,11 +7,10 @@
#
# @param source [String, ::File, Pathname, #read] The location of the zip or directory, or an IO-like object containing a zip.
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped (if its a Zip file).
# @return [Crate] The RO-Crate.
def self.read(source, target_dir: Dir.mktmpdir)
- raise "Not a directory!" unless ::File.directory?(target_dir)
begin
is_dir = ::File.directory?(source)
rescue TypeError
is_dir = false
end
@@ -80,10 +79,12 @@
#
# @param source [String, ::File, Pathname, #read] The location of the zip file, or an IO-like object.
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped.
# @return [Crate] The RO-Crate.
def self.read_zip(source, target_dir: Dir.mktmpdir)
+ raise ROCrate::ReadException, "Target is not a directory!" unless ::File.directory?(target_dir)
+
unzip_to(source, target_dir)
# Traverse the unzipped directory to try and find the crate's root
root_dir = detect_root_directory(target_dir)
@@ -94,25 +95,30 @@
# Reads an RO-Crate from a directory.
#
# @param source [String, ::File, Pathname] The location of the directory.
# @return [Crate] The RO-Crate.
def self.read_directory(source)
- raise "Not a directory!" unless ::File.directory?(source)
+ raise ROCrate::ReadException, "Source is not a directory!" unless ::File.directory?(source)
source = ::File.expand_path(source)
metadata_file = Dir.entries(source).detect { |entry| entry == ROCrate::Metadata::IDENTIFIER ||
entry == ROCrate::Metadata::IDENTIFIER_1_0 }
if metadata_file
metadata_json = ::File.read(::File.join(source, metadata_file))
- metadata = JSON.parse(metadata_json)
+ begin
+ metadata = JSON.parse(metadata_json)
+ rescue JSON::ParserError => e
+ raise ROCrate::ReadException.new("Error parsing metadata", e)
+ end
+
entities = entities_from_metadata(metadata)
context = metadata['@context']
build_crate(entities, source, context: context)
else
- raise 'No metadata found!'
+ raise ROCrate::ReadException, "No metadata found!"
end
end
##
# Extracts all the entities from the @graph of the RO-Crate Metadata.
@@ -129,18 +135,18 @@
entities[entity['@id']] = entity
end
# Do some normalization...
entities[ROCrate::Metadata::IDENTIFIER] = extract_metadata_entity(entities)
- raise "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
+ raise ROCrate::ReadException, "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
entities[ROCrate::Preview::IDENTIFIER] = extract_preview_entity(entities)
entities[ROCrate::Crate::IDENTIFIER] = extract_root_entity(entities)
- raise "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
+ raise ROCrate::ReadException, "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
entities
else
- raise "No @graph found in metadata!"
+ raise ROCrate::ReadException, "No @graph found in metadata!"
end
end
##
# Create and populate crate from the given set of entities.
@@ -196,11 +202,11 @@
# @param crate [Crate] The RO-Crate being read.
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
# @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
# @return [Array<ROCrate::File, ROCrate::Directory>] The extracted DataEntity objects.
def self.extract_data_entities(crate, source, entity_hash)
- crate.raw_properties['hasPart'].map do |ref|
+ (crate.raw_properties['hasPart'] || []).map do |ref|
entity_props = entity_hash.delete(ref['@id'])
next unless entity_props
entity_class = ROCrate::DataEntity.specialize(entity_props)
entity = create_data_entity(crate, entity_class, source, entity_props)
next if entity.nil?
@@ -232,25 +238,25 @@
# @param entity_props [Hash] A Hash containing the entity's properties, including its @id.
# @return [ROCrate::File, ROCrate::Directory, nil] The DataEntity object,
# or nil if it referenced a local file that wasn't found.
def self.create_data_entity(crate, entity_class, source, entity_props)
id = entity_props.delete('@id')
+ raise ROCrate::ReadException, "Data Entity missing '@id': #{entity_props.inspect}" unless id
decoded_id = URI.decode_www_form_component(id)
path = nil
uri = URI(id) rescue nil
if uri&.absolute?
path = uri
decoded_id = nil
- else
+ elsif !id.start_with?('#')
[id, decoded_id].each do |i|
fullpath = ::File.join(source, i)
path = Pathname.new(fullpath) if ::File.exist?(fullpath)
end
- # unless path
- # warn "Missing file/directory: #{id}, skipping..."
- # return nil
- # end
+ if path.nil?
+ raise ROCrate::ReadException, "Local Data Entity not found in crate: #{id}"
+ end
end
entity_class.new(crate, path, decoded_id, entity_props)
end
@@ -288,10 +294,10 @@
# https://www.researchobject.org/ro-crate/1.1/root-data-entity.html#finding-the-root-data-entity
# @return [Hash{String => Hash}] A Hash containing (hopefully) one value, the root entity's properties,
# mapped by its @id.
def self.extract_root_entity(entities)
root_id = entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')
- raise "Metadata entity does not reference any root entity" unless root_id
+ raise ROCrate::ReadException, "Metadata entity does not reference any root entity" unless root_id
entities.delete(root_id)
end
##
# Finds an RO-Crate's root directory (where `ro-crate-metdata.json` is located) within a given directory.