From e8914196aaa607cf2f5a01ce4f6d0a51129f08d9 Mon Sep 17 00:00:00 2001 From: Finn Bacall Date: Wed, 29 Jan 2025 16:06:46 +0000 Subject: [PATCH] Fix crash when reading RO-Crates with a single value (instead of array) at `hasPart` --- lib/ro_crate/reader.rb | 4 +- test/fixtures/singleton-haspart/a_file | 1 + .../singleton-haspart/ro-crate-metadata.json | 57 +++++++++++++++++++ test/reader_test.rb | 8 +++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/singleton-haspart/a_file create mode 100644 test/fixtures/singleton-haspart/ro-crate-metadata.json diff --git a/lib/ro_crate/reader.rb b/lib/ro_crate/reader.rb index 0eb5ba0..06cbcef 100644 --- a/lib/ro_crate/reader.rb +++ b/lib/ro_crate/reader.rb @@ -204,7 +204,9 @@ def self.initialize_crate(entity_hash, source, crate_class: ROCrate::Crate, cont # @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id. # @return [Array] The extracted DataEntity objects. def self.extract_data_entities(crate, source, entity_hash) - (crate.raw_properties['hasPart'] || []).map do |ref| + parts = crate.raw_properties['hasPart'] || [] + parts = [parts] unless parts.is_a?(Array) + parts.map do |ref| entity_props = entity_hash.delete(ref['@id']) next unless entity_props entity_class = ROCrate::DataEntity.specialize(entity_props) diff --git a/test/fixtures/singleton-haspart/a_file b/test/fixtures/singleton-haspart/a_file new file mode 100644 index 0000000..190a180 --- /dev/null +++ b/test/fixtures/singleton-haspart/a_file @@ -0,0 +1 @@ +123 diff --git a/test/fixtures/singleton-haspart/ro-crate-metadata.json b/test/fixtures/singleton-haspart/ro-crate-metadata.json new file mode 100644 index 0000000..ba98ce6 --- /dev/null +++ b/test/fixtures/singleton-haspart/ro-crate-metadata.json @@ -0,0 +1,57 @@ +{ + "@context": [ + "https://w3id.org/ro/crate/1.1/context", + "https://w3id.org/ro/terms/workflow-run/context" + ], + "@graph": [ + { + "@id": "./", + "@type": "Dataset", + "datePublished": "2025-01-28T02:44:51.523Z", + "hasPart": { + "@id": "a_file" + }, + "dateCreated": "2025-01-28T02:45:05.906Z", + "dateModified": "2025-01-28T02:44:51.523Z", + "description": "Something", + "license": { + "@id": "https://spdx.org/licenses/MIT" + }, + "mainEntity": { + "@id": "a_file" + }, + "name": "An RO-Crate containing just a single item" + }, + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "conformsTo": [ + { + "@id": "https://w3id.org/ro/crate/1.1" + }, + { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" + } + ], + "about": { + "@id": "./" + } + }, + { + "@id": "a_file", + "@type": [ + "File", + "ComputationalWorkflow", + "SoftwareSourceCode" + ], + "contentSize": 4, + "description": "A workflow", + "encodingFormat": "text/plain", + "name": "a_file", + "programmingLanguage": { + "@id": "https://example.com/workflow_format" + } + } + ] +} + diff --git a/test/reader_test.rb b/test/reader_test.rb index b3753c4..05bd8f6 100644 --- a/test/reader_test.rb +++ b/test/reader_test.rb @@ -373,6 +373,14 @@ class ReaderTest < Test::Unit::TestCase assert_equal 'At the root', crate.name end + test 'reads crate with singleton hasPart' do + crate = ROCrate::Reader.read(fixture_file('singleton-haspart').path) + + data = crate.data_entities + assert_equal 1, data.length + assert_equal 'a_file', data.first.name + end + private def check_exception(exception_class)