Class: ROBundle::File

Inherits:
UCF::File
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/ro-bundle/file.rb

Overview

This class represents a Research Object Bundle file. See the RO Bundle specification for more details.

Many of the methods that this class provides are actually implemented in the Manifest class, so please see its documentation for details.

Constant Summary collapse

MIMETYPE =

:stopdoc:

"application/vnd.wf4ever.robundle+zip"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename) ⇒ File

Returns a new instance of File.



34
35
36
37
38
39
40
41
# File 'lib/ro-bundle/file.rb', line 34

def initialize(filename)
  super(filename)

  # Initialize the managed entries and register the .ro directory.
  @manifest = Manifest.new
  @ro_dir = RODir.new(@manifest)
  initialize_managed_entries(@ro_dir)
end

Instance Attribute Details

#manifestObject (readonly)

Returns the value of attribute manifest.



29
30
31
# File 'lib/ro-bundle/file.rb', line 29

def manifest
  @manifest
end

Class Method Details

.create(filename, mimetype = MIMETYPE, &block) ⇒ Object

:call-seq:

create(filename) -> File
create(filename, mimetype) -> File
create(filename) {|file| ...}
create(filename, mimetype) {|file| ...}

Create a new RO Bundle file on disk and open it for editing. A custom mimetype for the bundle may be specified but is unnecessary if the default, “application/vnd.wf4ever.robundle+zip”, will be used.

Please see the UCF documentation for much more information and a list of all the other methods available in this class. RDoc does not list inherited methods, unfortunately.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ro-bundle/file.rb', line 58

def self.create(filename, mimetype = MIMETYPE, &block)
  # Wow. I have to specifically send nil as the block to stop super from
  # sending the other block up automatically. Is this a bug in Ruby?
  ro = super(filename, mimetype, &nil)
  ro.

  if block_given?
    begin
      yield ro
    ensure
      ro.close
    end
  end

  ro
end

Instance Method Details

#add(entry, src_path, options = {}, &continue_on_exists_proc) ⇒ Object

:call-seq:

add(entry, src_path, options = {}, &continue_on_exists_proc) -> Aggregate or nil

Convenience method for adding the contents of a file to the bundle file. If asked to add a file with a reserved name, such as the special mimetype header file or .ro/manifest.json, this method will raise a ReservedNameClashError.

This method automatically adds new entries to the list of bundle aggregates unless the :aggregate option is set to false.

If the added entry is aggregated then the Aggregate object is returned, otherwise nil is returned.

See the rubyzip documentation for details of the continue_on_exists_proc parameter.



91
92
93
94
95
96
97
98
99
# File 'lib/ro-bundle/file.rb', line 91

def add(entry, src_path, options = {}, &continue_on_exists_proc)
  super(entry, src_path, &continue_on_exists_proc)

  options = { :aggregate => true }.merge(options)

  if options[:aggregate]
    @manifest.add_aggregate(entry)
  end
end

#add_aggregate(entry, src_path = nil, &continue_on_exists_proc) ⇒ Object

:call-seq:

add_aggregate(uri) -> Aggregate
add_aggregate(entry) -> Aggregate
add_aggregate(entry, src_path, &continue_on_exists_proc) -> Aggregate

The first form of this method adds a URI as an aggregate of the bundle.

The second form adds an already existing entry in the bundle to the list of aggregates. Errno:ENOENT is raised if the entry does not exist.

The third form is equivalent to File#add called without any options.

In all cases the Aggregate object added to the Research Object is returned.



116
117
118
119
120
121
122
# File 'lib/ro-bundle/file.rb', line 116

def add_aggregate(entry, src_path = nil, &continue_on_exists_proc)
  if src_path.nil?
    @manifest.add_aggregate(entry)
  else
    add(entry, src_path, &continue_on_exists_proc)
  end
end

#add_annotation(target, body = nil, options = {}) ⇒ Object

:call-seq:

add_annotation(annotation_object) -> Annotation
add_annotation(aggregate, content, options = {}) -> Annotation
add_annotation(aggregate, file, options = {}) -> Annotation
add_annotation(aggregate, uri, options = {}) -> Annotation
add_annotation(uri, content, options = {}) -> Annotation
add_annotation(uri, file, options = {}) -> Annotation
add_annotation(uri, uri, options = {}) -> Annotation
add_annotation(annotation, content, options = {}) -> Annotation
add_annotation(annotation, file, options = {}) -> Annotation
add_annotation(annotation, uri, options = {}) -> Annotation

This method has two forms.

The first form registers an already initialized Annotation object in this Research Object.

The second form creates a new Annotation object for the specified target with the specified (or empty content) and registers it in this Research Object.

In both cases Errno:ENOENT is raised if the target of the annotation is not an annotatable resource.

The Annotation object added to the Research Object is returned.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/ro-bundle/file.rb', line 149

def add_annotation(target, body = nil, options = {})
  options = { :aggregate => false }.merge(options)

  if target.is_a?(Annotation) || annotatable?(target)
    if body.nil? || aggregate?(body)
      content = body
    elsif Util.is_absolute_uri?(body)
      content = body
      @manifest.add_aggregate(body) if options[:aggregate]
    else
      content = @ro_dir.write_annotation_data(body, options)
    end

    @manifest.add_annotation(target, content)
  else
    raise Errno::ENOENT,
      "'#{target}' is not a member of this Research Object or a URI."
  end
end

#add_history(entry, src_path = nil, &continue_on_exists_proc) ⇒ Object

:call-seq:

add_history(entry)
add_history(entry, src_path, &continue_on_exists_proc)

The first form of this method adds an already existing entry in the bundle to the history list in the manifest. Errno:ENOENT is raised if the entry does not exist.

The second form adds the entry before adding it to the history list. The entry is not aggregated.



179
180
181
182
183
184
185
# File 'lib/ro-bundle/file.rb', line 179

def add_history(entry, src_path = nil, &continue_on_exists_proc)
  unless src_path.nil?
    add(entry, src_path, :aggregate => false, &continue_on_exists_proc)
  end

  @manifest.add_history(entry)
end

#aggregate?(entry) ⇒ Boolean

:call-seq:

aggregate?(uri) -> true or false
aggregate?(entry) -> true or false

Is the supplied URI or entry aggregated in this Research Object?

Returns:

  • (Boolean)


192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ro-bundle/file.rb', line 192

def aggregate?(entry)
  return true if entry == @manifest.id

  if Util.is_absolute_uri?(entry)
    entry = entry.to_s
  else
    entry = entry_name(entry)
  end

  aggregates.each do |agg|
    return true if agg.uri == entry || agg.file_entry == entry
  end

  false
end

#annotatable?(target) ⇒ Boolean

:call-seq:

annotatable?(target) -> true or false

Is the supplied target an annotatable resource? An annotatable resource is either an absolute URI (which may or may not be aggregated in the RO), an aggregated resource or another registered annotation.

Returns:

  • (Boolean)


214
215
216
# File 'lib/ro-bundle/file.rb', line 214

def annotatable?(target)
  Util.is_absolute_uri?(target) || annotation?(target) || aggregate?(target)
end

#annotation?(id) ⇒ Boolean

:call-seq:

annotation?(id) -> true or false
annotation?(annotation) -> true or false

Is the supplied id or annotation registered in this Research Object?

Returns:

  • (Boolean)


223
224
225
226
227
228
229
230
231
# File 'lib/ro-bundle/file.rb', line 223

def annotation?(id)
  id = id.uri if id.instance_of?(Annotation)

  annotations.each do |ann|
    return true if ann.uri == id
  end

  false
end

#commitObject Also known as: close

:call-seq:

commit -> true or false
close -> true or false

Commits changes that have been made since the previous commit to the RO Bundle file. Returns true if anything was actually done, false otherwise.



240
241
242
243
244
245
246
247
248
249
# File 'lib/ro-bundle/file.rb', line 240

def commit
  if @manifest.edited?
    # This will overwrite the old version.
    @manifest.write

    @ro_dir.cleanup_annotation_data
  end

  super
end

#commit_required?Boolean

:call-seq:

commit_required? -> true or false

Returns true if any changes have been made to this RO Bundle file since the last commit, false otherwise.

Returns:

  • (Boolean)


258
259
260
# File 'lib/ro-bundle/file.rb', line 258

def commit_required?
  super || @manifest.edited?
end

#find_entry(entry_name, options = {}) ⇒ Object

:call-seq:

find_entry(entry_name, options = {}) -> Zip::Entry or nil

Searches for the entry with the specified name. Returns nil if no entry is found or if the specified entry is hidden for normal use. You can specify :include_hidden => true to include hidden entries in the search.



269
270
271
272
273
# File 'lib/ro-bundle/file.rb', line 269

def find_entry(entry_name, options = {})
  return if Util.is_absolute_uri?(entry_name)

  super(entry_name, options)
end

#init_metadataObject

:stopdoc:



327
328
329
330
331
# File 'lib/ro-bundle/file.rb', line 327

def 
  mkdir(@ro_dir.full_name)
  @manifest.init
  commit
end

#remove(entry, preserve_manifest = false) ⇒ Object

:call-seq:

remove(entry)

Removes the specified entry from the Research Object bundle. If asked to remove any reserved files such as the special mimetype header file this method will do nothing.

If the entry being removed is aggregated in this RO then the aggregation is removed. All annotations that refer to the removed entry are also removed.



285
286
287
288
289
290
291
292
293
294
# File 'lib/ro-bundle/file.rb', line 285

def remove(entry, preserve_manifest = false)
  super(entry)

  # The preserve manifest flag is STRICTLY for internal use only.
  unless preserve_manifest
    name = entry_name(entry)
    @manifest.remove_aggregate("/#{name}")
    remove_annotation("/#{name}")
  end
end

#remove_aggregate(object, options = {}) ⇒ Object

:call-seq:

remove_aggregate(entry)
remove_aggregate(uri)
remove_aggregate(Aggregate)

Remove (unregister) an aggregate from this Research Object. If it is a file then the file is no longer aggregated, and it is deleted from the bundle by this method unless the option :keep_file => true is supplied.

Any annotations with the removed aggregate as their target are also removed from the RO.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/ro-bundle/file.rb', line 308

def remove_aggregate(object, options = {})
  options = { :keep_file => false }.merge(options)
  file = nil

  if object.is_a?(Aggregate)
    file = object.file_entry
  elsif !Util.is_absolute_uri?(object)
    object = entry_name(object)
    file = Util.strip_leading_slash(object)
  end

  if !file.nil? && !options[:keep_file]
    remove(file, true)
  end

  @manifest.remove_aggregate(object)
end