haml 1.7.2 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/README +17 -9
- data/Rakefile +12 -4
- data/VERSION +1 -1
- data/init.rb +1 -6
- data/lib/haml.rb +65 -7
- data/lib/haml/buffer.rb +49 -84
- data/lib/haml/engine.rb +155 -797
- data/lib/haml/error.rb +3 -33
- data/lib/haml/exec.rb +86 -65
- data/lib/haml/filters.rb +57 -27
- data/lib/haml/helpers.rb +52 -9
- data/lib/haml/helpers/action_view_mods.rb +1 -1
- data/lib/haml/html.rb +20 -5
- data/lib/haml/precompiler.rb +671 -0
- data/lib/haml/template.rb +20 -73
- data/lib/haml/template/patch.rb +51 -0
- data/lib/haml/template/plugin.rb +21 -0
- data/lib/sass.rb +78 -3
- data/lib/sass/constant.rb +45 -19
- data/lib/sass/constant.rb.rej +42 -0
- data/lib/sass/constant/string.rb +4 -0
- data/lib/sass/css.rb +162 -39
- data/lib/sass/engine.rb +38 -14
- data/lib/sass/plugin.rb +79 -44
- data/lib/sass/tree/attr_node.rb +12 -11
- data/lib/sass/tree/comment_node.rb +9 -3
- data/lib/sass/tree/directive_node.rb +51 -0
- data/lib/sass/tree/node.rb +13 -6
- data/lib/sass/tree/rule_node.rb +34 -12
- data/test/benchmark.rb +85 -52
- data/test/haml/engine_test.rb +172 -84
- data/test/haml/helper_test.rb +31 -3
- data/test/haml/html2haml_test.rb +60 -0
- data/test/haml/markaby/standard.mab +52 -0
- data/test/haml/results/eval_suppressed.xhtml +4 -1
- data/test/haml/results/helpers.xhtml +15 -4
- data/test/haml/results/just_stuff.xhtml +9 -1
- data/test/haml/results/standard.xhtml +0 -1
- data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
- data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
- data/test/haml/rhtml/action_view.rhtml +62 -0
- data/test/haml/rhtml/standard.rhtml +0 -1
- data/test/haml/template_test.rb +41 -21
- data/test/haml/templates/_av_partial_1.haml +9 -0
- data/test/haml/templates/_av_partial_2.haml +5 -0
- data/test/haml/templates/action_view.haml +47 -0
- data/test/haml/templates/eval_suppressed.haml +1 -0
- data/test/haml/templates/helpers.haml +9 -3
- data/test/haml/templates/just_stuff.haml +10 -1
- data/test/haml/templates/partials.haml +1 -1
- data/test/haml/templates/standard.haml +0 -1
- data/test/profile.rb +2 -2
- data/test/sass/engine_test.rb +113 -3
- data/test/sass/engine_test.rb.rej +18 -0
- data/test/sass/plugin_test.rb +34 -11
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +1 -1
- data/test/sass/results/compressed.css +1 -0
- data/test/sass/results/constants.css +3 -1
- data/test/sass/results/expanded.css +2 -1
- data/test/sass/results/import.css +2 -0
- data/test/sass/results/nested.css +2 -1
- data/test/sass/templates/_partial.sass +2 -0
- data/test/sass/templates/compact.sass +2 -0
- data/test/sass/templates/complex.sass +1 -0
- data/test/sass/templates/compressed.sass +15 -0
- data/test/sass/templates/constants.sass +9 -0
- data/test/sass/templates/expanded.sass +2 -0
- data/test/sass/templates/import.sass +1 -1
- data/test/sass/templates/nested.sass +2 -0
- metadata +22 -2
@@ -0,0 +1,42 @@
|
|
1
|
+
***************
|
2
|
+
*** 106,121 ****
|
3
|
+
end
|
4
|
+
|
5
|
+
# Time for a unary minus!
|
6
|
+
- if negative_okay && symbol == :minus
|
7
|
+
- negative_okay = true
|
8
|
+
to_return << :neg
|
9
|
+
next
|
10
|
+
end
|
11
|
+
|
12
|
+
# Are we looking at an operator?
|
13
|
+
if symbol && (str.empty? || symbol != :mod)
|
14
|
+
str = reset_str.call
|
15
|
+
- negative_okay = true
|
16
|
+
to_return << symbol
|
17
|
+
next
|
18
|
+
end
|
19
|
+
--- 107,129 ----
|
20
|
+
end
|
21
|
+
|
22
|
+
# Time for a unary minus!
|
23
|
+
+ if beginning_of_token && symbol == :minus
|
24
|
+
+ beginning_of_token = true
|
25
|
+
to_return << :neg
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
+ # Is this a constant?
|
30
|
+
+ if beginning_of_token && symbol == :const
|
31
|
+
+ beginning_of_token = true
|
32
|
+
+ to_return << :const
|
33
|
+
+ next
|
34
|
+
+ end
|
35
|
+
+
|
36
|
+
# Are we looking at an operator?
|
37
|
+
if symbol && (str.empty? || symbol != :mod)
|
38
|
+
str = reset_str.call
|
39
|
+
+ beginning_of_token = true
|
40
|
+
to_return << symbol
|
41
|
+
next
|
42
|
+
end
|
data/lib/sass/constant/string.rb
CHANGED
data/lib/sass/css.rb
CHANGED
@@ -41,20 +41,52 @@ module Sass
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
# This class is based on the Ruby 1.9 ordered hashes.
|
46
|
+
# It keeps the semantics and most of the efficiency of normal hashes
|
47
|
+
# while also keeping track of the order in which elements were set.
|
48
|
+
class OrderedHash
|
49
|
+
Node = Struct.new('Node', :key, :value, :next)
|
50
|
+
include Enumerable
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@hash = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](key)
|
57
|
+
@hash[key] && @hash[key].value
|
58
|
+
end
|
59
|
+
|
60
|
+
def []=(key, value)
|
61
|
+
node = Node.new(key, value, nil)
|
62
|
+
if @first.nil?
|
63
|
+
@first = @last = node
|
64
|
+
else
|
65
|
+
@last.next = node
|
66
|
+
@last = node
|
67
|
+
end
|
68
|
+
@hash[key] = node
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
def each
|
73
|
+
return unless @first
|
74
|
+
yield [@first.key, @first.value]
|
75
|
+
node = @first
|
76
|
+
yield [node.key, node.value] while node = node.next
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def values
|
81
|
+
self.map { |k, v| v }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
44
85
|
# :startdoc:
|
45
86
|
|
46
87
|
# This class contains the functionality used in the +css2sass+ utility,
|
47
88
|
# namely converting CSS documents to Sass templates.
|
48
89
|
class CSS
|
49
|
-
# :stopdoc:
|
50
|
-
|
51
|
-
# The Regexp matching a CSS rule
|
52
|
-
RULE_RE = /\s*([^\{]+)\s*\{/
|
53
|
-
|
54
|
-
# The Regexp matching a CSS attribute
|
55
|
-
ATTR_RE = /\s*[^::\{\}]+\s*:\s*[^:;\{\}]+\s*;/
|
56
|
-
|
57
|
-
# :startdoc:
|
58
90
|
|
59
91
|
# Creates a new instance of Sass::CSS that will compile the given document
|
60
92
|
# to a Sass string when +render+ is called.
|
@@ -84,9 +116,12 @@ module Sass
|
|
84
116
|
def build_tree
|
85
117
|
root = Tree::Node.new(nil)
|
86
118
|
whitespace
|
87
|
-
directives
|
88
|
-
rules
|
89
|
-
|
119
|
+
directives root
|
120
|
+
rules root
|
121
|
+
expand_commas root
|
122
|
+
nest_rules root
|
123
|
+
flatten_rules root
|
124
|
+
fold_commas root
|
90
125
|
root
|
91
126
|
end
|
92
127
|
|
@@ -131,11 +166,11 @@ module Sass
|
|
131
166
|
assert_match /:/
|
132
167
|
|
133
168
|
value = ''
|
134
|
-
while @template.scan(/[^;\s]+/)
|
169
|
+
while @template.scan(/[^;\s\}]+/)
|
135
170
|
value << @template[0] << whitespace
|
136
171
|
end
|
137
172
|
|
138
|
-
assert_match
|
173
|
+
assert_match /(;|(?=\}))/
|
139
174
|
rule << Tree::AttrNode.new(name, value, nil)
|
140
175
|
end
|
141
176
|
|
@@ -161,37 +196,125 @@ module Sass
|
|
161
196
|
whitespace
|
162
197
|
end
|
163
198
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
199
|
+
# Transform
|
200
|
+
#
|
201
|
+
# foo, bar, baz
|
202
|
+
# color: blue
|
203
|
+
#
|
204
|
+
# into
|
205
|
+
#
|
206
|
+
# foo
|
207
|
+
# color: blue
|
208
|
+
# bar
|
209
|
+
# color: blue
|
210
|
+
# baz
|
211
|
+
# color: blue
|
212
|
+
#
|
213
|
+
# Yes, this expands the amount of code,
|
214
|
+
# but it's necessary to get nesting to work properly.
|
215
|
+
def expand_commas(root)
|
216
|
+
root.children.map! do |child|
|
217
|
+
next child unless Tree::RuleNode === child && child.rule.include?(',')
|
218
|
+
child.rule.split(',').map do |rule|
|
219
|
+
node = Tree::RuleNode.new(rule, nil)
|
220
|
+
node.children = child.children
|
221
|
+
node
|
222
|
+
end
|
223
|
+
end
|
224
|
+
root.children.flatten!
|
225
|
+
end
|
226
|
+
|
227
|
+
# Nest rules so that
|
228
|
+
#
|
229
|
+
# foo
|
230
|
+
# color: green
|
231
|
+
# foo bar
|
232
|
+
# color: red
|
233
|
+
# foo baz
|
234
|
+
# color: blue
|
235
|
+
#
|
236
|
+
# becomes
|
237
|
+
#
|
238
|
+
# foo
|
239
|
+
# color: green
|
240
|
+
# bar
|
241
|
+
# color: red
|
242
|
+
# baz
|
243
|
+
# color: blue
|
244
|
+
#
|
245
|
+
def nest_rules(root)
|
246
|
+
rules = OrderedHash.new
|
247
|
+
root.children.select { |c| Tree::RuleNode === c }.each do |child|
|
248
|
+
root.children.delete child
|
249
|
+
first, rest = child.rule.split(' ', 2)
|
250
|
+
rules[first] ||= Tree::RuleNode.new(first, nil)
|
251
|
+
if rest
|
252
|
+
child.rule = rest
|
253
|
+
rules[first] << child
|
170
254
|
else
|
171
|
-
|
255
|
+
rules[first].children += child.children
|
172
256
|
end
|
173
257
|
end
|
174
258
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
259
|
+
rules.values.each { |v| nest_rules(v) }
|
260
|
+
root.children += rules.values
|
261
|
+
end
|
262
|
+
|
263
|
+
# Flatten rules so that
|
264
|
+
#
|
265
|
+
# foo
|
266
|
+
# bar
|
267
|
+
# baz
|
268
|
+
# color: red
|
269
|
+
#
|
270
|
+
# becomes
|
271
|
+
#
|
272
|
+
# foo bar baz
|
273
|
+
# color: red
|
274
|
+
#
|
275
|
+
def flatten_rules(root)
|
276
|
+
root.children.each { |child| flatten_rule(child) if child.is_a?(Tree::RuleNode) }
|
277
|
+
end
|
278
|
+
|
279
|
+
def flatten_rule(rule)
|
280
|
+
while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
|
281
|
+
child = rule.children.first
|
282
|
+
rule.rule = "#{rule.rule} #{child.rule}"
|
283
|
+
rule.children = child.children
|
284
|
+
end
|
285
|
+
|
286
|
+
flatten_rules(rule)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Transform
|
290
|
+
#
|
291
|
+
# foo
|
292
|
+
# bar
|
293
|
+
# color: blue
|
294
|
+
# baz
|
295
|
+
# color: blue
|
296
|
+
#
|
297
|
+
# into
|
298
|
+
#
|
299
|
+
# foo
|
300
|
+
# bar, baz
|
301
|
+
# color: blue
|
302
|
+
#
|
303
|
+
def fold_commas(root)
|
304
|
+
prev_rule = nil
|
305
|
+
root.children.map! do |child|
|
306
|
+
next child unless Tree::RuleNode === child
|
307
|
+
|
308
|
+
if prev_rule && prev_rule.children == child.children
|
309
|
+
prev_rule.rule << ", #{child.rule}"
|
310
|
+
next nil
|
193
311
|
end
|
312
|
+
|
313
|
+
fold_commas(child)
|
314
|
+
prev_rule = child
|
315
|
+
child
|
194
316
|
end
|
317
|
+
root.children.compact!
|
195
318
|
end
|
196
319
|
end
|
197
320
|
end
|
data/lib/sass/engine.rb
CHANGED
@@ -3,6 +3,7 @@ require 'sass/tree/value_node'
|
|
3
3
|
require 'sass/tree/rule_node'
|
4
4
|
require 'sass/tree/comment_node'
|
5
5
|
require 'sass/tree/attr_node'
|
6
|
+
require 'sass/tree/directive_node'
|
6
7
|
require 'sass/constant'
|
7
8
|
require 'sass/error'
|
8
9
|
require 'haml/util'
|
@@ -38,6 +39,9 @@ module Sass
|
|
38
39
|
|
39
40
|
# The character used to denote a compiler directive.
|
40
41
|
DIRECTIVE_CHAR = ?@
|
42
|
+
|
43
|
+
# Designates a non-parsed rule.
|
44
|
+
ESCAPE_CHAR = ?\\
|
41
45
|
|
42
46
|
# The regex that matches and extracts data from
|
43
47
|
# attributes of the form <tt>:name attr</tt>.
|
@@ -69,7 +73,7 @@ module Sass
|
|
69
73
|
}.merge! options
|
70
74
|
@template = template.split(/\n\r|\n/)
|
71
75
|
@lines = []
|
72
|
-
@constants = {}
|
76
|
+
@constants = {"important" => "!important"}
|
73
77
|
end
|
74
78
|
|
75
79
|
# Processes the template and returns the result as a string.
|
@@ -232,6 +236,8 @@ module Sass
|
|
232
236
|
parse_comment(line)
|
233
237
|
when DIRECTIVE_CHAR
|
234
238
|
parse_directive(line)
|
239
|
+
when ESCAPE_CHAR
|
240
|
+
Tree::RuleNode.new(line[1..-1], @options[:style])
|
235
241
|
else
|
236
242
|
if line =~ ATTRIBUTE_ALTERNATE_MATCHER
|
237
243
|
parse_attribute(line, ATTRIBUTE_ALTERNATE)
|
@@ -242,6 +248,14 @@ module Sass
|
|
242
248
|
end
|
243
249
|
|
244
250
|
def parse_attribute(line, attribute_regx)
|
251
|
+
if @options[:attribute_syntax] == :normal &&
|
252
|
+
attribute_regx == ATTRIBUTE_ALTERNATE
|
253
|
+
raise SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
|
254
|
+
elsif @options[:attribute_syntax] == :alternate &&
|
255
|
+
attribute_regx == ATTRIBUTE
|
256
|
+
raise SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
|
257
|
+
end
|
258
|
+
|
245
259
|
name, eq, value = line.scan(attribute_regx)[0]
|
246
260
|
|
247
261
|
if name.nil? || value.nil?
|
@@ -281,7 +295,7 @@ module Sass
|
|
281
295
|
when "import"
|
282
296
|
import(value)
|
283
297
|
else
|
284
|
-
|
298
|
+
Tree::DirectiveNode.new(line, @options[:style])
|
285
299
|
end
|
286
300
|
end
|
287
301
|
|
@@ -290,7 +304,13 @@ module Sass
|
|
290
304
|
|
291
305
|
files.split(/,\s*/).each do |filename|
|
292
306
|
engine = nil
|
293
|
-
|
307
|
+
|
308
|
+
begin
|
309
|
+
filename = self.class.find_file_to_import(filename, @options[:load_paths])
|
310
|
+
rescue Exception => e
|
311
|
+
raise SyntaxError.new(e.message, @line)
|
312
|
+
end
|
313
|
+
|
294
314
|
if filename =~ /\.css$/
|
295
315
|
nodes << Tree::ValueNode.new("@import url(#{filename});", @options[:style])
|
296
316
|
else
|
@@ -319,10 +339,9 @@ module Sass
|
|
319
339
|
nodes
|
320
340
|
end
|
321
341
|
|
322
|
-
def find_file_to_import(filename)
|
342
|
+
def self.find_file_to_import(filename, load_paths)
|
323
343
|
was_sass = false
|
324
344
|
original_filename = filename
|
325
|
-
new_filename = nil
|
326
345
|
|
327
346
|
if filename[-5..-1] == ".sass"
|
328
347
|
filename = filename[0...-5]
|
@@ -331,18 +350,11 @@ module Sass
|
|
331
350
|
return filename
|
332
351
|
end
|
333
352
|
|
334
|
-
|
335
|
-
full_path = File.join(path, filename) + '.sass'
|
336
|
-
|
337
|
-
if File.readable?(full_path)
|
338
|
-
new_filename = full_path
|
339
|
-
break
|
340
|
-
end
|
341
|
-
end
|
353
|
+
new_filename = find_full_path("#{filename}.sass", load_paths)
|
342
354
|
|
343
355
|
if new_filename.nil?
|
344
356
|
if was_sass
|
345
|
-
raise
|
357
|
+
raise Exception.new("File to import not found or unreadable: #{original_filename}")
|
346
358
|
else
|
347
359
|
return filename + '.css'
|
348
360
|
end
|
@@ -350,5 +362,17 @@ module Sass
|
|
350
362
|
new_filename
|
351
363
|
end
|
352
364
|
end
|
365
|
+
|
366
|
+
def self.find_full_path(filename, load_paths)
|
367
|
+
load_paths.each do |path|
|
368
|
+
["_#{filename}", filename].each do |name|
|
369
|
+
full_path = File.join(path, name)
|
370
|
+
if File.readable?(full_path)
|
371
|
+
return full_path
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
nil
|
376
|
+
end
|
353
377
|
end
|
354
378
|
end
|
data/lib/sass/plugin.rb
CHANGED
@@ -26,62 +26,40 @@ module Sass
|
|
26
26
|
def options=(value)
|
27
27
|
@@options.merge!(value)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Checks each stylesheet in <tt>options[:css_location]</tt>
|
31
31
|
# to see if it needs updating,
|
32
32
|
# and updates it using the corresponding template
|
33
33
|
# from <tt>options[:templates]</tt>
|
34
34
|
# if it does.
|
35
35
|
def update_stylesheets
|
36
|
+
return if options[:never_update]
|
37
|
+
|
36
38
|
Dir.glob(File.join(options[:template_location], "**", "*.sass")).entries.each do |file|
|
37
|
-
|
39
|
+
|
38
40
|
# Get the relative path to the file with no extension
|
39
41
|
name = file.sub(options[:template_location] + "/", "")[0...-5]
|
40
|
-
|
41
|
-
if options[:always_update] || stylesheet_needs_update?(name)
|
42
|
+
|
43
|
+
if !forbid_update?(name) && (options[:always_update] || stylesheet_needs_update?(name))
|
42
44
|
css = css_filename(name)
|
43
45
|
File.delete(css) if File.exists?(css)
|
44
|
-
|
46
|
+
|
45
47
|
filename = template_filename(name)
|
46
48
|
l_options = @@options.dup
|
47
49
|
l_options[:filename] = filename
|
48
|
-
l_options[:load_paths] =
|
50
|
+
l_options[:load_paths] = load_paths
|
49
51
|
engine = Engine.new(File.read(filename), l_options)
|
50
|
-
begin
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
if e.is_a? Sass::SyntaxError
|
57
|
-
e_string << "\non line #{e.sass_line}"
|
58
|
-
|
59
|
-
if e.sass_filename
|
60
|
-
e_string << " of #{e.sass_filename}"
|
61
|
-
|
62
|
-
if File.exists?(e.sass_filename)
|
63
|
-
e_string << "\n\n"
|
64
|
-
|
65
|
-
min = [e.sass_line - 5, 0].max
|
66
|
-
File.read(e.sass_filename).rstrip.split("\n")[
|
67
|
-
min .. e.sass_line + 5
|
68
|
-
].each_with_index do |line, i|
|
69
|
-
e_string << "#{min + i + 1}: #{line}\n"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
result = "/*\n#{e_string}\n\nBacktrace:\n#{e.backtrace.join("\n")}\n*/"
|
75
|
-
else
|
76
|
-
result = "/* Internal stylesheet error */"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
52
|
+
result = begin
|
53
|
+
engine.render
|
54
|
+
rescue Exception => e
|
55
|
+
exception_string(e)
|
56
|
+
end
|
57
|
+
|
80
58
|
# Create any directories that might be necessary
|
81
59
|
dirs = [l_options[:css_location]]
|
82
60
|
name.split("/")[0...-1].each { |dir| dirs << "#{dirs[-1]}/#{dir}" }
|
83
61
|
dirs.each { |dir| Dir.mkdir(dir) unless File.exist?(dir) }
|
84
|
-
|
62
|
+
|
85
63
|
# Finally, write the file
|
86
64
|
File.open(css, 'w') do |file|
|
87
65
|
file.print(result)
|
@@ -89,19 +67,76 @@ module Sass
|
|
89
67
|
end
|
90
68
|
end
|
91
69
|
end
|
92
|
-
|
70
|
+
|
93
71
|
private
|
94
|
-
|
72
|
+
|
73
|
+
def load_paths
|
74
|
+
(options[:load_paths] || []) + [options[:template_location]]
|
75
|
+
end
|
76
|
+
|
77
|
+
def exception_string(e)
|
78
|
+
if options[:full_exception]
|
79
|
+
e_string = "#{e.class}: #{e.message}"
|
80
|
+
|
81
|
+
if e.is_a? Sass::SyntaxError
|
82
|
+
e_string << "\non line #{e.sass_line}"
|
83
|
+
|
84
|
+
if e.sass_filename
|
85
|
+
e_string << " of #{e.sass_filename}"
|
86
|
+
|
87
|
+
if File.exists?(e.sass_filename)
|
88
|
+
e_string << "\n\n"
|
89
|
+
|
90
|
+
min = [e.sass_line - 5, 0].max
|
91
|
+
File.read(e.sass_filename).rstrip.split("\n")[
|
92
|
+
min .. e.sass_line + 5
|
93
|
+
].each_with_index do |line, i|
|
94
|
+
e_string << "#{min + i + 1}: #{line}\n"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
"/*\n#{e_string}\n\nBacktrace:\n#{e.backtrace.join("\n")}\n*/"
|
100
|
+
else
|
101
|
+
"/* Internal stylesheet error */"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
95
105
|
def template_filename(name)
|
96
|
-
"#{
|
106
|
+
"#{options[:template_location]}/#{name}.sass"
|
97
107
|
end
|
98
|
-
|
108
|
+
|
99
109
|
def css_filename(name)
|
100
|
-
"#{
|
110
|
+
"#{options[:css_location]}/#{name}.css"
|
111
|
+
end
|
112
|
+
|
113
|
+
def forbid_update?(name)
|
114
|
+
name[0] == ?_
|
101
115
|
end
|
102
|
-
|
116
|
+
|
103
117
|
def stylesheet_needs_update?(name)
|
104
|
-
!File.exists?(css_filename(name))
|
118
|
+
if !File.exists?(css_filename(name))
|
119
|
+
return true
|
120
|
+
else
|
121
|
+
css_mtime = File.mtime(css_filename(name))
|
122
|
+
File.mtime(template_filename(name)) > css_mtime ||
|
123
|
+
dependencies(template_filename(name)).any?(&dependency_updated?(css_mtime))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def dependency_updated?(css_mtime)
|
128
|
+
lambda do |dep|
|
129
|
+
File.mtime(dep) > css_mtime ||
|
130
|
+
dependencies(dep).any?(&dependency_updated?(css_mtime))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def dependencies(filename)
|
135
|
+
File.readlines(filename).grep(/^@import /).map do |line|
|
136
|
+
line[8..-1].split(',').map do |inc|
|
137
|
+
Sass::Engine.find_file_to_import(inc.strip, load_paths)
|
138
|
+
end
|
139
|
+
end.flatten.grep(/\.sass$/)
|
105
140
|
end
|
106
141
|
end
|
107
142
|
end
|