Class: IiifPrint::Data::WorkDerivatives
- Inherits:
-
Object
- Object
- IiifPrint::Data::WorkDerivatives
- Includes:
- FilesetHelper, PathHelper
- Defined in:
- lib/iiif_print/data/work_derivatives.rb
Overview
TODO: consider compositional refactoring (not mixins), but this
may make readability/comprehendability higher, and yield
higher applied/practical complexity.
Class Attribute Summary collapse
-
.remap_names ⇒ Object
Returns the value of attribute remap_names.
Instance Attribute Summary collapse
-
#assigned ⇒ Array<String>
Assigned attachment queue (of paths).
-
#fileset ⇒ FileSet
FileSet is secondary adapted context.
-
#parent ⇒ IiifPrint::Data::WorkFile
Parent pointer to WorkFile object representing fileset.
-
#unassigned ⇒ Array<String>
Assigned deletion queue (of destination names).
-
#work ⇒ ActiveFedora::Base
Work is primary adapted context.
Class Method Summary collapse
- .data(from:, of_type:) ⇒ String
-
.of(work, fileset = nil, parent = nil) ⇒ Object
alternate constructor spelling:.
Instance Method Summary collapse
-
#assign(path) ⇒ Object
Assign a path to assigned queue for attachment.
-
#attach(file, name) ⇒ Object
attach a single derivative file to work.
-
#commit! ⇒ Object
commit pending changes to work files beginning with removals, then with new assignments.
-
#commit_queued!(file_set) ⇒ Object
Given a fileset meeting both of the following conditions: 1.
-
#data(name) ⇒ String
Get raw binary or encoded text data of file as a String.
-
#delete(name, force: nil) ⇒ Object
Delete a derivative file from work, by destination name.
-
#exist?(name) ⇒ TrueClass, FalseClass
Check if derivative file exists for destination name.
-
#initialize(work: nil, fileset: nil, parent: nil) ⇒ WorkDerivatives
constructor
Adapt work and either specific or first fileset.
-
#load_paths ⇒ Object
Load all paths/names to @paths once, upon first access.
-
#path(name) ⇒ String, NilClass
path to existing derivative file for destination name.
-
#size(name = nil) ⇒ Integer
Get number of derivatives or, if a destination name argument is provided, the size of derivative file.
-
#state ⇒ String
Assignment state.
-
#unassign(name) ⇒ Object
Assign a destination name to unassigned queue for deletion – OR – remove a path from queue of assigned items.
-
#with_io(name, &block) ⇒ Object
Run a block in context of the opened derivative file for reading.
Methods included from PathHelper
#isuri?, #normalize_path, #path_to_uri, #registered_ingest_path, #validate_path
Methods included from FilesetHelper
Constructor Details
#initialize(work: nil, fileset: nil, parent: nil) ⇒ WorkDerivatives
Adapt work and either specific or first fileset
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 54 def initialize(work: nil, fileset: nil, parent: nil) # adapted context usually work, may be string id of FileSet @work = work @fileset = fileset.nil? ? first_fileset : fileset # computed name-to-path mapping, initially nil as sentinel for JIT load @paths = nil # assignments for attachment @assigned = [] # un-assignments for deletion @unassigned = [] # parent is IiifPrint::Data::WorkFile object for derivatives @parent = parent end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object (private)
298 299 300 301 302 303 304 305 306 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 298 def method_missing(method, *args, &block) # if we proxy mapping/hash enumertion methods, # make sure @paths loaded, then proxy to it. if respond_to_missing?(method) load_paths if @paths.nil? return @paths.send(method, *args, &block) end super end |
Class Attribute Details
.remap_names ⇒ Object
Returns the value of attribute remap_names.
37 38 39 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 37 def remap_names @remap_names end |
Instance Attribute Details
#assigned ⇒ Array<String>
Assigned attachment queue (of paths)
26 27 28 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 26 def assigned @assigned end |
#fileset ⇒ FileSet
FileSet is secondary adapted context
18 19 20 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 18 def fileset @fileset end |
#parent ⇒ IiifPrint::Data::WorkFile
Parent pointer to WorkFile object representing fileset
22 23 24 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 22 def parent @parent end |
#unassigned ⇒ Array<String>
Assigned deletion queue (of destination names)
30 31 32 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 30 def unassigned @unassigned end |
#work ⇒ ActiveFedora::Base
Work is primary adapted context
14 15 16 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 14 def work @work end |
Class Method Details
.data(from:, of_type:) ⇒ String
44 45 46 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 44 def self.data(from:, of_type:) new(work: from).data(of_type) end |
.of(work, fileset = nil, parent = nil) ⇒ Object
alternate constructor spelling:
49 50 51 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 49 def self.of(work, fileset = nil, parent = nil) new(work: work, fileset: fileset, parent: parent) end |
Instance Method Details
#assign(path) ⇒ Object
Assign a path to assigned queue for attachment
79 80 81 82 83 84 85 86 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 79 def assign(path) path = normalize_path(path) validate_path(path) @assigned.push(path) # We are keeping assignment both in ephemeral, transient @assigned # and mirroring to db to share context with other components: log_assignment(path, path_destination_name(path)) end |
#attach(file, name) ⇒ Object
attach a single derivative file to work
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 140 def attach(file, name) raise 'Cannot save for nil fileset' if fileset.nil? mkdir_pairtree path = path_factory.derivative_path_for_reference(fileset, name) # if file argument is path, copy file if file.is_a? String FileUtils.copy(file, path) else # otherwise, presume file is an IO, read, write it # note: does not close input file/IO, presume that is caller's # responsibility. orig_pos = file.tell file.seek(0) File.open(path, 'w') { |dstfile| dstfile.write(file.read) } file.seek(orig_pos) end # finally, reload @paths after mutation load_paths end |
#commit! ⇒ Object
commit pending changes to work files
beginning with removals, then with new assignments
103 104 105 106 107 108 109 110 111 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 103 def commit! @unassigned.each { |name| delete(name) } @assigned.each do |path| attach(path, path_destination_name(path)) end # reset queues after work is complete @assigned = [] @unassigned = [] end |
#commit_queued!(file_set) ⇒ Object
Given a fileset meeting both of the following conditions:
1. a non-nil import_url value;
2. is attached to a work (persisted in Fedora, if not yet in Solr)...
…this method gets associated derivative paths queued and attach all.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 119 def commit_queued!(file_set) raise ArgumentError, 'No FileSet import_url' if file_set.import_url.nil? import_path = file_url_to_path(file_set.import_url) work = file_set.member_of.select(&:work?)[0] raise ArgumentError, 'Work not found for fileset' if work.nil? derivatives = WorkDerivatives.of(work, file_set) IngestFileRelation.derivatives_for_file(import_path).each do |path| next unless File.exist?(path) = DerivativeAttachment.where(path: path).first derivatives.attach(path, .destination_name) # update previously nil fileset id .fileset_id = file_set.id .save! end @fileset ||= file_set load_paths end |
#data(name) ⇒ String
Get raw binary or encoded text data of file as a String
226 227 228 229 230 231 232 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 226 def data(name) result = '' with_io(name) do |io| result += io.read end result end |
#delete(name, force: nil) ⇒ Object
Delete a derivative file from work, by destination name
162 163 164 165 166 167 168 169 170 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 162 def delete(name, force: nil) raise 'Cannot save for nil fileset' if fileset.nil? path = path_factory.derivative_path_for_reference(fileset, name) # will remove file, if it exists; won't remove pairtree, even # if it becomes empty, as that is excess scope. FileUtils.rm(path, force: force) if File.exist?(path) # finally, reload @paths after mutation load_paths end |
#exist?(name) ⇒ TrueClass, FalseClass
Check if derivative file exists for destination name
218 219 220 221 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 218 def exist?(name) # TODO: It is unclear where the #keys and and #[] methods are coming from. There's @paths.keys referenced in this code. keys.include?(name) && File.exist?(self[name]) end |
#load_paths ⇒ Object
Load all paths/names to @paths once, upon first access
173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 173 def load_paths fsid = fileset_id if fsid.nil? @paths = {} return end # list of paths paths = path_factory.derivatives_for_reference(fsid) # names from paths @paths = paths.map { |e| [path_destination_name(e), e] }.to_h end |
#path(name) ⇒ String, NilClass
path to existing derivative file for destination name
188 189 190 191 192 193 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 188 def path(name) load_paths if @paths.nil? result = @paths[name] return if result.nil? File.exist?(result) ? result : nil end |
#size(name = nil) ⇒ Integer
Get number of derivatives or, if a destination name argument
is provided, the size of derivative file
209 210 211 212 213 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 209 def size(name = nil) load_paths if @paths.nil? return @paths.size if name.nil? File.size(@paths[name]) end |
#state ⇒ String
Assignment state
70 71 72 73 74 75 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 70 def state load_paths return 'dirty' unless @unassigned.empty? && @assigned.empty? return 'empty' if @paths.keys.empty? 'saved' end |
#unassign(name) ⇒ Object
Assign a destination name to unassigned queue for deletion – OR –
remove a path from queue of assigned items
91 92 93 94 95 96 97 98 99 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 91 def unassign(name) # if name is queued path, remove from @assigned queue: if @assigned.include?(name) @assigned.delete(name) unlog_assignment(name, path_destination_name(name)) end # if name is known destination name, remove @unassigned.push(name) if exist?(name) end |
#with_io(name, &block) ⇒ Object
Run a block in context of the opened derivative file for reading
198 199 200 201 202 203 |
# File 'lib/iiif_print/data/work_derivatives.rb', line 198 def with_io(name, &block) mode = ['xml', 'txt', 'html'].include?(name) ? 'rb:UTF-8' : 'rb' filepath = path(name) return if filepath.nil? File.open(filepath, mode, &block) end |