lib/stashify/directory.rb in stashify-3.2.0 vs lib/stashify/directory.rb in stashify-3.2.1
- old
+ new
@@ -1,73 +1,176 @@
# frozen_string_literal: true
module Stashify
+ # A common abstraction for interacting with directories. All methods
+ # that need to interact with directories are assumed to adhere to
+ # the public methods defined here. Specifically, the methods
+ # {#find}, {#write}, {#delete}, and {#files} are guaranteed to exist
+ # and behave in a way that is consistent across all gems. Unless
+ # called out separately, documentation for those methods here will
+ # hold true of any implementations of this class.
class Directory
- attr_reader :name, :files, :path
+ # Provides the files and subdirectories of this directory. In the
+ # base class, this is implemented as an attribute which defaults
+ # to an empty list, but most implementations will override this
+ # with a method. In most implementations, the performance cost of
+ # reading all of thie names in a directory to construct these
+ # objects is high enough that we only want to pay it if it's
+ # actually needed.
+ #
+ # @return [Array<Stashify::File and Stashify::Directory>] Returns
+ # an Enumerable of Stashify::File and Stashify::Directory
+ # objects.
+ attr_reader :files
+ # The name of the directory. It is everything that follows the
+ # final "/" in the {#path}. This is always guaranteed to be
+ # populated.
+ attr_reader :name
+
+ # The full path to the directory this represents. Anything after the
+ # final "/" will also be returned from {#name}. This is not
+ # necessarily guaranteed to be populated, but usually will be.
+ attr_reader :path
+
+ # Basic information associated with a directory that is necessary
+ # to enable memory-based interactions.
+ #
+ # @param name [String not containing a "/"] The name of the file. Either this or path must be defined.
+ # @param path [String] The path of the file, will populate name with everything following the final "/".
+ # @param files An array of Stashify::File and Stashify::Directory
+ # objects representing the contents of this directory.
def initialize(name: nil, path: nil, files: [])
raise StandardError, "name or path must be defined" unless name || path
@path = path
@name = name || ::File.basename(path)
@files = files
end
+ # Look up the item in this directory represented by the provided
+ # name.
+ #
+ # For those looking to implement this method, it's typically more
+ # effective to override {#directory?}, {#directory}, {#exists?}
+ # and {#file}. Unless there are performance concerns with calling
+ # those, the default implementation will work pretty well.
+ #
+ # @param name [String with no "/"] The name of the desired item in
+ # this directory.
+ #
+ # @return Either a Stashify::File or Stashify::Directory object,
+ # depending on what that name represents.
def find(name)
if directory?(name)
directory(name)
elsif exists?(name)
file(name)
end
end
- def write(file)
- if file.is_a?(Stashify::Directory)
- write_directory(file)
+ # Write the provided item into the directory. If the item is a
+ # directory itself, then all of the contents will be copied.
+ #
+ # For those looking to implement this method, it's typically
+ # easier to implement {#write_file} and {#write_directory}. This
+ # helps you avoid having to know what type of object you're
+ # dealing with.
+ #
+ # @param item Either a Stashify::File or Stashify::Directory
+ # object. Note that these can be any implementation of these
+ # base classes, it's not limited to the classes from the same
+ # provider.
+ def write(item)
+ if item.is_a?(Stashify::Directory)
+ write_directory(item)
else
- write_file(file)
+ write_file(item)
end
end
+ # Writes the provided directory. Typically you will want to
+ # interact with this functionality through {#write} rather than
+ # directly, as it protects you from errors related to accidentally
+ # passing a Stashify::File value in. It is primarily implemented
+ # separately to give a more specific hook for various
+ # implementations.
+ #
+ # The default implementation might work for you, as it iterates
+ # through {#files} and writes them to the new subdirectory.
def write_directory(directory)
subdir = self.directory(directory.name)
directory.files.each { |file| subdir.write(file) }
end
+ # Writes the provided file. Typically you will want to interact
+ # with this functionality through {#write} rather than directly,
+ # as it protects you from errors related to accidentally passing a
+ # Stashify::Directory value in. It is primarily implemented
+ # separately to give a more specific hook for various
+ # implementations.
def write_file(file)
file(file.name).write(file.contents)
end
+ # Delete provided name from the directory. If the item is a
+ # directory itself, then all of the contents will be copied.
+ #
+ # For those looking to implement this method, it's typically
+ # easier to implement {#directory?}, {#delete_directory} and
+ # {#delete_file}. The primary reason to override this method would
+ # be for performance reasons.
+ #
+ # @param name [String] Name of the item to be deleted.
def delete(name)
if directory?(name)
delete_directory(name)
else
delete_file(name)
end
end
+ # Deletes the provided directory name. Typically you will want to
+ # interact with this functionality through {#delete} rather than
+ # directly, as it protects you from errors related to accidentally
+ # asking to delete a file as a directory.
def delete_directory(name)
subdir = directory(name)
subdir.files.each { |file| subdir.delete(file.name) }
end
+ # Deletes the provided file name. Typically you will want to
+ # interact with this functionality through {#delete} rather than
+ # directly, as it protects you from errors related to accidentally
+ # asking to delete a directory as a file.
def delete_file(name)
file(name).delete
end
+ # Two directories are equal if their files are equal. This is
+ # distinct from being the same directory, which is served by the
+ # {#eql?} method.
def ==(other)
files == other.files
end
+ # This answers if the two directories are the same, which is
+ # usually more specific than you want. If you wish to determine if
+ # all of the files are equal, consider {#==} instead..
def eql?(other)
self.class == other.class && name == other.name && path == other.path
end
+ # @return [Stashify::File] Return an object representing a single
+ # file in this directory.
def file(name)
Stashify::File.new(path: path_of(name))
end
- def path_of(*name)
- ::File.join(path, *name)
+ # The full path to the item in this directory provided by the
+ # names. Any number of names can be provided, allowing arbitrarily
+ # deep paths to be constructed below this directory.
+ def path_of(*names)
+ ::File.join(path, *names)
end
end
end