ro-crate 0.4.1 → 0.4.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/.ruby-version +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +11 -7
- data/lib/ro_crate/json_ld_hash.rb +1 -1
- data/lib/ro_crate/model/contextual_entity.rb +1 -1
- data/lib/ro_crate/model/crate.rb +54 -15
- data/lib/ro_crate/model/data_entity.rb +1 -1
- data/lib/ro_crate/model/directory.rb +39 -11
- data/lib/ro_crate/model/entity.rb +3 -3
- data/lib/ro_crate/model/entry.rb +1 -1
- data/lib/ro_crate/model/file.rb +5 -3
- data/lib/ro_crate/model/remote_entry.rb +1 -1
- data/lib/ro_crate/reader.rb +18 -15
- data/lib/ro_crate/ro-crate-preview.html.erb +3 -3
- data/lib/ro_crate/writer.rb +3 -3
- data/ro_crate.gemspec +2 -2
- data/test/crate_test.rb +95 -0
- data/test/fixtures/directory.zip +0 -0
- data/test/fixtures/directory/.dir/test.txt +1 -0
- data/test/fixtures/directory/.dotfile +1 -0
- data/test/fixtures/directory_crate/ro-crate-metadata.jsonld +7 -0
- data/test/fixtures/directory_crate/ro-crate-preview.html +66 -0
- data/test/fixtures/sparse_directory_crate.zip +0 -0
- data/test/fixtures/sparse_directory_crate/fish/data/binary.jpg +0 -0
- data/test/fixtures/sparse_directory_crate/fish/data/info.txt +1 -0
- data/test/fixtures/sparse_directory_crate/fish/data/nested.txt +1 -0
- data/test/fixtures/sparse_directory_crate/fish/info.txt +1 -0
- data/test/fixtures/sparse_directory_crate/fish/root.txt +1 -0
- data/test/fixtures/sparse_directory_crate/listed_file.txt +1 -0
- data/test/fixtures/sparse_directory_crate/ro-crate-metadata.jsonld +32 -0
- data/test/fixtures/sparse_directory_crate/ro-crate-preview.html +66 -0
- data/test/fixtures/sparse_directory_crate/unlisted_file.txt +1 -0
- data/test/reader_test.rb +36 -2
- data/test/writer_test.rb +33 -0
- metadata +16 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4880110308b68d8bc35333b1fc8a8396ea30e36069f92e059b8c57ec3567d33e
         | 
| 4 | 
            +
              data.tar.gz: 77a17a0436f2dea14254a3501f9db349eed5460851d94ab4e87adb7be83e1b38
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 711a45d7aaa63f8a5a7bba78e433d82875311472d6f4abfd6d388dd8565a7707036152c81de4059fd92da5b7851925caf9d808f39d115752e68eaddbdc85bac1
         | 
| 7 | 
            +
              data.tar.gz: ce14efaf63e7224adc79cdb11d27bdec933be290ccf60196014cb7ce9380136451265a8f814e1ca7b70286fc32852024d429334bbaab18208d31095cd619dc9e
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            ruby-2. | 
| 1 | 
            +
            ruby-2.6.6
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,9 +1,9 @@ | |
| 1 1 | 
             
            # ro-crate-ruby
         | 
| 2 2 |  | 
| 3 | 
            -
            This is a WIP gem for creating, manipulating and reading RO  | 
| 3 | 
            +
            This is a WIP gem for creating, manipulating and reading RO-Crates (conforming to version 1.1 of the specification).
         | 
| 4 4 |  | 
| 5 | 
            -
            * RO | 
| 6 | 
            -
            * RO | 
| 5 | 
            +
            * RO-Crate - https://researchobject.github.io/ro-crate/
         | 
| 6 | 
            +
            * RO-Crate spec (1.1) - https://researchobject.github.io/ro-crate/1.1/
         | 
| 7 7 |  | 
| 8 8 | 
             
            ## Installation
         | 
| 9 9 |  | 
| @@ -31,13 +31,17 @@ crate = ROCrate::Crate.new | |
| 31 31 | 
             
            crate.add_file(File.open('Gemfile')) # Using IO-like objects
         | 
| 32 32 | 
             
            crate.add_file('README.md') # or paths
         | 
| 33 33 |  | 
| 34 | 
            +
            # Quickly add everything from a directory into the crate
         | 
| 35 | 
            +
            crate = ROCrate::Crate.new
         | 
| 36 | 
            +
            crate.add_all('workspace/secret_project/dataset123')
         | 
| 37 | 
            +
             | 
| 34 38 | 
             
            # Write to a zip file
         | 
| 35 39 | 
             
            ROCrate::Writer.new(crate).write_zip(File.new('ro_crate.zip', 'w'))
         | 
| 36 40 |  | 
| 37 41 | 
             
            # Write to a directory
         | 
| 38 42 | 
             
            ROCrate::Writer.new(crate).write('./ro_crate_stuff')
         | 
| 39 43 |  | 
| 40 | 
            -
            # Read an RO | 
| 44 | 
            +
            # Read an RO-Crate
         | 
| 41 45 | 
             
            crate = ROCrate::Reader.read('./an_ro_crate_directory')
         | 
| 42 46 |  | 
| 43 47 | 
             
            # Make some changes
         | 
| @@ -55,9 +59,9 @@ ext_file = crate.add_external_file('https://example.com/my_file.txt') | |
| 55 59 | 
             
            ROCrate::Writer.new(crate).write('./an_ro_crate_directory')
         | 
| 56 60 | 
             
            ```
         | 
| 57 61 |  | 
| 58 | 
            -
            ### RO | 
| 59 | 
            -
            A simple HTML preview page is generated when an RO | 
| 60 | 
            -
            metadata. This preview is written to `ro-crate-preview.html` at the root of the RO | 
| 62 | 
            +
            ### RO-Crate Preview
         | 
| 63 | 
            +
            A simple HTML preview page is generated when an RO-Crate is written, containing a list of the crate's contents and some
         | 
| 64 | 
            +
            metadata. This preview is written to `ro-crate-preview.html` at the root of the RO-Crate.
         | 
| 61 65 |  | 
| 62 66 | 
             
            The default template can be seen here [here](lib/ro_crate/ro-crate-preview.html.erb).
         | 
| 63 67 |  | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A wrapper class for Hash that adds methods to dereference Entities within an RO | 
| 3 | 
            +
              # A wrapper class for Hash that adds methods to dereference Entities within an RO-Crate.
         | 
| 4 4 | 
             
              class JSONLDHash < ::Hash
         | 
| 5 5 | 
             
                def initialize(graph, content = {})
         | 
| 6 6 | 
             
                  @graph = graph
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A class to represent a "Contextual Entity" within an RO | 
| 3 | 
            +
              # A class to represent a "Contextual Entity" within an RO-Crate.
         | 
| 4 4 | 
             
              # Contextual Entities are used to describe and provide context to the Data Entities within the crate.
         | 
| 5 5 | 
             
              class ContextualEntity < Entity
         | 
| 6 6 | 
             
                def self.format_id(id)
         | 
    
        data/lib/ro_crate/model/crate.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A Ruby abstraction of an RO | 
| 3 | 
            +
              # A Ruby abstraction of an RO-Crate.
         | 
| 4 4 | 
             
              class Crate < Directory
         | 
| 5 5 | 
             
                IDENTIFIER = './'.freeze
         | 
| 6 6 | 
             
                attr_reader :data_entities
         | 
| @@ -13,7 +13,7 @@ module ROCrate | |
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                ##
         | 
| 16 | 
            -
                # Initialize an empty RO | 
| 16 | 
            +
                # Initialize an empty RO-Crate.
         | 
| 17 17 | 
             
                def initialize(id = IDENTIFIER, properties = {})
         | 
| 18 18 | 
             
                  @data_entities = []
         | 
| 19 19 | 
             
                  @contextual_entities = []
         | 
| @@ -24,7 +24,7 @@ module ROCrate | |
| 24 24 | 
             
                # Create a new file and add it to the crate.
         | 
| 25 25 | 
             
                #
         | 
| 26 26 | 
             
                # @param source [String, Pathname, ::File, #read, nil] The source on the disk where this file will be read.
         | 
| 27 | 
            -
                # @param crate_path [String] The relative path within the RO  | 
| 27 | 
            +
                # @param crate_path [String] The relative path within the RO-Crate where this file will be written.
         | 
| 28 28 | 
             
                # @param entity_class [Class] The class to use to instantiate the Entity,
         | 
| 29 29 | 
             
                #   useful if you have created a subclass of ROCrate::File that you want to use. (defaults to ROCrate::File).
         | 
| 30 30 | 
             
                # @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this file.
         | 
| @@ -51,7 +51,7 @@ module ROCrate | |
| 51 51 | 
             
                # Create a new directory and add it to the crate.
         | 
| 52 52 | 
             
                #
         | 
| 53 53 | 
             
                # @param source_directory [String, Pathname, ::File, #read, nil] The source directory that will be included in the crate.
         | 
| 54 | 
            -
                # @param crate_path [String] The relative path within the RO  | 
| 54 | 
            +
                # @param crate_path [String] The relative path within the RO-Crate where this directory will be written.
         | 
| 55 55 | 
             
                # @param entity_class [Class] The class to use to instantiate the Entity,
         | 
| 56 56 | 
             
                #   useful if you have created a subclass of ROCrate::Directory that you want to use. (defaults to ROCrate::Directory).
         | 
| 57 57 | 
             
                # @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this directory.
         | 
| @@ -61,6 +61,35 @@ module ROCrate | |
| 61 61 | 
             
                  entity_class.new(self, source_directory, crate_path, properties).tap { |e| add_data_entity(e) }
         | 
| 62 62 | 
             
                end
         | 
| 63 63 |  | 
| 64 | 
            +
                ##
         | 
| 65 | 
            +
                # Recursively add the contents of the given source directory at the root of the crate.
         | 
| 66 | 
            +
                # Useful for quickly RO-Crate-ifying a directory.
         | 
| 67 | 
            +
                # Creates data entities for each file/directory discovered (excluding the top level directory itself) if `create_entities` is true.
         | 
| 68 | 
            +
                #
         | 
| 69 | 
            +
                # @param source_directory [String, Pathname, ::File,] The source directory that will be included in the crate.
         | 
| 70 | 
            +
                # @param create_entities [Boolean] Whether to create data entities for the added content, or just include them anonymously.
         | 
| 71 | 
            +
                # @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
         | 
| 72 | 
            +
                #
         | 
| 73 | 
            +
                # @return [Array<DataEntity>] Any entities that were created from the directory contents. Will be empty if `create_entities` was false.
         | 
| 74 | 
            +
                def add_all(source_directory, create_entities = true, include_hidden: false)
         | 
| 75 | 
            +
                  added = []
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  if create_entities
         | 
| 78 | 
            +
                    list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
         | 
| 79 | 
            +
                      source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
         | 
| 80 | 
            +
                      if source_path.directory?
         | 
| 81 | 
            +
                        added << add_directory(source_path, rel_path)
         | 
| 82 | 
            +
                      else
         | 
| 83 | 
            +
                        added << add_file(source_path, rel_path)
         | 
| 84 | 
            +
                      end
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                  else
         | 
| 87 | 
            +
                    populate_entries(Pathname.new(::File.expand_path(source_directory)), include_hidden: include_hidden)
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  added
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 64 93 | 
             
                ##
         | 
| 65 94 | 
             
                # Create a new ROCrate::Person and add it to the crate
         | 
| 66 95 | 
             
                #
         | 
| @@ -119,7 +148,7 @@ module ROCrate | |
| 119 148 | 
             
                end
         | 
| 120 149 |  | 
| 121 150 | 
             
                ##
         | 
| 122 | 
            -
                # The RO  | 
| 151 | 
            +
                # The RO-Crate metadata file
         | 
| 123 152 | 
             
                #
         | 
| 124 153 | 
             
                # @return [Metadata]
         | 
| 125 154 | 
             
                def metadata
         | 
| @@ -127,7 +156,7 @@ module ROCrate | |
| 127 156 | 
             
                end
         | 
| 128 157 |  | 
| 129 158 | 
             
                ##
         | 
| 130 | 
            -
                # The RO  | 
| 159 | 
            +
                # The RO-Crate preview file
         | 
| 131 160 | 
             
                #
         | 
| 132 161 | 
             
                # @return [Preview]
         | 
| 133 162 | 
             
                def preview
         | 
| @@ -143,7 +172,7 @@ module ROCrate | |
| 143 172 | 
             
                end
         | 
| 144 173 |  | 
| 145 174 | 
             
                ##
         | 
| 146 | 
            -
                # Entities for the metadata file and crate itself, which should be present in all RO | 
| 175 | 
            +
                # Entities for the metadata file and crate itself, which should be present in all RO-Crates.
         | 
| 147 176 | 
             
                #
         | 
| 148 177 | 
             
                # @return [Array<Entity>]
         | 
| 149 178 | 
             
                def default_entities
         | 
| @@ -186,18 +215,22 @@ module ROCrate | |
| 186 215 | 
             
                  entity.class.new(crate, entity.id, entity.raw_properties)
         | 
| 187 216 | 
             
                end
         | 
| 188 217 |  | 
| 218 | 
            +
                alias_method :own_entries, :entries
         | 
| 189 219 | 
             
                ##
         | 
| 190 | 
            -
                #  | 
| 191 | 
            -
                # and the value is an Entry where the source data can be read.
         | 
| 220 | 
            +
                # # The RO-Crate's "payload" of the crate - a map of all the files/directories contained in the RO-Crate, where the
         | 
| 221 | 
            +
                # key is the destination path within the crate and the value is an Entry where the source data can be read.
         | 
| 192 222 | 
             
                #
         | 
| 193 223 | 
             
                # @return [Hash{String => Entry}>]
         | 
| 194 224 | 
             
                def entries
         | 
| 195 | 
            -
                  entries  | 
| 196 | 
            -
             | 
| 197 | 
            -
                   | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 225 | 
            +
                  # Gather a map of entries, starting from the crate itself, then any directory data entities, then finally any
         | 
| 226 | 
            +
                  # file data entities. This ensures in the case of a conflict, the more "specific" data entities take priority.
         | 
| 227 | 
            +
                  entries = own_entries
         | 
| 228 | 
            +
                  non_self_entities = default_entities.reject { |e| e == self }
         | 
| 229 | 
            +
                  sorted_entities = (non_self_entities | data_entities).sort_by { |e| e.is_a?(ROCrate::Directory) ? 0 : 1 }
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                  sorted_entities.each do |entity|
         | 
| 232 | 
            +
                    entity.entries.each do |path, entry|
         | 
| 233 | 
            +
                      entries[path] = entry
         | 
| 201 234 | 
             
                    end
         | 
| 202 235 | 
             
                  end
         | 
| 203 236 |  | 
| @@ -207,5 +240,11 @@ module ROCrate | |
| 207 240 | 
             
                def get_binding
         | 
| 208 241 | 
             
                  binding
         | 
| 209 242 | 
             
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                private
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                def full_entry_path(relative_path)
         | 
| 247 | 
            +
                  relative_path
         | 
| 248 | 
            +
                end
         | 
| 210 249 | 
             
              end
         | 
| 211 250 | 
             
            end
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A class to represent a "Data Entity" within an RO | 
| 3 | 
            +
              # A class to represent a "Data Entity" within an RO-Crate.
         | 
| 4 4 | 
             
              # Data Entities are the actual physical files and directories within the Crate.
         | 
| 5 5 | 
             
              class DataEntity < Entity
         | 
| 6 6 | 
             
                def self.format_id(id)
         | 
| @@ -12,37 +12,34 @@ module ROCrate | |
| 12 12 | 
             
                # Create a new Directory. PLEASE NOTE, the new directory will not be added to the crate. To do this, call
         | 
| 13 13 | 
             
                # Crate#add_data_entity, or just use Crate#add_directory.
         | 
| 14 14 | 
             
                #
         | 
| 15 | 
            -
                # @param crate [Crate] The RO  | 
| 15 | 
            +
                # @param crate [Crate] The RO-Crate that owns this directory.
         | 
| 16 16 | 
             
                # @param source_directory [String, Pathname, ::File, nil] The source directory that will be included in the crate.
         | 
| 17 | 
            -
                # @param crate_path [String] The relative path within the RO  | 
| 17 | 
            +
                # @param crate_path [String] The relative path within the RO-Crate where this directory will be written.
         | 
| 18 18 | 
             
                # @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this directory.
         | 
| 19 19 | 
             
                def initialize(crate, source_directory = nil, crate_path = nil, properties = {})
         | 
| 20 20 | 
             
                  @directory_entries = {}
         | 
| 21 21 |  | 
| 22 22 | 
             
                  if source_directory
         | 
| 23 | 
            -
                    raise 'Not a directory' unless ::File.directory?(source_directory)
         | 
| 24 23 | 
             
                    source_directory = Pathname.new(::File.expand_path(source_directory))
         | 
| 24 | 
            +
                    @entry = Entry.new(source_directory)
         | 
| 25 | 
            +
                    populate_entries(source_directory)
         | 
| 25 26 | 
             
                    crate_path = source_directory.basename.to_s if crate_path.nil?
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                    Dir.chdir(source_directory) { Dir.glob('**/*') }.each do |rel_path|
         | 
| 28 | 
            -
                      source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
         | 
| 29 | 
            -
                      @directory_entries[rel_path] = Entry.new(source_path)
         | 
| 30 | 
            -
                    end
         | 
| 31 27 | 
             
                  end
         | 
| 32 28 |  | 
| 33 29 | 
             
                  super(crate, crate_path, properties)
         | 
| 34 30 | 
             
                end
         | 
| 35 31 |  | 
| 36 32 | 
             
                ##
         | 
| 37 | 
            -
                #  | 
| 38 | 
            -
                # and the value is an Entry where the source data can be read.
         | 
| 33 | 
            +
                # The "payload" of this directory - a map of all the files/directories, where the key is the destination path
         | 
| 34 | 
            +
                # within the crate and the value is an Entry where the source data can be read.
         | 
| 39 35 | 
             
                #
         | 
| 40 36 | 
             
                # @return [Hash{String => Entry}>]
         | 
| 41 37 | 
             
                def entries
         | 
| 42 38 | 
             
                  entries = {}
         | 
| 39 | 
            +
                  entries[filepath.chomp('/')] = @entry if @entry
         | 
| 43 40 |  | 
| 44 41 | 
             
                  @directory_entries.each do |rel_path, entry|
         | 
| 45 | 
            -
                    entries[ | 
| 42 | 
            +
                    entries[full_entry_path(rel_path)] = entry
         | 
| 46 43 | 
             
                  end
         | 
| 47 44 |  | 
| 48 45 | 
             
                  entries
         | 
| @@ -50,6 +47,37 @@ module ROCrate | |
| 50 47 |  | 
| 51 48 | 
             
                private
         | 
| 52 49 |  | 
| 50 | 
            +
                ##
         | 
| 51 | 
            +
                # Populate this directory with files/directories from a given source directory on disk.
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
                # @param source_directory [Pathname] The source directory to populate from.
         | 
| 54 | 
            +
                # @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
         | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                # @return [Hash{String => Entry}>] The files/directories that were populated.
         | 
| 57 | 
            +
                #   The key is the relative path of the file/directory, and the value is an Entry object where data can be read etc.
         | 
| 58 | 
            +
                def populate_entries(source_directory, include_hidden: false)
         | 
| 59 | 
            +
                  raise 'Not a directory' unless ::File.directory?(source_directory)
         | 
| 60 | 
            +
                  @directory_entries = {}
         | 
| 61 | 
            +
                  list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
         | 
| 62 | 
            +
                    source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
         | 
| 63 | 
            +
                    @directory_entries[rel_path] = Entry.new(source_path)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  @directory_entries
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def full_entry_path(relative_path)
         | 
| 70 | 
            +
                  ::File.join(filepath, relative_path)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def list_all_files(source_directory, include_hidden: false)
         | 
| 74 | 
            +
                  args = ['**/*']
         | 
| 75 | 
            +
                  args << ::File::FNM_DOTMATCH if include_hidden
         | 
| 76 | 
            +
                  Dir.chdir(source_directory) { Dir.glob(*args) }.reject do |path|
         | 
| 77 | 
            +
                    path == '.' || path == '..' || path.end_with?('/.')
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 53 81 | 
             
                def default_properties
         | 
| 54 82 | 
             
                  super.merge(
         | 
| 55 83 | 
             
                    '@id' => "#{SecureRandom.uuid}/",
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A generic "Entity" within an RO | 
| 4 | 
            -
              # RO | 
| 3 | 
            +
              # A generic "Entity" within an RO-Crate. It has an identifier and a set of properties, and will be referenced in the
         | 
| 4 | 
            +
              # RO-Crate Metadata's @graph.
         | 
| 5 5 | 
             
              class Entity
         | 
| 6 6 | 
             
                attr_reader :crate
         | 
| 7 7 | 
             
                attr_reader :properties
         | 
| @@ -60,7 +60,7 @@ module ROCrate | |
| 60 60 | 
             
                ##
         | 
| 61 61 | 
             
                # Automatically replace an Entity or Array of Entities with a reference or Array of references. Also associates
         | 
| 62 62 | 
             
                # the Entity/Entities with the current crate. This is useful for maintaining the flat @graph of entities that the
         | 
| 63 | 
            -
                # RO  | 
| 63 | 
            +
                # RO-Crate metadata file requires.
         | 
| 64 64 | 
             
                #
         | 
| 65 65 | 
             
                # @param value [Entity, Array<Entity>, Object] A value that may be reference or array of references.
         | 
| 66 66 | 
             
                # @return [Hash, Array<Hash>, Object] Return a reference, Array of references, or just the object itself if
         | 
    
        data/lib/ro_crate/model/entry.rb
    CHANGED
    
    
    
        data/lib/ro_crate/model/file.rb
    CHANGED
    
    | @@ -8,9 +8,9 @@ module ROCrate | |
| 8 8 | 
             
                # Create a new ROCrate::File. PLEASE NOTE, the new file will not be added to the crate. To do this, call
         | 
| 9 9 | 
             
                # Crate#add_data_entity, or just use Crate#add_file.
         | 
| 10 10 | 
             
                #
         | 
| 11 | 
            -
                # @param crate [Crate] The RO  | 
| 11 | 
            +
                # @param crate [Crate] The RO-Crate that owns this file.
         | 
| 12 12 | 
             
                # @param source [String, Pathname, ::File, #read, URI, nil] The source on the disk (or on the internet if a URI) where this file will be read.
         | 
| 13 | 
            -
                # @param crate_path [String] The relative path within the RO  | 
| 13 | 
            +
                # @param crate_path [String] The relative path within the RO-Crate where this file will be written.
         | 
| 14 14 | 
             
                # @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this file.
         | 
| 15 15 | 
             
                def initialize(crate, source, crate_path = nil, properties = {})
         | 
| 16 16 | 
             
                  if crate_path.is_a?(Hash) && properties.empty?
         | 
| @@ -52,7 +52,9 @@ module ROCrate | |
| 52 52 | 
             
                end
         | 
| 53 53 |  | 
| 54 54 | 
             
                ##
         | 
| 55 | 
            -
                # A map  | 
| 55 | 
            +
                # The "payload". A map with a single key and value, of the relative filepath within the crate, to the source on disk
         | 
| 56 | 
            +
                # where the actual bytes of the file can be read. Blank if remote.
         | 
| 57 | 
            +
                #
         | 
| 56 58 | 
             
                # (for compatibility with Directory#entries)
         | 
| 57 59 | 
             
                #
         | 
| 58 60 | 
             
                # @return [Hash{String => Entry}>] The key is the location within the crate, and the value is an Entry.
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A class to represent a reference within an RO | 
| 3 | 
            +
              # A class to represent a reference within an RO-Crate, to a remote file held on the internet somewhere.
         | 
| 4 4 | 
             
              # It handles the actual reading/writing of bytes.
         | 
| 5 5 | 
             
              class RemoteEntry
         | 
| 6 6 | 
             
                attr_reader :uri
         | 
    
        data/lib/ro_crate/reader.rb
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A class to handle reading of RO | 
| 3 | 
            +
              # A class to handle reading of RO-Crates from Zip files or directories.
         | 
| 4 4 | 
             
              class Reader
         | 
| 5 5 | 
             
                ##
         | 
| 6 | 
            -
                # Reads an RO | 
| 6 | 
            +
                # Reads an RO-Crate from a directory of zip file.
         | 
| 7 7 | 
             
                #
         | 
| 8 8 | 
             
                # @param source [String, ::File, Pathname] The source location for the crate.
         | 
| 9 9 | 
             
                # @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped (if its a Zip file).
         | 
| 10 | 
            -
                # @return [Crate] The RO | 
| 10 | 
            +
                # @return [Crate] The RO-Crate.
         | 
| 11 11 | 
             
                def self.read(source, target_dir: Dir.mktmpdir)
         | 
| 12 12 | 
             
                  raise "Not a directory!" unless ::File.directory?(target_dir)
         | 
| 13 13 | 
             
                  if ::File.directory?(source)
         | 
| @@ -37,12 +37,12 @@ module ROCrate | |
| 37 37 | 
             
                end
         | 
| 38 38 |  | 
| 39 39 | 
             
                ##
         | 
| 40 | 
            -
                # Reads an RO | 
| 40 | 
            +
                # Reads an RO-Crate from a zip file. It first extracts the Zip file to a temporary directory, and then calls
         | 
| 41 41 | 
             
                # #read_directory.
         | 
| 42 42 | 
             
                #
         | 
| 43 43 | 
             
                # @param source [String, ::File, Pathname] The location of the zip file.
         | 
| 44 44 | 
             
                # @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped.
         | 
| 45 | 
            -
                # @return [Crate] The RO | 
| 45 | 
            +
                # @return [Crate] The RO-Crate.
         | 
| 46 46 | 
             
                def self.read_zip(source, target_dir: Dir.mktmpdir)
         | 
| 47 47 | 
             
                  unzip_to(source, target_dir)
         | 
| 48 48 |  | 
| @@ -50,10 +50,10 @@ module ROCrate | |
| 50 50 | 
             
                end
         | 
| 51 51 |  | 
| 52 52 | 
             
                ##
         | 
| 53 | 
            -
                # Reads an RO | 
| 53 | 
            +
                # Reads an RO-Crate from a directory.
         | 
| 54 54 | 
             
                #
         | 
| 55 55 | 
             
                # @param source [String, ::File, Pathname] The location of the directory.
         | 
| 56 | 
            -
                # @return [Crate] The RO | 
| 56 | 
            +
                # @return [Crate] The RO-Crate.
         | 
| 57 57 | 
             
                def self.read_directory(source)
         | 
| 58 58 | 
             
                  source = ::File.expand_path(source)
         | 
| 59 59 | 
             
                  metadata_file = Dir.entries(source).detect { |entry| entry == ROCrate::Metadata::IDENTIFIER ||
         | 
| @@ -68,7 +68,7 @@ module ROCrate | |
| 68 68 | 
             
                end
         | 
| 69 69 |  | 
| 70 70 | 
             
                ##
         | 
| 71 | 
            -
                # Extracts all the entities from the @graph of the RO | 
| 71 | 
            +
                # Extracts all the entities from the @graph of the RO-Crate Metadata.
         | 
| 72 72 | 
             
                #
         | 
| 73 73 | 
             
                # @param metadata_json [String] A string containing the metadata JSON.
         | 
| 74 74 | 
             
                # @return [Hash{String => Hash}] A Hash of all the entities, mapped by their @id.
         | 
| @@ -99,12 +99,15 @@ module ROCrate | |
| 99 99 | 
             
                # Create a crate from the given set of entities.
         | 
| 100 100 | 
             
                #
         | 
| 101 101 | 
             
                # @param entity_hash [Hash{String => Hash}] A Hash containing all the entities in the @graph, mapped by their @id.
         | 
| 102 | 
            -
                # @param source [String, ::File, Pathname] The location of the RO | 
| 103 | 
            -
                # @return [Crate] The RO | 
| 102 | 
            +
                # @param source [String, ::File, Pathname] The location of the RO-Crate being read.
         | 
| 103 | 
            +
                # @return [Crate] The RO-Crate.
         | 
| 104 104 | 
             
                def self.build_crate(entity_hash, source)
         | 
| 105 105 | 
             
                  ROCrate::Crate.new.tap do |crate|
         | 
| 106 106 | 
             
                    crate.properties = entity_hash.delete(ROCrate::Crate::IDENTIFIER)
         | 
| 107 107 | 
             
                    crate.metadata.properties = entity_hash.delete(ROCrate::Metadata::IDENTIFIER)
         | 
| 108 | 
            +
                    preview_properties = entity_hash.delete(ROCrate::Preview::IDENTIFIER)
         | 
| 109 | 
            +
                    crate.preview.properties = preview_properties if preview_properties
         | 
| 110 | 
            +
                    crate.add_all(source, false)
         | 
| 108 111 | 
             
                    extract_data_entities(crate, source, entity_hash).each do |entity|
         | 
| 109 112 | 
             
                      crate.add_data_entity(entity)
         | 
| 110 113 | 
             
                    end
         | 
| @@ -118,8 +121,8 @@ module ROCrate | |
| 118 121 | 
             
                ##
         | 
| 119 122 | 
             
                # Discover data entities from the `hasPart` property of a crate, and create DataEntity objects for them.
         | 
| 120 123 | 
             
                # Entities are looked up in the given `entity_hash` (and then removed from it).
         | 
| 121 | 
            -
                # @param crate [Crate] The RO | 
| 122 | 
            -
                # @param source [String, ::File, Pathname] The location of the RO | 
| 124 | 
            +
                # @param crate [Crate] The RO-Crate being read.
         | 
| 125 | 
            +
                # @param source [String, ::File, Pathname] The location of the RO-Crate being read.
         | 
| 123 126 | 
             
                # @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
         | 
| 124 127 | 
             
                # @return [Array<ROCrate::File, ROCrate::Directory>] The extracted DataEntity objects.
         | 
| 125 128 | 
             
                def self.extract_data_entities(crate, source, entity_hash)
         | 
| @@ -135,7 +138,7 @@ module ROCrate | |
| 135 138 |  | 
| 136 139 | 
             
                ##
         | 
| 137 140 | 
             
                # Create appropriately specialized ContextualEntity objects from the given hash of entities and their properties.
         | 
| 138 | 
            -
                # @param crate [Crate] The RO | 
| 141 | 
            +
                # @param crate [Crate] The RO-Crate being read.
         | 
| 139 142 | 
             
                # @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
         | 
| 140 143 | 
             
                # @return [Array<ContextualEntity>] The extracted ContextualEntity objects.
         | 
| 141 144 | 
             
                def self.extract_contextual_entities(crate, entity_hash)
         | 
| @@ -152,8 +155,8 @@ module ROCrate | |
| 152 155 |  | 
| 153 156 | 
             
                ##
         | 
| 154 157 | 
             
                # Create a DataEntity of the given class.
         | 
| 155 | 
            -
                # @param crate [Crate] The RO | 
| 156 | 
            -
                # @param source [String, ::File, Pathname] The location of the RO | 
| 158 | 
            +
                # @param crate [Crate] The RO-Crate being read.
         | 
| 159 | 
            +
                # @param source [String, ::File, Pathname] The location of the RO-Crate being read.
         | 
| 157 160 | 
             
                # @param entity_props [Hash] A Hash containing the entity's properties, including its @id.
         | 
| 158 161 | 
             
                # @return [ROCrate::File, ROCrate::Directory, nil] The DataEntity object,
         | 
| 159 162 | 
             
                #          or nil if it referenced a local file that wasn't found.
         | 
| @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            <!DOCTYPE html>
         | 
| 2 2 | 
             
            <html>
         | 
| 3 3 | 
             
            <head>
         | 
| 4 | 
            -
              <title><%= name || "New RO | 
| 4 | 
            +
              <title><%= name || "New RO-Crate" %></title>
         | 
| 5 5 | 
             
              <script type="application/ld+json"><%= metadata.generate %></script>
         | 
| 6 6 | 
             
              <meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
         | 
| 7 | 
            -
              <meta name="keywords" content="RO | 
| 7 | 
            +
              <meta name="keywords" content="RO-Crate">
         | 
| 8 8 | 
             
            </head>
         | 
| 9 9 | 
             
            <body>
         | 
| 10 | 
            -
              <h1><%= name || "New RO | 
| 10 | 
            +
              <h1><%= name || "New RO-Crate" %></h1>
         | 
| 11 11 | 
             
              <% if url %>
         | 
| 12 12 | 
             
                <a href="<%= url %>" target="_blank"><%= url %></a>
         | 
| 13 13 | 
             
              <% end %>
         | 
    
        data/lib/ro_crate/writer.rb
    CHANGED
    
    | @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            module ROCrate
         | 
| 2 2 | 
             
              ##
         | 
| 3 | 
            -
              # A class to handle writing of RO | 
| 3 | 
            +
              # A class to handle writing of RO-Crates to Zip files or directories.
         | 
| 4 4 | 
             
              class Writer
         | 
| 5 5 | 
             
                ##
         | 
| 6 6 | 
             
                # Initialize a new Writer for the given Crate.
         | 
| 7 | 
            -
                # @param crate [Crate] The RO | 
| 7 | 
            +
                # @param crate [Crate] The RO-Crate to be written.
         | 
| 8 8 | 
             
                def initialize(crate)
         | 
| 9 9 | 
             
                  @crate = crate
         | 
| 10 10 | 
             
                end
         | 
| @@ -35,7 +35,7 @@ module ROCrate | |
| 35 35 | 
             
                ##
         | 
| 36 36 | 
             
                # Write the crate to a zip file.
         | 
| 37 37 | 
             
                #
         | 
| 38 | 
            -
                # @param destination [String, ::File] The destination where to write the RO | 
| 38 | 
            +
                # @param destination [String, ::File] The destination where to write the RO-Crate zip.
         | 
| 39 39 | 
             
                def write_zip(destination)
         | 
| 40 40 | 
             
                  Zip::File.open(destination, Zip::File::CREATE) do |zip|
         | 
| 41 41 | 
             
                    @crate.entries.each do |path, entry|
         | 
    
        data/ro_crate.gemspec
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name        = 'ro-crate'
         | 
| 3 | 
            -
              s.version     = '0.4. | 
| 4 | 
            -
              s.summary     = 'Create, manipulate, read RO | 
| 3 | 
            +
              s.version     = '0.4.6'
         | 
| 4 | 
            +
              s.summary     = 'Create, manipulate, read RO-Crates.'
         | 
| 5 5 | 
             
              s.authors     = ['Finn Bacall']
         | 
| 6 6 | 
             
              s.email       = 'finn.bacall@manchester.ac.uk'
         | 
| 7 7 | 
             
              s.files       = `git ls-files`.split("\n")
         | 
    
        data/test/crate_test.rb
    CHANGED
    
    | @@ -198,4 +198,99 @@ class CrateTest < Test::Unit::TestCase | |
| 198 198 | 
             
                assert_equal file, new_crate.get('some/file.txt')
         | 
| 199 199 | 
             
                assert_equal file, new_crate.get('http://mycoolwebsite.golf/ro_crate/some/file.txt')
         | 
| 200 200 | 
             
              end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
              test 'can add an entire directory tree as data entities' do
         | 
| 203 | 
            +
                crate = ROCrate::Crate.new
         | 
| 204 | 
            +
                entities = crate.add_all(fixture_file('directory').path, include_hidden: true)
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                paths = crate.entries.keys
         | 
| 207 | 
            +
                assert_equal 11, paths.length
         | 
| 208 | 
            +
                assert_includes paths, 'data'
         | 
| 209 | 
            +
                assert_includes paths, 'root.txt'
         | 
| 210 | 
            +
                assert_includes paths, 'info.txt'
         | 
| 211 | 
            +
                assert_includes paths, 'data/binary.jpg'
         | 
| 212 | 
            +
                assert_includes paths, 'data/info.txt'
         | 
| 213 | 
            +
                assert_includes paths, 'data/nested.txt'
         | 
| 214 | 
            +
                assert_includes paths, '.dotfile'
         | 
| 215 | 
            +
                assert_includes paths, '.dir'
         | 
| 216 | 
            +
                assert_includes paths, '.dir/test.txt'
         | 
| 217 | 
            +
                assert_includes paths, 'ro-crate-metadata.json'
         | 
| 218 | 
            +
                assert_includes paths, 'ro-crate-preview.html'
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                assert_equal 9, entities.length
         | 
| 221 | 
            +
                assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
         | 
| 222 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
         | 
| 223 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
         | 
| 224 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
         | 
| 225 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
         | 
| 226 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
         | 
| 227 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('.dotfile').class.name
         | 
| 228 | 
            +
                assert_equal 'ROCrate::Directory', crate.dereference('.dir/').class.name
         | 
| 229 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('.dir/test.txt').class.name
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                assert_equal "5678\n", crate.dereference('data/info.txt').source.read
         | 
| 232 | 
            +
                assert_equal "Am I included?\n", crate.dereference('.dotfile').source.read
         | 
| 233 | 
            +
              end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
              test 'can create an RO-Crate using content from a given directory' do
         | 
| 236 | 
            +
                crate = ROCrate::Crate.new
         | 
| 237 | 
            +
                entities = crate.add_all(fixture_file('directory').path, false, include_hidden: true)
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                assert_empty entities
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                paths = crate.entries.keys
         | 
| 242 | 
            +
                assert_equal 11, paths.length
         | 
| 243 | 
            +
                assert_includes paths, 'data'
         | 
| 244 | 
            +
                assert_includes paths, 'root.txt'
         | 
| 245 | 
            +
                assert_includes paths, 'info.txt'
         | 
| 246 | 
            +
                assert_includes paths, 'data/binary.jpg'
         | 
| 247 | 
            +
                assert_includes paths, 'data/info.txt'
         | 
| 248 | 
            +
                assert_includes paths, 'data/nested.txt'
         | 
| 249 | 
            +
                assert_includes paths, '.dotfile'
         | 
| 250 | 
            +
                assert_includes paths, '.dir'
         | 
| 251 | 
            +
                assert_includes paths, '.dir/test.txt'
         | 
| 252 | 
            +
                assert_includes paths, 'ro-crate-metadata.json'
         | 
| 253 | 
            +
                assert_includes paths, 'ro-crate-preview.html'
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                # Should not create any data entities
         | 
| 256 | 
            +
                assert_nil crate.dereference('data/')
         | 
| 257 | 
            +
                assert_nil crate.dereference('root.txt')
         | 
| 258 | 
            +
                assert_nil crate.dereference('info.txt')
         | 
| 259 | 
            +
                assert_nil crate.dereference('data/binary.jpg')
         | 
| 260 | 
            +
                assert_nil crate.dereference('data/info.txt')
         | 
| 261 | 
            +
                assert_nil crate.dereference('data/nested.txt')
         | 
| 262 | 
            +
                assert_nil crate.dereference('.dotfile')
         | 
| 263 | 
            +
              end
         | 
| 264 | 
            +
             | 
| 265 | 
            +
              test 'can create an RO-Crate using content from a given directory, excluding hidden files' do
         | 
| 266 | 
            +
                crate = ROCrate::Crate.new
         | 
| 267 | 
            +
                entities = crate.add_all(fixture_file('directory').path)
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                paths = crate.entries.keys
         | 
| 270 | 
            +
                assert_equal 8, paths.length
         | 
| 271 | 
            +
                assert_includes paths, 'data'
         | 
| 272 | 
            +
                assert_includes paths, 'root.txt'
         | 
| 273 | 
            +
                assert_includes paths, 'info.txt'
         | 
| 274 | 
            +
                assert_includes paths, 'data/binary.jpg'
         | 
| 275 | 
            +
                assert_includes paths, 'data/info.txt'
         | 
| 276 | 
            +
                assert_includes paths, 'data/nested.txt'
         | 
| 277 | 
            +
                assert_not_includes paths, '.dotfile'
         | 
| 278 | 
            +
                assert_not_includes paths, '.dir'
         | 
| 279 | 
            +
                assert_not_includes paths, '.dir/test.txt'
         | 
| 280 | 
            +
                assert_includes paths, 'ro-crate-metadata.json'
         | 
| 281 | 
            +
                assert_includes paths, 'ro-crate-preview.html'
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                assert_equal 6, entities.length
         | 
| 284 | 
            +
                assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
         | 
| 285 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
         | 
| 286 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
         | 
| 287 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
         | 
| 288 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
         | 
| 289 | 
            +
                assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
         | 
| 290 | 
            +
                assert_nil crate.dereference('.dotfile')
         | 
| 291 | 
            +
                assert_nil crate.dereference('.dir/')
         | 
| 292 | 
            +
                assert_nil crate.dereference('.dir/test.txt')
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                assert_equal "5678\n", crate.dereference('data/info.txt').source.read
         | 
| 295 | 
            +
              end
         | 
| 201 296 | 
             
            end
         | 
    
        data/test/fixtures/directory.zip
    CHANGED
    
    | Binary file | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            123
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            Am I included?
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html>
         | 
| 3 | 
            +
            <head>
         | 
| 4 | 
            +
              <title>New RO-Crate</title>
         | 
| 5 | 
            +
              <script type="application/ld+json">{
         | 
| 6 | 
            +
              "@context": "https://w3id.org/ro/crate/1.1/context",
         | 
| 7 | 
            +
              "@graph": [
         | 
| 8 | 
            +
                {
         | 
| 9 | 
            +
                  "@id": "ro-crate-metadata.jsonld",
         | 
| 10 | 
            +
                  "@type": "CreativeWork",
         | 
| 11 | 
            +
                  "about": {
         | 
| 12 | 
            +
                    "@id": "./"
         | 
| 13 | 
            +
                  }
         | 
| 14 | 
            +
                },
         | 
| 15 | 
            +
                {
         | 
| 16 | 
            +
                  "@id": "ro-crate-preview.html",
         | 
| 17 | 
            +
                  "@type": "CreativeWork",
         | 
| 18 | 
            +
                  "about": {
         | 
| 19 | 
            +
                    "@id": "./"
         | 
| 20 | 
            +
                  }
         | 
| 21 | 
            +
                },
         | 
| 22 | 
            +
                {
         | 
| 23 | 
            +
                  "@id": "./",
         | 
| 24 | 
            +
                  "@type": "Dataset",
         | 
| 25 | 
            +
                  "hasPart": [
         | 
| 26 | 
            +
                    {
         | 
| 27 | 
            +
                      "@id": "fish/"
         | 
| 28 | 
            +
                    }
         | 
| 29 | 
            +
                  ]
         | 
| 30 | 
            +
                },
         | 
| 31 | 
            +
                {
         | 
| 32 | 
            +
                  "@id": "fish/",
         | 
| 33 | 
            +
                  "@type": "Dataset"
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
              ]
         | 
| 36 | 
            +
            }</script>
         | 
| 37 | 
            +
              <meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
         | 
| 38 | 
            +
              <meta name="keywords" content="RO-Crate">
         | 
| 39 | 
            +
            </head>
         | 
| 40 | 
            +
            <body>
         | 
| 41 | 
            +
              <h1>New RO-Crate</h1>
         | 
| 42 | 
            +
              
         | 
| 43 | 
            +
              <p>
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
              </p>
         | 
| 46 | 
            +
              <dl>
         | 
| 47 | 
            +
                
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
              </dl>
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              <h2>Contents</h2>
         | 
| 54 | 
            +
              <ul>
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                  <li id="__data_entity_fish/">
         | 
| 57 | 
            +
                    
         | 
| 58 | 
            +
                      <strong>fish/</strong>
         | 
| 59 | 
            +
                    
         | 
| 60 | 
            +
                    
         | 
| 61 | 
            +
                    
         | 
| 62 | 
            +
                  </li>
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
              </ul>
         | 
| 65 | 
            +
            </body>
         | 
| 66 | 
            +
            </html>
         | 
| Binary file | 
| Binary file | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            5678
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            I'm nested
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            1234
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            I'm at the root
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            123
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "@context": "https://w3id.org/ro/crate/1.0/context",
         | 
| 3 | 
            +
              "@graph": [
         | 
| 4 | 
            +
                {
         | 
| 5 | 
            +
                  "@id": "ro-crate-metadata.jsonld",
         | 
| 6 | 
            +
                  "@type": "CreativeWork",
         | 
| 7 | 
            +
                  "about": {
         | 
| 8 | 
            +
                    "@id": "./"
         | 
| 9 | 
            +
                  }
         | 
| 10 | 
            +
                },
         | 
| 11 | 
            +
                {
         | 
| 12 | 
            +
                  "@id": "ro-crate-preview.html",
         | 
| 13 | 
            +
                  "@type": "CreativeWork",
         | 
| 14 | 
            +
                  "about": {
         | 
| 15 | 
            +
                    "@id": "./"
         | 
| 16 | 
            +
                  }
         | 
| 17 | 
            +
                },
         | 
| 18 | 
            +
                {
         | 
| 19 | 
            +
                  "@id": "./",
         | 
| 20 | 
            +
                  "@type": "Dataset",
         | 
| 21 | 
            +
                  "hasPart": [
         | 
| 22 | 
            +
                    {
         | 
| 23 | 
            +
                      "@id": "listed_file.txt"
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
                  ]
         | 
| 26 | 
            +
                },
         | 
| 27 | 
            +
                {
         | 
| 28 | 
            +
                  "@id": "listed_file.txt",
         | 
| 29 | 
            +
                  "@type": "File"
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
              ]
         | 
| 32 | 
            +
            }
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html>
         | 
| 3 | 
            +
            <head>
         | 
| 4 | 
            +
              <title>New RO-Crate</title>
         | 
| 5 | 
            +
              <script type="application/ld+json">{
         | 
| 6 | 
            +
              "@context": "https://w3id.org/ro/crate/1.1/context",
         | 
| 7 | 
            +
              "@graph": [
         | 
| 8 | 
            +
                {
         | 
| 9 | 
            +
                  "@id": "ro-crate-metadata.jsonld",
         | 
| 10 | 
            +
                  "@type": "CreativeWork",
         | 
| 11 | 
            +
                  "about": {
         | 
| 12 | 
            +
                    "@id": "./"
         | 
| 13 | 
            +
                  }
         | 
| 14 | 
            +
                },
         | 
| 15 | 
            +
                {
         | 
| 16 | 
            +
                  "@id": "ro-crate-preview.html",
         | 
| 17 | 
            +
                  "@type": "CreativeWork",
         | 
| 18 | 
            +
                  "about": {
         | 
| 19 | 
            +
                    "@id": "./"
         | 
| 20 | 
            +
                  }
         | 
| 21 | 
            +
                },
         | 
| 22 | 
            +
                {
         | 
| 23 | 
            +
                  "@id": "./",
         | 
| 24 | 
            +
                  "@type": "Dataset",
         | 
| 25 | 
            +
                  "hasPart": [
         | 
| 26 | 
            +
                    {
         | 
| 27 | 
            +
                      "@id": "fish/"
         | 
| 28 | 
            +
                    }
         | 
| 29 | 
            +
                  ]
         | 
| 30 | 
            +
                },
         | 
| 31 | 
            +
                {
         | 
| 32 | 
            +
                  "@id": "fish/",
         | 
| 33 | 
            +
                  "@type": "Dataset"
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
              ]
         | 
| 36 | 
            +
            }</script>
         | 
| 37 | 
            +
              <meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
         | 
| 38 | 
            +
              <meta name="keywords" content="RO-Crate">
         | 
| 39 | 
            +
            </head>
         | 
| 40 | 
            +
            <body>
         | 
| 41 | 
            +
              <h1>New RO-Crate</h1>
         | 
| 42 | 
            +
              
         | 
| 43 | 
            +
              <p>
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
              </p>
         | 
| 46 | 
            +
              <dl>
         | 
| 47 | 
            +
                
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
              </dl>
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              <h2>Contents</h2>
         | 
| 54 | 
            +
              <ul>
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                  <li id="__data_entity_fish/">
         | 
| 57 | 
            +
                    
         | 
| 58 | 
            +
                      <strong>fish/</strong>
         | 
| 59 | 
            +
                    
         | 
| 60 | 
            +
                    
         | 
| 61 | 
            +
                    
         | 
| 62 | 
            +
                  </li>
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
              </ul>
         | 
| 65 | 
            +
            </body>
         | 
| 66 | 
            +
            </html>
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            456
         | 
    
        data/test/reader_test.rb
    CHANGED
    
    | @@ -109,11 +109,13 @@ class ReaderTest < Test::Unit::TestCase | |
| 109 109 | 
             
              test 'reading from directory with directories' do
         | 
| 110 110 | 
             
                crate = ROCrate::Reader.read_directory(fixture_file('directory_crate').path)
         | 
| 111 111 |  | 
| 112 | 
            +
                assert crate.entries.values.all? { |e| e.is_a?(ROCrate::Entry) }
         | 
| 112 113 | 
             
                assert crate.entries['fish/info.txt']
         | 
| 113 114 | 
             
                assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
         | 
| 114 | 
            -
                 | 
| 115 | 
            +
                refute crate.entries['fish/root.txt'].directory?
         | 
| 116 | 
            +
                assert crate.entries['fish/data'].directory?
         | 
| 115 117 | 
             
                assert crate.entries['fish/data/info.txt']
         | 
| 116 | 
            -
                 | 
| 118 | 
            +
                refute crate.entries['fish/data/nested.txt'].remote?
         | 
| 117 119 | 
             
                assert crate.entries['fish/data/binary.jpg']
         | 
| 118 120 | 
             
                assert_equal ['./', 'fish/', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
         | 
| 119 121 | 
             
              end
         | 
| @@ -161,4 +163,36 @@ class ReaderTest < Test::Unit::TestCase | |
| 161 163 | 
             
                assert_equal 'http://example.com/external_ref.txt', ext_file.id
         | 
| 162 164 | 
             
                assert_equal 'file contents', ext_file.source.read
         | 
| 163 165 | 
             
              end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
              test 'reading from directory with unlisted files' do
         | 
| 168 | 
            +
                crate = ROCrate::Reader.read_directory(fixture_file('sparse_directory_crate').path)
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                assert_equal 11, crate.entries.count
         | 
| 171 | 
            +
                assert crate.entries['listed_file.txt']
         | 
| 172 | 
            +
                assert crate.entries['unlisted_file.txt']
         | 
| 173 | 
            +
                assert crate.entries['fish']
         | 
| 174 | 
            +
                assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
         | 
| 175 | 
            +
                refute crate.entries['fish/root.txt'].directory?
         | 
| 176 | 
            +
                assert crate.entries['fish/data'].directory?
         | 
| 177 | 
            +
                assert crate.entries['fish/data/info.txt']
         | 
| 178 | 
            +
                refute crate.entries['fish/data/nested.txt'].remote?
         | 
| 179 | 
            +
                assert crate.entries['fish/data/binary.jpg']
         | 
| 180 | 
            +
                assert_equal ['./', 'listed_file.txt', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
         | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
              test 'reading from a zip with unlisted files' do
         | 
| 184 | 
            +
                crate = ROCrate::Reader.read_zip(fixture_file('sparse_directory_crate.zip').path)
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                assert_equal 11, crate.entries.count
         | 
| 187 | 
            +
                assert crate.entries['listed_file.txt']
         | 
| 188 | 
            +
                assert crate.entries['unlisted_file.txt']
         | 
| 189 | 
            +
                assert crate.entries['fish']
         | 
| 190 | 
            +
                assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
         | 
| 191 | 
            +
                refute crate.entries['fish/root.txt'].directory?
         | 
| 192 | 
            +
                assert crate.entries['fish/data'].directory?
         | 
| 193 | 
            +
                assert crate.entries['fish/data/info.txt']
         | 
| 194 | 
            +
                refute crate.entries['fish/data/nested.txt'].remote?
         | 
| 195 | 
            +
                assert crate.entries['fish/data/binary.jpg']
         | 
| 196 | 
            +
                assert_equal ['./', 'listed_file.txt', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
         | 
| 197 | 
            +
              end
         | 
| 164 198 | 
             
            end
         | 
    
        data/test/writer_test.rb
    CHANGED
    
    | @@ -99,4 +99,37 @@ class WriterTest < Test::Unit::TestCase | |
| 99 99 | 
             
                  end
         | 
| 100 100 | 
             
                end
         | 
| 101 101 | 
             
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              test 'should write out same contents that it was created with' do
         | 
| 104 | 
            +
                crate = ROCrate::Crate.new
         | 
| 105 | 
            +
                crate.add_all(fixture_file('directory').path, false)
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                Dir.mktmpdir do |dir|
         | 
| 108 | 
            +
                  ROCrate::Writer.new(crate).write(dir)
         | 
| 109 | 
            +
                  assert ::File.exist?(::File.join(dir, ROCrate::Metadata::IDENTIFIER))
         | 
| 110 | 
            +
                  assert ::File.exist?(::File.join(dir, ROCrate::Preview::IDENTIFIER))
         | 
| 111 | 
            +
                  assert_equal 5, ::File.size(::File.join(dir, 'info.txt'))
         | 
| 112 | 
            +
                  assert_equal 2529, ::File.size(::File.join(dir, 'data', 'binary.jpg'))
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              test 'reading and writing out a directory crate produces an identical crate' do
         | 
| 117 | 
            +
                fixture = fixture_file('sparse_directory_crate').path
         | 
| 118 | 
            +
                Dir.mktmpdir do |dir|
         | 
| 119 | 
            +
                  dir = ::File.join(dir, 'new_directory')
         | 
| 120 | 
            +
                  crate = ROCrate::Reader.read(fixture)
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  ROCrate::Writer.new(crate).write(dir)
         | 
| 123 | 
            +
                  expected_files = Dir.chdir(fixture) { Dir.glob('**/*') }
         | 
| 124 | 
            +
                  actual_files =  Dir.chdir(dir) { Dir.glob('**/*') }
         | 
| 125 | 
            +
                  assert_equal expected_files, actual_files
         | 
| 126 | 
            +
                  expected_files.each do |file|
         | 
| 127 | 
            +
                    next if file == 'ro-crate-metadata.jsonld' # Expected context gets updated.
         | 
| 128 | 
            +
                    next if file == 'ro-crate-preview.html' # RO-Crate preview format changed
         | 
| 129 | 
            +
                    abs_file_path = ::File.join(fixture, file)
         | 
| 130 | 
            +
                    next if ::File.directory?(abs_file_path)
         | 
| 131 | 
            +
                    assert_equal ::File.read(abs_file_path), ::File.read(::File.join(dir, file)), "#{file} didn't match"
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              end
         | 
| 102 135 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ro-crate
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.4. | 
| 4 | 
            +
              version: 0.4.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Finn Bacall
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021- | 
| 11 | 
            +
            date: 2021-02-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: addressable
         | 
| @@ -149,6 +149,8 @@ files: | |
| 149 149 | 
             
            - test/fixtures/crate-spec1.1/ro-crate-metadata.json
         | 
| 150 150 | 
             
            - test/fixtures/data.csv
         | 
| 151 151 | 
             
            - test/fixtures/directory.zip
         | 
| 152 | 
            +
            - test/fixtures/directory/.dir/test.txt
         | 
| 153 | 
            +
            - test/fixtures/directory/.dotfile
         | 
| 152 154 | 
             
            - test/fixtures/directory/data/binary.jpg
         | 
| 153 155 | 
             
            - test/fixtures/directory/data/info.txt
         | 
| 154 156 | 
             
            - test/fixtures/directory/data/nested.txt
         | 
| @@ -160,10 +162,21 @@ files: | |
| 160 162 | 
             
            - test/fixtures/directory_crate/fish/info.txt
         | 
| 161 163 | 
             
            - test/fixtures/directory_crate/fish/root.txt
         | 
| 162 164 | 
             
            - test/fixtures/directory_crate/ro-crate-metadata.jsonld
         | 
| 165 | 
            +
            - test/fixtures/directory_crate/ro-crate-preview.html
         | 
| 163 166 | 
             
            - test/fixtures/file with spaces.txt
         | 
| 164 167 | 
             
            - test/fixtures/info.txt
         | 
| 165 168 | 
             
            - test/fixtures/spaces/file with spaces.txt
         | 
| 166 169 | 
             
            - test/fixtures/spaces/ro-crate-metadata.jsonld
         | 
| 170 | 
            +
            - test/fixtures/sparse_directory_crate.zip
         | 
| 171 | 
            +
            - test/fixtures/sparse_directory_crate/fish/data/binary.jpg
         | 
| 172 | 
            +
            - test/fixtures/sparse_directory_crate/fish/data/info.txt
         | 
| 173 | 
            +
            - test/fixtures/sparse_directory_crate/fish/data/nested.txt
         | 
| 174 | 
            +
            - test/fixtures/sparse_directory_crate/fish/info.txt
         | 
| 175 | 
            +
            - test/fixtures/sparse_directory_crate/fish/root.txt
         | 
| 176 | 
            +
            - test/fixtures/sparse_directory_crate/listed_file.txt
         | 
| 177 | 
            +
            - test/fixtures/sparse_directory_crate/ro-crate-metadata.jsonld
         | 
| 178 | 
            +
            - test/fixtures/sparse_directory_crate/ro-crate-preview.html
         | 
| 179 | 
            +
            - test/fixtures/sparse_directory_crate/unlisted_file.txt
         | 
| 167 180 | 
             
            - test/fixtures/workflow-0.2.0.zip
         | 
| 168 181 | 
             
            - test/fixtures/workflow-0.2.0/Dockerfile
         | 
| 169 182 | 
             
            - test/fixtures/workflow-0.2.0/README.md
         | 
| @@ -2414,5 +2427,5 @@ requirements: [] | |
| 2414 2427 | 
             
            rubygems_version: 3.0.8
         | 
| 2415 2428 | 
             
            signing_key: 
         | 
| 2416 2429 | 
             
            specification_version: 4
         | 
| 2417 | 
            -
            summary: Create, manipulate, read RO | 
| 2430 | 
            +
            summary: Create, manipulate, read RO-Crates.
         | 
| 2418 2431 | 
             
            test_files: []
         |