Dylan mode Module: locators-internals Synopsis: Abstract modeling of locations Author: Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: See License.txt in this distribution for details. Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define open generic locator-server (locator :: ) => (server :: false-or( )); define open generic locator-host (locator :: ) => (host :: false-or( )); define open generic locator-volume (locator :: ) => (volume :: false-or( )); define open generic locator-directory (locator :: ) => (directory :: false-or( )); define open generic locator-relative? (locator :: ) => (relative? :: ); define open generic locator-path (locator :: ) => (path :: ); define open generic locator-base (locator :: ) => (base :: false-or( )); define open generic locator-extension (locator :: ) => (extension :: false-or( )); /// Locator classes define open abstract class ( ) end class ; define open abstract class ( ) end class ; define method as (class == , string :: ) => (locator :: ) as( , string) end method as; define method make (class == , #key server :: false-or( ) = #f, path :: = #[], relative? :: = #f, name :: false-or( ) = #f) => (locator :: ) make( , server: server, path: path, relative?: relative?, name: name) end method make; define method as (class == , string :: ) => (locator :: ) as( , string) end method as; define method make (class == , #key directory :: false-or( ) = #f, base :: false-or( ) = #f, extension :: false-or( ) = #f, name :: false-or( ) = #f) => (locator :: ) make( , directory: directory, base: base, extension: extension, name: name) end method make; /// Locator coercion //---*** andrewa: This caching scheme doesn't work yet, so disable it. define constant $cache-locators? = #f; define constant $cache-locator-strings? = #f; define constant $locator-to-string-cache = make( , weak: #"key"); define constant $string-to-locator-cache = make( , weak: #"value"); define open generic locator-as-string (class :: subclass( ), locator :: ) => (string :: ); define open generic string-as-locator (class :: subclass( ), string :: ) => (locator :: ); define sealed sideways method as (class :: subclass( ), locator :: ) => (string :: ) let string = element($locator-to-string-cache, locator, default: #f); if (string) as(class, string) else let string = locator-as-string(class, locator); if ($cache-locator-strings?) element($locator-to-string-cache, locator) := string; else string end end end method as; define sealed sideways method as (class :: subclass( ), string :: ) => (locator :: ) let locator = element($string-to-locator-cache, string, default: #f); if (instance?(locator, class)) locator else let locator = string-as-locator(class, string); if ($cache-locators?) element($string-to-locator-cache, string) := locator; else locator end end end method as; /// Locator conditions define class ( , ) end class ; define function locator-error (format-string :: , #rest format-arguments) error(make( , format-string: format-string, format-arguments: format-arguments)) end function locator-error; /// Useful locator protocols define open generic locator-test (locator :: ) => (test :: ); define method locator-test (locator :: ) => (test :: ) \= end method locator-test; define open generic locator-might-have-links? (locator :: ) => (links? :: ); define method locator-might-have-links? (locator :: ) => (links? :: singleton(#f)) #f end method locator-might-have-links?; define method locator-relative? (locator :: ) => (relative? :: ) let directory = locator.locator-directory; ~directory | directory.locator-relative? end method locator-relative?; define method current-directory-locator? (locator :: ) => (current-directory? :: ) locator.locator-relative? & locator.locator-path = #[#"self"] end method current-directory-locator?; define method locator-directory (locator :: ) => (parent :: false-or( )) let path = locator.locator-path; unless (empty?(path)) make(object-class(locator), server: locator.locator-server, path: copy-sequence(path, end: path.size - 1), relative?: locator.locator-relative?) end end method locator-directory; /// Simplify locator define open generic simplify-locator (locator :: ) => (simplified-locator :: ); define method simplify-locator (locator :: ) => (simplified-locator :: ) let path = locator.locator-path; let relative? = locator.locator-relative?; let resolve-parent? = ~locator.locator-might-have-links?; let simplified-path = simplify-path(path, resolve-parent?: resolve-parent?, relative?: relative?); if (path ~= simplified-path) make(object-class(locator), server: locator.locator-server, path: simplified-path, relative?: locator.locator-relative?) else locator end end method simplify-locator; define method simplify-locator (locator :: ) => (simplified-locator :: ) let directory = locator.locator-directory; let simplified-directory = directory & simplify-locator(directory); if (directory ~= simplified-directory) make(object-class(locator), directory: simplified-directory, base: locator.locator-base, extension: locator.locator-extension) else locator end end method simplify-locator; /// Subdirectory locator define open generic subdirectory-locator (locator :: , #rest sub-path) => (subdirectory :: ); define method subdirectory-locator (locator :: , #rest sub-path) => (subdirectory :: ) let old-path = locator.locator-path; let new-path = concatenate-as( , old-path, sub-path); make(object-class(locator), server: locator.locator-server, path: new-path, relative?: locator.locator-relative?) end method subdirectory-locator; /// Relative locator define open generic relative-locator (locator :: , from-locator :: ) => (relative-locator :: ); define method relative-locator (locator :: , from-locator :: ) => (relative-locator :: ) let path = locator.locator-path; let from-path = from-locator.locator-path; case ~locator.locator-relative? & from-locator.locator-relative? => locator-error ("Cannot find relative path of absolute locator %= from relative locator %=", locator, from-locator); locator.locator-server ~= from-locator.locator-server => locator; path = from-path => make(object-class(locator), path: vector(#"self"), relative?: #t); otherwise => make(object-class(locator), path: relative-path(path, from-path, test: locator.locator-test), relative?: #t); end end method relative-locator; define method relative-locator (locator :: , from-directory :: ) => (relative-locator :: ) let directory = locator.locator-directory; let relative-directory = directory & relative-locator(directory, from-directory); if (relative-directory ~= directory) simplify-locator (make(object-class(locator), directory: relative-directory, base: locator.locator-base, extension: locator.locator-extension)) else locator end end method relative-locator; define method relative-locator (locator :: , from-locator :: ) => (relative-locator :: ) let from-directory = from-locator.locator-directory; case from-directory => relative-locator(locator, from-directory); ~locator.locator-relative? => locator-error ("Cannot find relative path of absolute locator %= from relative locator %=", locator, from-locator); otherwise => locator; end end method relative-locator; /// Merge locators define open generic merge-locators (locator :: , from-locator :: ) => (merged-locator :: ); /// Merge locators define method merge-locators (locator :: , from-locator :: ) => (merged-locator :: ) if (locator.locator-relative?) let path = concatenate(from-locator.locator-path, locator.locator-path); simplify-locator (make(object-class(locator), server: from-locator.locator-server, path: path, relative?: from-locator.locator-relative?)) else locator end end method merge-locators; define method merge-locators (locator :: , from-locator :: ) => (merged-locator :: ) let directory = locator.locator-directory; let merged-directory = if (directory) merge-locators(directory, from-locator) else simplify-locator(from-locator) end; if (merged-directory ~= directory) make(object-class(locator), directory: merged-directory, base: locator.locator-base, extension: locator.locator-extension) else locator end end method merge-locators; define method merge-locators (locator :: , from-locator :: ) => (merged-locator :: ) let from-directory = from-locator.locator-directory; if (from-directory) merge-locators(locator, from-directory) else locator end end method merge-locators; /// Locator protocols define sideways method supports-open-locator? (locator :: ) => (openable? :: ) ~locator.locator-relative? end method supports-open-locator?; define sideways method open-locator (locator :: , #rest keywords, #key, #all-keys) => (stream :: ) apply(open-file-stream, locator, keywords) end method open-locator; MIME types defined: text/x-dylan.