haml-edge 3.1.73 → 3.1.74
Sign up to get free protection for your applications and to get access to all the features.
- data/EDGE_GEM_VERSION +1 -1
- data/VERSION +1 -1
- data/lib/haml/exec.rb +7 -7
- data/lib/haml/util.rb +37 -0
- data/lib/sass/cache_store.rb +213 -0
- data/lib/sass/callbacks.rb +14 -0
- data/lib/sass/engine.rb +98 -15
- data/lib/sass/error.rb +4 -1
- data/lib/sass/importers/base.rb +138 -0
- data/lib/sass/importers/filesystem.rb +121 -0
- data/lib/sass/importers.rb +22 -0
- data/lib/sass/plugin/compiler.rb +351 -0
- data/lib/sass/plugin/configuration.rb +114 -212
- data/lib/sass/plugin/merb.rb +24 -13
- data/lib/sass/plugin/rails.rb +16 -7
- data/lib/sass/plugin/staleness_checker.rb +55 -33
- data/lib/sass/plugin.rb +25 -173
- data/lib/sass/script/node.rb +3 -3
- data/lib/sass/selector/simple.rb +1 -1
- data/lib/sass/tree/import_node.rb +44 -22
- data/lib/sass/tree/node.rb +17 -2
- data/lib/sass.rb +43 -0
- data/test/haml/util_test.rb +32 -0
- data/test/sass/cache_test.rb +67 -0
- data/test/sass/engine_test.rb +47 -16
- data/test/sass/importer_test.rb +82 -0
- data/test/sass/plugin_test.rb +21 -15
- data/test/sass/test_helper.rb +5 -0
- metadata +12 -3
- data/lib/sass/files.rb +0 -160
data/EDGE_GEM_VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.74
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.74
|
data/lib/haml/exec.rb
CHANGED
@@ -281,19 +281,19 @@ END
|
|
281
281
|
output = @options[:output]
|
282
282
|
|
283
283
|
@options[:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
|
284
|
-
|
284
|
+
engine =
|
285
285
|
if input.is_a?(File) && !@options[:check_syntax]
|
286
|
-
::Sass::Files.
|
286
|
+
::Sass::Files.engine_for(input.path, @options[:for_engine])
|
287
287
|
else
|
288
288
|
# We don't need to do any special handling of @options[:check_syntax] here,
|
289
289
|
# because the Sass syntax checking happens alongside evaluation
|
290
290
|
# and evaluation doesn't actually evaluate any code anyway.
|
291
|
-
::Sass::Engine.new(input.read(), @options[:for_engine])
|
291
|
+
::Sass::Engine.new(input.read(), @options[:for_engine])
|
292
292
|
end
|
293
293
|
|
294
294
|
input.close() if input.is_a?(File)
|
295
295
|
|
296
|
-
output.write(
|
296
|
+
output.write(engine.render)
|
297
297
|
output.close() if output.is_a? File
|
298
298
|
rescue ::Sass::SyntaxError => e
|
299
299
|
raise e if @options[:trace]
|
@@ -769,10 +769,10 @@ END
|
|
769
769
|
Less::Engine.new(input).to_tree.to_sass_tree.send("to_#{@options[:to]}", @options[:for_tree])
|
770
770
|
else
|
771
771
|
if input.is_a?(File)
|
772
|
-
::Sass::Files.
|
772
|
+
::Sass::Files.engine_for(input.path, @options[:for_engine])
|
773
773
|
else
|
774
|
-
::Sass::Engine.new(input.read, @options[:for_engine])
|
775
|
-
end.send("to_#{@options[:to]}", @options[:for_tree])
|
774
|
+
::Sass::Engine.new(input.read, @options[:for_engine])
|
775
|
+
end.to_tree.send("to_#{@options[:to]}", @options[:for_tree])
|
776
776
|
end
|
777
777
|
end
|
778
778
|
|
data/lib/haml/util.rb
CHANGED
@@ -263,6 +263,43 @@ module Haml
|
|
263
263
|
version_gt(v1, v2) || !version_gt(v2, v1)
|
264
264
|
end
|
265
265
|
|
266
|
+
# A wrapper for `Marshal.dump` that calls `#_before_dump` on the object
|
267
|
+
# before dumping it, `#_after_dump` afterwards.
|
268
|
+
# It also calls `#_around_dump` and passes it a block in which the object is dumped.
|
269
|
+
#
|
270
|
+
# If any of these methods are undefined, they are not called.
|
271
|
+
#
|
272
|
+
# @param obj [Object] The object to dump.
|
273
|
+
# @return [String] The dumped data.
|
274
|
+
def dump(obj)
|
275
|
+
obj._before_dump if obj.respond_to?(:_before_dump)
|
276
|
+
return Marshal.dump(obj) unless obj.respond_to?(:_around_dump)
|
277
|
+
res = nil
|
278
|
+
obj._around_dump {res = Marshal.dump(obj)}
|
279
|
+
res
|
280
|
+
ensure
|
281
|
+
obj._after_dump if obj.respond_to?(:_after_dump)
|
282
|
+
end
|
283
|
+
|
284
|
+
# A wrapper for `Marshal.load` that calls `#_after_load` on the object
|
285
|
+
# after loading it, if it's defined.
|
286
|
+
#
|
287
|
+
# @param data [String] The data to load.
|
288
|
+
# @return [Object] The loaded object.
|
289
|
+
def load(data)
|
290
|
+
obj = Marshal.load(data)
|
291
|
+
obj._after_load if obj.respond_to?(:_after_load)
|
292
|
+
obj
|
293
|
+
end
|
294
|
+
|
295
|
+
# Throws a NotImplementedError for an abstract method.
|
296
|
+
#
|
297
|
+
# @param obj [Object] `self`
|
298
|
+
# @raise [NotImplementedError]
|
299
|
+
def abstract(obj)
|
300
|
+
raise NotImplementedError.new("#{obj.class} must implement ##{caller_info[2]}")
|
301
|
+
end
|
302
|
+
|
266
303
|
# Silence all output to STDERR within a block.
|
267
304
|
#
|
268
305
|
# @yield A block in which no output will be printed to STDERR
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# An abstract base class for backends for the Sass cache.
|
5
|
+
# Any key-value store can act as such a backend;
|
6
|
+
# it just needs to implement the
|
7
|
+
# \{#_store} and \{#_retrieve} methods.
|
8
|
+
#
|
9
|
+
# To use a cache store with Sass,
|
10
|
+
# use the {file:SASS_REFERENCE.md#cache_store-option `:cache_store` option}.
|
11
|
+
class CacheStore
|
12
|
+
# Store cached contents for later retrieval
|
13
|
+
# Must be implemented by all CacheStore subclasses
|
14
|
+
#
|
15
|
+
# Note: cache contents contain binary data.
|
16
|
+
#
|
17
|
+
# @param key [String] The key to store the contents under
|
18
|
+
# @param version [String] The current sass version.
|
19
|
+
# Cached contents must not be retrieved across different versions of sass.
|
20
|
+
# @param sha [String] The sha of the sass source.
|
21
|
+
# Cached contents must not be retrieved if the sha has changed.
|
22
|
+
# @param contents [String] The contents to store.
|
23
|
+
def _store(key, version, sha, contents)
|
24
|
+
raise "#{self.class} must implement #_store."
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retrieved cached contents.
|
28
|
+
# Must be implemented by all subclasses.
|
29
|
+
#
|
30
|
+
# Note: if the key exists but the sha or version have changed,
|
31
|
+
# then the key may be deleted by the cache store, if it wants to do so.
|
32
|
+
#
|
33
|
+
# @param key [String] The key to retrieve
|
34
|
+
# @param version [String] The current sass version.
|
35
|
+
# Cached contents must not be retrieved across different versions of sass.
|
36
|
+
# @param sha [String] The sha of the sass source.
|
37
|
+
# Cached contents must not be retrieved if the sha has changed.
|
38
|
+
# @return [String] The contents that were previously stored.
|
39
|
+
# @return [NilClass] when the cache key is not found or the version or sha have changed.
|
40
|
+
def _retrieve(key, version, sha)
|
41
|
+
raise "#{self.class} must implement #_retrieve."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Store a {Sass::Tree::RootNode}.
|
45
|
+
#
|
46
|
+
# @param key [String] The key to store it under.
|
47
|
+
# @param sha [String] The checksum for the contents that are being stored.
|
48
|
+
# @param root [Sass::Tree::RootNode] The root of the tree to be stored.
|
49
|
+
def store(key, sha, root)
|
50
|
+
orig_options = root.options
|
51
|
+
begin
|
52
|
+
_store(key, Sass::VERSION, sha, Haml::Util.dump(root))
|
53
|
+
ensure
|
54
|
+
root.options = orig_options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Retrieve a {Sass::Tree::RootNode}.
|
59
|
+
#
|
60
|
+
# @param key [String] The key the root element was stored under.
|
61
|
+
# @param sha [String] The checksum of the root element's content.
|
62
|
+
# @return [Sass::Tree::RootNode] The root node.
|
63
|
+
def retrieve(key, sha)
|
64
|
+
contents = _retrieve(key, Sass::VERSION, sha)
|
65
|
+
Haml::Util.load(contents) if contents
|
66
|
+
rescue EOFError, TypeError, ArgumentError => e
|
67
|
+
raise
|
68
|
+
Haml::Util.haml_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the key for the sass file.
|
72
|
+
#
|
73
|
+
# The `(sass_dirname, sass_basename)` pair
|
74
|
+
# should uniquely identify the Sass document,
|
75
|
+
# but otherwise there are no restrictions on their content.
|
76
|
+
#
|
77
|
+
# @param sass_dirname [String]
|
78
|
+
# The fully-expanded location of the Sass file.
|
79
|
+
# This corresponds to the directory name on a filesystem.
|
80
|
+
# @param sass_basename [String] The name of the Sass file that is being referenced.
|
81
|
+
# This corresponds to the basename on a filesystem.
|
82
|
+
def key(sass_dirname, sass_basename)
|
83
|
+
dir = Digest::SHA1.hexdigest(sass_dirname)
|
84
|
+
filename = "#{sass_basename}c"
|
85
|
+
"#{dir}/#{filename}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# A backend for the Sass cache using the filesystem.
|
90
|
+
class FileCacheStore < CacheStore
|
91
|
+
# The directory where the cached files will be stored.
|
92
|
+
#
|
93
|
+
# @return [String]
|
94
|
+
attr_accessor :cache_location
|
95
|
+
|
96
|
+
# Create a new FileCacheStore.
|
97
|
+
#
|
98
|
+
# @param cache_location [String] see \{#cache\_location}
|
99
|
+
def initialize(cache_location)
|
100
|
+
@cache_location = cache_location
|
101
|
+
end
|
102
|
+
|
103
|
+
# @see {CacheStore#\_retrieve\_}
|
104
|
+
def _retrieve(key, version, sha)
|
105
|
+
return unless File.readable?(path_to(key))
|
106
|
+
contents = nil
|
107
|
+
File.open(path_to(key), "rb") do |f|
|
108
|
+
if f.readline("\n").strip == version && f.readline("\n").strip == sha
|
109
|
+
return f.read
|
110
|
+
end
|
111
|
+
end
|
112
|
+
File.unlink path_to(key)
|
113
|
+
nil
|
114
|
+
rescue EOFError, TypeError, ArgumentError => e
|
115
|
+
Haml::Util.haml_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
|
116
|
+
end
|
117
|
+
|
118
|
+
# @see {CacheStore#\_store\_}
|
119
|
+
def _store(key, version, sha, contents)
|
120
|
+
return unless File.writable?(File.dirname(@cache_location))
|
121
|
+
return if File.exists?(@cache_location) && !File.writable?(@cache_location)
|
122
|
+
compiled_filename = path_to(key)
|
123
|
+
return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
|
124
|
+
return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
|
125
|
+
FileUtils.mkdir_p(File.dirname(compiled_filename))
|
126
|
+
File.open(compiled_filename, "wb") do |f|
|
127
|
+
f.puts(version)
|
128
|
+
f.puts(sha)
|
129
|
+
f.write(contents)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# Returns the path to a file for the given key.
|
136
|
+
#
|
137
|
+
# @param key [String]
|
138
|
+
# @return [String] The path to the cache file.
|
139
|
+
def path_to(key)
|
140
|
+
File.join(cache_location, key)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# A backend for the Sass cache using in-process memory.
|
145
|
+
class InMemoryCacheStore < CacheStore
|
146
|
+
# Since the {InMemoryCacheStore} is stored in the Sass tree's options hash,
|
147
|
+
# when the options get serialized as part of serializing the tree,
|
148
|
+
# you get crazy exponential growth in the size of the cached objects
|
149
|
+
# unless you don't dump the cache.
|
150
|
+
#
|
151
|
+
# @private
|
152
|
+
def _dump(depth)
|
153
|
+
""
|
154
|
+
end
|
155
|
+
|
156
|
+
# If we deserialize this class, just make a new empty one.
|
157
|
+
#
|
158
|
+
# @private
|
159
|
+
def self._load(repr)
|
160
|
+
InMemoryCacheStore.new
|
161
|
+
end
|
162
|
+
|
163
|
+
# Create a new, empty cache store.
|
164
|
+
def initialize
|
165
|
+
@contents = {}
|
166
|
+
end
|
167
|
+
|
168
|
+
# @see CacheStore#_retrieve
|
169
|
+
def _retrieve(key, version, sha)
|
170
|
+
if @contents.has_key?(key)
|
171
|
+
return unless @contents[key][:version] == version
|
172
|
+
return unless @contents[key][:sha] == sha
|
173
|
+
return @contents[key][:contents]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# @see CacheStore#_store
|
178
|
+
def _store(key, version, sha, contents)
|
179
|
+
@contents[key] = {
|
180
|
+
:version => version,
|
181
|
+
:sha => sha,
|
182
|
+
:contents => contents
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
# Destructively clear the cache.
|
187
|
+
def reset!
|
188
|
+
@contents = {}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Doesn't store anything, but records what things it should have stored.
|
193
|
+
# This doesn't currently have any use except for testing and debugging.
|
194
|
+
#
|
195
|
+
# @private
|
196
|
+
class NullCacheStore < CacheStore
|
197
|
+
def initialize
|
198
|
+
@keys = {}
|
199
|
+
end
|
200
|
+
|
201
|
+
def _retrieve(key, version, sha)
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def _store(key, version, sha, contents)
|
206
|
+
@keys[key] = true
|
207
|
+
end
|
208
|
+
|
209
|
+
def was_set?(key)
|
210
|
+
@keys[key]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
data/lib/sass/callbacks.rb
CHANGED
@@ -23,8 +23,22 @@ module Sass
|
|
23
23
|
# m.on_string_munged {|str, res| puts "#{str} was munged into #{res}!"}
|
24
24
|
# m.munge "bar" #=> bar was munged into bbaarr!
|
25
25
|
module Callbacks
|
26
|
+
# Automatically includes {InstanceMethods}
|
27
|
+
# when something extends this module.
|
28
|
+
#
|
29
|
+
# @param base [Module]
|
30
|
+
def self.extended(base)
|
31
|
+
base.send(:include, InstanceMethods)
|
32
|
+
end
|
26
33
|
protected
|
27
34
|
|
35
|
+
module InstanceMethods
|
36
|
+
# Removes all callbacks registered against this object.
|
37
|
+
def clear_callbacks!
|
38
|
+
@_sass_callbacks = {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
28
42
|
# Define a callback with the given name.
|
29
43
|
# This will define an `on_#{name}` method
|
30
44
|
# that registers a block,
|
data/lib/sass/engine.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'strscan'
|
2
2
|
require 'digest/sha1'
|
3
|
+
require 'sass/cache_store'
|
3
4
|
require 'sass/tree/node'
|
4
5
|
require 'sass/tree/root_node'
|
5
6
|
require 'sass/tree/rule_node'
|
@@ -21,10 +22,11 @@ require 'sass/environment'
|
|
21
22
|
require 'sass/script'
|
22
23
|
require 'sass/scss'
|
23
24
|
require 'sass/error'
|
24
|
-
require 'sass/
|
25
|
+
require 'sass/importers'
|
25
26
|
require 'haml/shared'
|
26
27
|
|
27
28
|
module Sass
|
29
|
+
|
28
30
|
# A Sass mixin.
|
29
31
|
#
|
30
32
|
# `name`: `String`
|
@@ -130,30 +132,94 @@ module Sass
|
|
130
132
|
:cache => true,
|
131
133
|
:cache_location => './.sass-cache',
|
132
134
|
:syntax => :sass,
|
135
|
+
:filesystem_importer => Sass::Importers::Filesystem
|
133
136
|
}.freeze
|
134
137
|
|
138
|
+
# Converts a Sass options hash into a standard form, filling in
|
139
|
+
# default values and resolving aliases.
|
140
|
+
#
|
141
|
+
# @param options [{Symbol => Object}] The options hash;
|
142
|
+
# see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
|
143
|
+
# @return [{Symbol => Object}] The normalized options hash.
|
144
|
+
# @private
|
145
|
+
def self.normalize_options(options)
|
146
|
+
options = DEFAULT_OPTIONS.merge(options.reject {|k, v| v.nil?})
|
147
|
+
|
148
|
+
# If the `:filename` option is passed in without an importer,
|
149
|
+
# assume it's using the default filesystem importer.
|
150
|
+
options[:importer] ||= options[:filesystem_importer].new(".") if options[:filename]
|
151
|
+
|
152
|
+
options[:cache_store] ||= Sass::FileCacheStore.new(options[:cache_location])
|
153
|
+
# Support both, because the docs said one and the other actually worked
|
154
|
+
# for quite a long time.
|
155
|
+
options[:line_comments] ||= options[:line_numbers]
|
156
|
+
|
157
|
+
options[:load_paths] = options[:load_paths].map do |p|
|
158
|
+
next p unless p.is_a?(String)
|
159
|
+
options[:filesystem_importer].new(p)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Backwards compatibility
|
163
|
+
options[:property_syntax] ||= options[:attribute_syntax]
|
164
|
+
case options[:property_syntax]
|
165
|
+
when :alternate; options[:property_syntax] = :new
|
166
|
+
when :normal; options[:property_syntax] = :old
|
167
|
+
end
|
168
|
+
|
169
|
+
options
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the {Sass::Engine} for the given file.
|
173
|
+
# This is preferable to Sass::Engine.new when reading from a file
|
174
|
+
# because it properly sets up the Engine's metadata,
|
175
|
+
# enables parse-tree caching,
|
176
|
+
# and infers the syntax from the filename.
|
177
|
+
#
|
178
|
+
# @param filename [String] The path to the Sass or SCSS file
|
179
|
+
# @param options [{Symbol => Object}] The options hash;
|
180
|
+
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
181
|
+
# @return [Sass::Engine] The Engine for the given Sass or SCSS file.
|
182
|
+
# @raise [Sass::SyntaxError] if there's an error in the document.
|
183
|
+
def self.for_file(filename, options)
|
184
|
+
had_syntax = options[:syntax]
|
185
|
+
|
186
|
+
if had_syntax
|
187
|
+
# Use what was explicitly specificed
|
188
|
+
elsif filename =~ /\.scss$/
|
189
|
+
options.merge!(:syntax => :scss)
|
190
|
+
elsif filename =~ /\.sass$/
|
191
|
+
options.merge!(:syntax => :sass)
|
192
|
+
end
|
193
|
+
|
194
|
+
Sass::Engine.new(File.read(filename), options.merge(:filename => filename))
|
195
|
+
end
|
196
|
+
|
197
|
+
# The options for the Sass engine.
|
198
|
+
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
199
|
+
#
|
200
|
+
# @return [{Symbol => Object}]
|
201
|
+
attr_reader :options
|
202
|
+
|
203
|
+
# Creates a new Engine. Note that Engine should only be used directly
|
204
|
+
# when compiling in-memory Sass code.
|
205
|
+
# If you're compiling a single Sass file from the filesystem,
|
206
|
+
# use \{Sass::Engine.for\_file}.
|
207
|
+
# If you're compiling multiple files from the filesystem,
|
208
|
+
# use {Sass::Plugin.
|
209
|
+
#
|
135
210
|
# @param template [String] The Sass template.
|
136
211
|
# This template can be encoded using any encoding
|
137
212
|
# that can be converted to Unicode.
|
138
213
|
# If the template contains an `@charset` declaration,
|
139
214
|
# that overrides the Ruby encoding
|
140
215
|
# (see {file:SASS_REFERENCE.md#encodings the encoding documentation})
|
141
|
-
# @param options [{Symbol => Object}] An options hash
|
142
|
-
#
|
216
|
+
# @param options [{Symbol => Object}] An options hash.
|
217
|
+
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
218
|
+
# @see {Sass::Engine.for_file}
|
219
|
+
# @see {Sass::Plugin}
|
143
220
|
def initialize(template, options={})
|
144
|
-
@options =
|
221
|
+
@options = self.class.normalize_options(options)
|
145
222
|
@template = template
|
146
|
-
|
147
|
-
# Support both, because the docs said one and the other actually worked
|
148
|
-
# for quite a long time.
|
149
|
-
@options[:line_comments] ||= @options[:line_numbers]
|
150
|
-
|
151
|
-
# Backwards compatibility
|
152
|
-
@options[:property_syntax] ||= @options[:attribute_syntax]
|
153
|
-
case @options[:property_syntax]
|
154
|
-
when :alternate; @options[:property_syntax] = :new
|
155
|
-
when :normal; @options[:property_syntax] = :old
|
156
|
-
end
|
157
223
|
end
|
158
224
|
|
159
225
|
# Render the template to CSS.
|
@@ -199,6 +265,18 @@ module Sass
|
|
199
265
|
end
|
200
266
|
|
201
267
|
def _to_tree
|
268
|
+
if (@options[:cache] || @options[:read_cache]) &&
|
269
|
+
@options[:filename] && @options[:importer]
|
270
|
+
key = sassc_key
|
271
|
+
sha = Digest::SHA1.hexdigest(@template)
|
272
|
+
|
273
|
+
if root = @options[:cache_store].retrieve(key, sha)
|
274
|
+
@options = root.options.merge(@options)
|
275
|
+
root.options = @options
|
276
|
+
return root
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
202
280
|
check_encoding!
|
203
281
|
|
204
282
|
if @options[:syntax] == :scss
|
@@ -209,6 +287,7 @@ module Sass
|
|
209
287
|
end
|
210
288
|
|
211
289
|
root.options = @options
|
290
|
+
@options[:cache_store].store(key, sha, root) if @options[:cache] && key && sha
|
212
291
|
root
|
213
292
|
rescue SyntaxError => e
|
214
293
|
e.modify_backtrace(:filename => @options[:filename], :line => @line)
|
@@ -216,6 +295,10 @@ module Sass
|
|
216
295
|
raise e
|
217
296
|
end
|
218
297
|
|
298
|
+
def sassc_key
|
299
|
+
@options[:cache_store].key(*@options[:importer].key(@options[:filename], @options))
|
300
|
+
end
|
301
|
+
|
219
302
|
def check_encoding!
|
220
303
|
return if @checked_encoding
|
221
304
|
@checked_encoding = true
|
data/lib/sass/error.rb
CHANGED
@@ -125,6 +125,7 @@ module Sass
|
|
125
125
|
# @return [Array<String>]
|
126
126
|
def backtrace
|
127
127
|
return nil if super.nil?
|
128
|
+
return super if sass_backtrace.all? {|h| h.empty?}
|
128
129
|
sass_backtrace.map do |h|
|
129
130
|
"#{h[:filename] || "(sass)"}:#{h[:line]}" +
|
130
131
|
(h[:mixin] ? ":in `#{h[:mixin]}'" : "")
|
@@ -178,7 +179,9 @@ END
|
|
178
179
|
private
|
179
180
|
|
180
181
|
def header_string(e, options)
|
181
|
-
|
182
|
+
unless e.is_a?(Sass::SyntaxError) && e.sass_line && e.sass_template
|
183
|
+
return "#{e.class}: #{e.message}"
|
184
|
+
end
|
182
185
|
|
183
186
|
line_offset = options[:line] || 1
|
184
187
|
line_num = e.sass_line + 1 - line_offset
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Sass
|
2
|
+
module Importers
|
3
|
+
# The abstract base class for Sass importers.
|
4
|
+
# All importers should inherit from this.
|
5
|
+
#
|
6
|
+
# At the most basic level, an importer is given a string
|
7
|
+
# and must return a {Sass::Engine} containing some Sass code.
|
8
|
+
# This string can be interpreted however the importer wants;
|
9
|
+
# however, subclasses are encouraged to use the URI format
|
10
|
+
# for pathnames.
|
11
|
+
#
|
12
|
+
# Importers that have some notion of "relative imports"
|
13
|
+
# should take a single load path in their constructor,
|
14
|
+
# and interpret paths as relative to that.
|
15
|
+
# They should also implement the \{#find\_relative} method.
|
16
|
+
#
|
17
|
+
# Importers should be serializable via `Marshal.dump`.
|
18
|
+
# In addition to the standard `_dump` and `_load` methods,
|
19
|
+
# importers can define `_before_dump`, `_after_dump`, `_around_dump`,
|
20
|
+
# and `_after_load` methods as per {Haml::Util#dump} and {Haml::Util#load}.
|
21
|
+
#
|
22
|
+
# @abstract
|
23
|
+
class Base
|
24
|
+
|
25
|
+
# Find a Sass file relative to another file.
|
26
|
+
# Importers without a notion of "relative paths"
|
27
|
+
# should just return nil here.
|
28
|
+
#
|
29
|
+
# If the importer does have a notion of "relative paths",
|
30
|
+
# it should ignore its load path during this method.
|
31
|
+
#
|
32
|
+
# See \{#find} for important information on how this method should behave.
|
33
|
+
#
|
34
|
+
# The `:filename` option passed to the returned {Sass::Engine}
|
35
|
+
# should be of a format that could be passed to \{#find}.
|
36
|
+
#
|
37
|
+
# @param uri [String] The URI to import. This is not necessarily relative,
|
38
|
+
# but this method should only return true if it is.
|
39
|
+
# @param base [String] The base filename. If `uri` is relative,
|
40
|
+
# it should be interpreted as relative to `base`.
|
41
|
+
# `base` is guaranteed to be in a format importable by this importer.
|
42
|
+
# @param options [{Symbol => Object}] Options for the Sass file
|
43
|
+
# containing the `@import` that's currently being resolved.
|
44
|
+
# @return [Sass::Engine, nil] An Engine containing the imported file,
|
45
|
+
# or nil if it couldn't be found or was in the wrong format.
|
46
|
+
def find_relative(uri, base, options)
|
47
|
+
Haml::Util.abstract(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Find a Sass file, if it exists.
|
51
|
+
#
|
52
|
+
# This is the primary entry point of the Importer.
|
53
|
+
# It corresponds directly to an `@import` statement in Sass.
|
54
|
+
# It should do three basic things:
|
55
|
+
#
|
56
|
+
# * Determine if the URI is in this importer's format.
|
57
|
+
# If not, return nil.
|
58
|
+
# * Determine if the file indicated by the URI actually exists and is readable.
|
59
|
+
# If not, return nil.
|
60
|
+
# * Read the file and place the contents in a {Sass::Engine}.
|
61
|
+
# Return that engine.
|
62
|
+
#
|
63
|
+
# If this importer's format allows for file extensions,
|
64
|
+
# it should treat them the same way as the default {Filesystem} importer.
|
65
|
+
# If the URI explicitly has a `.sass` or `.scss` filename,
|
66
|
+
# the importer should look for that exact file
|
67
|
+
# and import it as the syntax indicated.
|
68
|
+
# If it doesn't exist, the importer should return nil.
|
69
|
+
#
|
70
|
+
# If the URI doesn't have either of these extensions,
|
71
|
+
# the importer should look for files with the extensions.
|
72
|
+
# If no such files exist, it should return nil.
|
73
|
+
#
|
74
|
+
# The {Sass::Engine} to be returned should be passed `options`,
|
75
|
+
# with a few modifications. `:filename` and `:syntax` should be set appropriately,
|
76
|
+
# and `:importer` should be set to this importer.
|
77
|
+
#
|
78
|
+
# @param uri [String] The URI to import.
|
79
|
+
# @param options [{Symbol => Object}] Options for the Sass file
|
80
|
+
# containing the `@import` that's currently being resolved.
|
81
|
+
# This is safe for subclasses to modify destructively.
|
82
|
+
# Callers should only pass in a value they don't mind being destructively modified.
|
83
|
+
# @return [Sass::Engine, nil] An Engine containing the imported file,
|
84
|
+
# or nil if it couldn't be found or was in the wrong format.
|
85
|
+
def find(uri, options)
|
86
|
+
Haml::Util.abstract(self)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the time the given Sass file was last modified.
|
90
|
+
#
|
91
|
+
# If the given file has been deleted or the time can't be accessed
|
92
|
+
# for some other reason, this should return nil.
|
93
|
+
#
|
94
|
+
# @param uri [String] The URI of the file to check.
|
95
|
+
# Comes from a `:filename` option set on an engine returned by this importer.
|
96
|
+
# @param options [{Symbol => Objet}] Options for the Sass file
|
97
|
+
# containing the `@import` currently being checked.
|
98
|
+
# @return [Time, nil]
|
99
|
+
def mtime(uri, options)
|
100
|
+
Haml::Util.abstract(self)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get the cache key pair for the given Sass URI.
|
104
|
+
# The URI need not be checked for validity.
|
105
|
+
#
|
106
|
+
# The only strict requirement is that the returned pair of strings
|
107
|
+
# uniquely identify the file at the given URI.
|
108
|
+
# However, the first component generally corresponds roughly to the directory,
|
109
|
+
# and the second to the basename, of the URI.
|
110
|
+
#
|
111
|
+
# Note that keys must be unique *across importers*.
|
112
|
+
# Thus it's probably a good idea to include the importer name
|
113
|
+
# at the beginning of the first component.
|
114
|
+
#
|
115
|
+
# @param uri [String] A URI known to be valid for this importer.
|
116
|
+
# @param options [{Symbol => Object}] Options for the Sass file
|
117
|
+
# containing the `@import` currently being checked.
|
118
|
+
# @return [(String, String)] The key pair which uniquely identifies
|
119
|
+
# the file at the given URI.
|
120
|
+
def key(uri, options)
|
121
|
+
Haml::Util.abstract(self)
|
122
|
+
end
|
123
|
+
|
124
|
+
# A string representation of the importer.
|
125
|
+
# Should be overridden by subclasses.
|
126
|
+
#
|
127
|
+
# This is used to help debugging,
|
128
|
+
# and should usually just show the load path encapsulated by this importer.
|
129
|
+
#
|
130
|
+
# @return [String]
|
131
|
+
def to_s
|
132
|
+
Haml::Util.abstract(self)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
|