require'pathname'moduleSassmoduleImporters# The default importer, used for any strings found in the load path.# Simply loads Sass files from the filesystem using the default logic.classFilesystem<Baseattr_accessor:root# Creates a new filesystem importer that imports files relative to a given path.## @param root [String] The root path.# This importer will import files relative to this path.definitialize(root)@root=rootend# @see Base#find_relativedeffind_relative(name,base,options)_find(File.dirname(base),name,options)end# @see Base#finddeffind(name,options)_find(@root,name,options)end# @see Base#mtimedefmtime(name,options)file,s=find_real_file(@root,name)File.mtime(file)iffilerescueErrno::ENOENTnilend# @see Base#keydefkey(name,options)[self.class.name+":"+File.dirname(File.expand_path(name)),File.basename(name)]end# @see Base#to_sdefto_s@rootendprotected# If a full uri is passed, this removes the root from it# otherwise returns the name unchangeddefremove_root(name)root=@root.end_with?('/')?@root:@root+'/'ifname.index(root)==0name[root.length..-1]elsenameendend# A hash from file extensions to the syntaxes for those extensions.# The syntaxes must be `:sass` or `:scss`.## This can be overridden by subclasses that want normal filesystem importing# with unusual extensions.## @return [{String => Symbol}]defextensions{'sass'=>:sass,'scss'=>:scss}end# Given an `@import`ed path, returns an array of possible# on-disk filenames and their corresponding syntaxes for that path.## @param name [String] The filename.# @return [Array(String, Symbol)] An array of pairs.# The first element of each pair is a filename to look for;# the second element is the syntax that file would be in (`:sass` or `:scss`).defpossible_files(name)dirname,basename,extname=split(name)sorted_exts=extensions.sortsyntax=extensions[extname]return[["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}",syntax]]ifsyntaxsorted_exts.map{|ext,syn|["#{dirname}/{_,}#{basename}.#{ext}",syn]}endREDUNDANT_DIRECTORY=%r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}# Given a base directory and an `@import`ed name,# finds an existant file that matches the name.## @param dir [String] The directory relative to which to search.# @param name [String] The filename to search for.# @return [(String, Symbol)] A filename-syntax pair.deffind_real_file(dir,name)for(f,s)inpossible_files(remove_root(name))path=(dir==".")?f:"#{dir}/#{f}"iffull_path=Dir[path].firstfull_path.gsub!(REDUNDANT_DIRECTORY,File::SEPARATOR)returnfull_path,sendendnilend# Splits a filename into three parts, a directory part, a basename, and an extension# Only the known extensions returned from the extensions method will be recognized as such.defsplit(name)extension=nildirname,basename=File.dirname(name),File.basename(name)ifbasename=~/^(.*)\.(#{extensions.keys.map{|e|Regexp.escape(e)}.join('|')})$/basename=$1extension=$2end[dirname,basename,extension]enddefhash@root.hashenddefeql?(other)root.eql?(other.root)endprivatedef_find(dir,name,options)full_filename,syntax=find_real_file(dir,name)returnunlessfull_filename&&File.readable?(full_filename)options[:syntax]=syntaxoptions[:filename]=full_filenameoptions[:importer]=selfSass::Engine.new(File.read(full_filename),options)enddefjoin(base,path)Pathname.new(base).join(path).to_sendendendend