module Pione module Location class DataLocation < BasicLocation location_type :data KNOWN_ATTRS = [:need_caching, :real_appendable, :writable] class << self # @return [String] # location's scheme name attr_reader :scheme # Declare the name as location scheme. # # @param name [String] # scheme name def set_scheme(name) @scheme = name SCHEMES[name] = self end # Define a location's attribute. # # - need_caching : whether the location needs to be cached or not # - real_appendable : whether the location can appendable or not # - writable : whether the location is writable or not def define(name, val) if DataLocation::KNOWN_ATTRS.include?(name) (@attr ||= Hash.new)[name] = val else raise ArgumentError.new(name) end end # Return true if the location needs caching. def need_caching? @attr[:need_caching] end def real_appendable? @attr[:real_appendable] end def writable? @writable end end forward! :class, :scheme, :real_appendable?, :writable?, :need_caching? forward :@uri, :host # @return [URI] # URI of the location attr_reader :uri # @return [Pathname] # path of the location attr_reader :path # Create a location with the URI. # # @param uri [URI] # location URI def initialize(uri) @address = uri.to_s @uri = uri.kind_of?(URI::Generic) ? uri : URI.parse(uri) @path = Pathname.new(uri.path) raise ArgumentError.new(uri) unless @uri.scheme = scheme end # Copy the content to temporary local location and return the location. If # the scheme is local, return itself. def local if scheme == "local" self else Location[Temppath.create].tap {|tmp| copy(tmp) if exist?} end end # Return true if scheme of the location is local. def local? scheme == "local" end # Create new location appended the name. # # @param name [String] # filename or directory name # @return [BasicLocation] # new location def +(name) self.class.new(@uri.as_directory + name.to_s) end # Create new location that has URI as a directory. # # @return [BasicLocation] # new location def as_directory self.class.new(@uri.as_directory) end # Return the basename of the location. # # @param suffix [String] # suffix name # @return [String] # basename def basename(suffix="") File.basename(@path, suffix) end # Return the extension name of location. # # @return # the extension name of location def extname File.extname(basename) end # Return the dirname of location. This method returns it as a location. def dirname rebuild(@path.dirname).as_directory end # Rebuild location with the path. # # @param path [Pathname] # new path # @return [Location] # location with new path def rebuild(path) scheme = @uri.scheme auth = @uri.user and @uri.password ? "%s:%s@" % [@uri.user, @uri.password] : "" host = @uri.host port = @uri.port ? ":%i" % @uri.port : "" path = path.expand_path("/").to_s Location["%s://%s%s%s%s" % [scheme, auth, host, port, path]] end # Return true if the location is cached. # # @return [Boolean] # true if the location is cached def cached? System::FileCache.cached?(self) end # Write a data into the location. # # @param data [String] # data content # @return [void] def write(data) if exist? update(data) else create(data) end end # Creates a file at the location. If a file exists at the location aleady, # it raises an exception. # # @param data [String] # data content # @return [void] def create(data) raise NotImplementedError end # Append data to the location data. # # @param data [String] # data content # @return [void] def append(data) if real_appendable? raise NotImplmentedError else _local = local _local.append(data) _local.copy(self) end end # Read location data. # # @return [String] # data content def read raise NotImplementedError end # Update with the data. # # @param data [String] # new data content # @return [void] def update(data) raise NotImplementedError end # Delete data of the location. # # @return [void] def delete raise NotImplementedError end # Return ctime of the location. # # @return [Time] # ctime def ctime raise NotImplementedError end # Return mtime of the location. # # @return [Time] # mtime def mtime raise NotImplementedError end # Set mtime of the location. # # @return [void] def mtime=(time) raise NotImplementedError end # Return byte size of data in the location. # # @return [Integer] # byte size of data def size raise NotImplementedError end # Return entries of the location. # # @return [Array] # entries of the location def entries(&b) raise NotImplementedError end # Return relative entries of the location. # # @return [Array] # entries of the location def rel_entries(option) raise NotImplementedError end # Return file entries of the location. # # @return [Array] # file entries of the location def file_entries entries.select{|entry| entry.file?} end # Return directory entries of the location. # # @return [Array] # directory entries of the location def directory_entries entries.select do |entry| entry.directory? and not(entry.path.basename == "." or entry.path.basename == "..") end end # Return true if there is data in the location. # # @return [Boolean] # if there is data in the location def exist? raise NotImplementedError end # Return true if data at the location is a file. When there exists no # files and no directories, then return false. # # @return [Boolean] # true if data at the location is a file def file? raise NotImplementedError end # Return true if data at the location is a directory. When there exists no # files and no direcotries, then return false. # # @return [Boolean] # true if data at the location is a directory def directory? raise NotImplementedError end # Make the path a directory. # # @return [void] def mkdir raise NotImplementedError end # Move to the destination. # # @param dest [BasicLocation] # destination # @return [void] def move(dest) raise NotImplementedError end # Copy location's content to the destination. # # @param dest [BasicLocation] # destination # @return [void] def copy(dest) raise NotImplementedError end # Link to the destination. If the location scheme is same to destination, # create link by a symbolic link or lightweight copy method. If not, copy # it simply. # # @param dest [BasicLocation] # destination # @return [void] def link(dest) raise NotImplementedError end # Move data to the destination and link self to it. # # @param dest [BasicLocation] # destination # @return [void] def turn(dest) raise NotImplementedError end # Return the digest string by SHA1. # # @return [String] # hex-string of the file def sha1 if file? Digest::SHA1.file(local.path) else raise InvalidFileOperation.new(self) end end # @api private def inspect "#<%s %s:%s>" % [self.class, scheme, @path.to_s] end alias :to_s :inspect # @api private def ==(other) return false unless other.kind_of?(self.class) @uri == other.uri end alias :eql? :"==" # @api private def hash @uri.hash end end end end