Class: Sass::Importers::Filesystem

Inherits:
Base
  • Object
show all
Defined in:
lib/sass/importers/filesystem.rb

Overview

The default importer, used for any strings found in the load path. Simply loads Sass files from the filesystem using the default logic.

Direct Known Subclasses

DeprecatedPath

Constant Summary collapse

REDUNDANT_DIRECTORY =
/#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ Filesystem

Creates a new filesystem importer that imports files relative to a given path.

Parameters:

  • root (String)

    The root path. This importer will import files relative to this path.



14
15
16
17
18
# File 'lib/sass/importers/filesystem.rb', line 14

def initialize(root)
  @root = File.expand_path(root)
  @real_root = Sass::Util.realpath(@root).to_s
  @same_name_warnings = Set.new
end

Instance Attribute Details

#root

Returns the value of attribute root.



8
9
10
# File 'lib/sass/importers/filesystem.rb', line 8

def root
  @root
end

Instance Method Details

#directories_to_watch



58
59
60
# File 'lib/sass/importers/filesystem.rb', line 58

def directories_to_watch
  [root]
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/sass/importers/filesystem.rb', line 53

def eql?(other)
  !other.nil? && other.respond_to?(:root) && root.eql?(other.root)
end

#escape_glob_characters(name) (protected)



128
129
130
131
132
# File 'lib/sass/importers/filesystem.rb', line 128

def escape_glob_characters(name)
  name.gsub(/[\*\[\]\{\}\?]/) do |char|
    "\\#{char}"
  end
end

#extensions{String => Symbol} (protected)

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.

Returns:

  • ({String => Symbol})


101
102
103
# File 'lib/sass/importers/filesystem.rb', line 101

def extensions
  {'sass' => :sass, 'scss' => :scss}
end

#find(name, options)

See Also:



26
27
28
# File 'lib/sass/importers/filesystem.rb', line 26

def find(name, options)
  _find(@root, name, options)
end

#find_real_file(dir, name, options) ⇒ (String, Symbol) (protected)

Given a base directory and an @imported name, finds an existent file that matches the name.

Parameters:

  • dir (String)

    The directory relative to which to search.

  • name (String)

    The filename to search for.

Returns:

  • ((String, Symbol))

    A filename-syntax pair.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/sass/importers/filesystem.rb', line 141

def find_real_file(dir, name, options)
  # On windows 'dir' or 'name' can be in native File::ALT_SEPARATOR form.
  dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
  name = name.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?

  found = possible_files(remove_root(name)).map do |f, s|
    path = if dir == "." || Sass::Util.pathname(f).absolute?
             f
           else
             "#{escape_glob_characters(dir)}/#{f}"
           end
    Dir[path].map do |full_path|
      full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
      [Sass::Util.cleanpath(full_path).to_s, s]
    end
  end.flatten(1)
  if found.empty? && split(name)[2].nil? && File.directory?("#{dir}/#{name}")
    return find_real_file("#{dir}/#{name}", "index", options)
  end

  if found.size > 1 && !@same_name_warnings.include?(found.first.first)
    found.each {|(f, _)| @same_name_warnings << f}
    relative_to = Sass::Util.pathname(dir)
    if options[:_from_import_node]
      # If _line exists, we're here due to an actual import in an
      # import_node and we want to print a warning for a user writing an
      # ambiguous import.
      candidates = found.map do |(f, _)|
        "  " + Sass::Util.pathname(f).relative_path_from(relative_to).to_s
      end.join("\n")
      raise Sass::SyntaxError.new(<<MESSAGE)
It's not clear which file to import for '@import "#{name}"'.
Candidates:
#{candidates}
Please delete or rename all but one of these files.
MESSAGE
    else
      # Otherwise, we're here via StalenessChecker, and we want to print a
      # warning for a user running `sass --watch` with two ambiguous files.
      candidates = found.map {|(f, _)| "    " + File.basename(f)}.join("\n")
      Sass::Util.sass_warn <<WARNING
WARNING: In #{File.dirname(name)}:
  There are multiple files that match the name "#{File.basename(name)}":
#{candidates}
WARNING
    end
  end
  found.first
end

#find_relative(name, base, options)

See Also:



21
22
23
# File 'lib/sass/importers/filesystem.rb', line 21

def find_relative(name, base, options)
  _find(File.dirname(base), name, options)
end

#hash



49
50
51
# File 'lib/sass/importers/filesystem.rb', line 49

def hash
  @root.hash
end

#key(name, options)

See Also:



39
40
41
42
# File 'lib/sass/importers/filesystem.rb', line 39

def key(name, options)
  [self.class.name + ":" + File.dirname(File.expand_path(name)),
   File.basename(name)]
end

#mtime(name, options)

See Also:



31
32
33
34
35
36
# File 'lib/sass/importers/filesystem.rb', line 31

def mtime(name, options)
  file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
  File.mtime(file) if file
rescue Errno::ENOENT
  nil
end

#possible_files(name) ⇒ Array(String, Symbol) (protected)

Given an @imported path, returns an array of possible on-disk filenames and their corresponding syntaxes for that path.

Parameters:

  • name (String)

    The filename.

Returns:

  • (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).



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/sass/importers/filesystem.rb', line 112

def possible_files(name)
  name = escape_glob_characters(name)
  dirname, basename, extname = split(name)
  sorted_exts = extensions.sort
  syntax = extensions[extname]

  if syntax
    ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
  else
    ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
  end

  # JRuby chokes when trying to import files from JARs when the path starts with './'.
  ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
end

#public_url(name, sourcemap_directory)



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/sass/importers/filesystem.rb', line 69

def public_url(name, sourcemap_directory)
  file_pathname = Sass::Util.cleanpath(File.absolute_path(name, @root))
  return Sass::Util.file_uri_from_path(file_pathname) if sourcemap_directory.nil?

  sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
  begin
    Sass::Util.file_uri_from_path(
      Sass::Util.relative_path_from(file_pathname, sourcemap_pathname))
  rescue ArgumentError # when a relative path cannot be constructed
    Sass::Util.file_uri_from_path(file_pathname)
  end
end

#remove_root(name) (protected)

If a full uri is passed, this removes the root from it otherwise returns the name unchanged



86
87
88
89
90
91
92
# File 'lib/sass/importers/filesystem.rb', line 86

def remove_root(name)
  if name.index(@root + "/") == 0
    name[(@root.length + 1)..-1]
  else
    name
  end
end

#split(name) (protected)

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.



193
194
195
196
197
198
199
200
201
# File 'lib/sass/importers/filesystem.rb', line 193

def split(name)
  extension = nil
  dirname, basename = File.dirname(name), File.basename(name)
  if basename =~ /^(.*)\.(#{extensions.keys.map {|e| Regexp.escape(e)}.join('|')})$/
    basename = $1
    extension = $2
  end
  [dirname, basename, extension]
end

#to_s

See Also:



45
46
47
# File 'lib/sass/importers/filesystem.rb', line 45

def to_s
  @root
end

#watched_file?(filename) ⇒ Boolean

Returns:

  • (Boolean)

See Also:



63
64
65
66
67
# File 'lib/sass/importers/filesystem.rb', line 63

def watched_file?(filename)
  # Check against the root with symlinks resolved, since Listen
  # returns fully-resolved paths.
  filename =~ /\.s[ac]ss$/ && filename.start_with?(@real_root + File::SEPARATOR)
end