haml-edge 3.1.73 → 3.1.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|