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
# File 'lib/sass/importers/filesystem.rb', line 14

def initialize(root)
  @root = File.expand_path(root)
  @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



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

def directories_to_watch
  [root]
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


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

def eql?(other)
  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:



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

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 existant 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
# 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 = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
      "#{escape_glob_characters(dir)}/#{f}"
    Dir[path].map do |full_path|
      full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
      [Sass::Util.cleanpath(full_path).to_s, s]
    end
  end
  found = Sass::Util.flatten(found, 1)
  return if found.empty?

  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:



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

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

#hash



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

def hash
  @root.hash
end

#key(name, options)

See Also:



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

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

#mtime(name, options)

See Also:



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

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(/^\.\//, ''), s]}
end

#public_url(name, sourcemap_directory = nil)



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

def public_url(name, sourcemap_directory = nil)
  if sourcemap_directory.nil?
    warn_about_public_url(name)
  else
    file_pathname = Sass::Util.cleanpath(Sass::Util.absolute_path(name, @root))
    sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
    begin
      Sass::Util.file_uri_from_path(file_pathname.relative_path_from(sourcemap_pathname))
    rescue ArgumentError # when a relative path cannot be constructed
      warn_about_public_url(name)
      nil
    end
  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.



189
190
191
192
193
194
195
196
197
# File 'lib/sass/importers/filesystem.rb', line 189

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:



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

def to_s
  @root
end

#warn_about_public_url(uri) ⇒ NilClass (protected)

Issues a warning about being unable to determine a public url.

Parameters:

  • uri (String)

    A URI known to be valid for this importer.

Returns:

  • (NilClass)

    nil



203
204
205
206
207
208
209
210
211
212
213
# File 'lib/sass/importers/filesystem.rb', line 203

def warn_about_public_url(uri)
  @warnings_issued ||= Set.new
  unless @warnings_issued.include?(uri)
    Sass::Util.sass_warn <<WARNING
WARNING: Couldn't determine public URL for "#{uri}" while generating sourcemap.
  Without a public URL, there's nothing for the source map to link to.
WARNING
    @warnings_issued << uri
  end
  nil
end

#watched_file?(filename) ⇒ Boolean

Returns:

  • (Boolean)

See Also:



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

def watched_file?(filename)
  filename =~ /\.s[ac]ss$/ &&
    filename.start_with?(root + File::SEPARATOR)
end