haml 2.0.2 → 2.0.3
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/VERSION +1 -1
- data/bin/haml +2 -1
- data/lib/haml.rb +19 -22
- data/lib/haml/buffer.rb +3 -3
- data/lib/haml/engine.rb +2 -1
- data/lib/haml/error.rb +1 -1
- data/lib/haml/exec.rb +20 -1
- data/lib/haml/filters.rb +34 -24
- data/lib/haml/helpers.rb +1 -1
- data/lib/haml/html.rb +1 -1
- data/lib/haml/precompiler.rb +8 -12
- data/lib/sass.rb +11 -4
- data/lib/sass/constant/number.rb +1 -1
- data/lib/sass/css.rb +28 -27
- data/lib/sass/error.rb +1 -1
- data/lib/sass/plugin.rb +11 -7
- data/lib/sass/plugin/merb.rb +1 -1
- data/rails/init.rb +1 -0
- data/test/haml/engine_test.rb +37 -96
- data/test/haml/html2haml_test.rb +2 -1
- data/test/haml/results/filters.xhtml +2 -23
- data/test/haml/results/just_stuff.xhtml +6 -0
- data/test/haml/templates/filters.haml +0 -23
- data/test/haml/templates/just_stuff.haml +7 -0
- data/test/sass/plugin_test.rb +1 -0
- data/test/test_helper.rb +4 -2
- metadata +100 -99
data/lib/sass/constant/number.rb
CHANGED
@@ -8,7 +8,7 @@ module Sass::Constant # :nodoc:
|
|
8
8
|
def parse(value)
|
9
9
|
first, second, unit = value.scan(Literal::NUMBER)[0]
|
10
10
|
@value = first.empty? ? second.to_i : "#{first}#{second}".to_f
|
11
|
-
@unit = unit
|
11
|
+
@unit = unit.empty? ? nil : unit
|
12
12
|
end
|
13
13
|
|
14
14
|
def plus(other)
|
data/lib/sass/css.rb
CHANGED
@@ -18,7 +18,7 @@ module Sass
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class ValueNode
|
21
|
-
def to_sass(tabs)
|
21
|
+
def to_sass(tabs, opts = {})
|
22
22
|
"#{value}\n"
|
23
23
|
end
|
24
24
|
end
|
@@ -40,6 +40,12 @@ module Sass
|
|
40
40
|
"#{' ' * tabs}#{opts[:alternate] ? '' : ':'}#{name}#{opts[:alternate] ? ':' : ''} #{value}\n"
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
class DirectiveNode
|
45
|
+
def to_sass(tabs, opts = {})
|
46
|
+
"#{' ' * tabs}#{value}#{children.map {|c| c.to_sass(tabs + 1, opts)}}\n"
|
47
|
+
end
|
48
|
+
end
|
43
49
|
end
|
44
50
|
|
45
51
|
# This class is based on the Ruby 1.9 ordered hashes.
|
@@ -118,7 +124,7 @@ module Sass
|
|
118
124
|
# containing the CSS template.
|
119
125
|
def render
|
120
126
|
begin
|
121
|
-
build_tree.to_sass(@options).
|
127
|
+
build_tree.to_sass(@options).strip + "\n"
|
122
128
|
rescue Exception => err
|
123
129
|
line = @template.string[0...@template.pos].split("\n").size
|
124
130
|
|
@@ -132,7 +138,6 @@ module Sass
|
|
132
138
|
def build_tree
|
133
139
|
root = Tree::Node.new(nil)
|
134
140
|
whitespace
|
135
|
-
directives root
|
136
141
|
rules root
|
137
142
|
expand_commas root
|
138
143
|
parent_ref_rules root
|
@@ -142,37 +147,33 @@ module Sass
|
|
142
147
|
root
|
143
148
|
end
|
144
149
|
|
145
|
-
def
|
146
|
-
while
|
147
|
-
|
148
|
-
whitespace
|
149
|
-
value = @template.scan /[^;]+/
|
150
|
-
assert_match /;/
|
150
|
+
def rules(root)
|
151
|
+
while r = rule
|
152
|
+
root << r
|
151
153
|
whitespace
|
152
|
-
|
153
|
-
if name == "import" && value =~ /^(url\()?"?([^\s\(\)\"]+)\.css"?\)?$/
|
154
|
-
value = $2
|
155
|
-
end
|
156
|
-
|
157
|
-
root << Tree::ValueNode.new("@#{name} #{value};", nil)
|
158
154
|
end
|
159
155
|
end
|
160
156
|
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
whitespace
|
157
|
+
def rule
|
158
|
+
return unless rule = @template.scan(/[^\{\};]+/)
|
159
|
+
rule.strip!
|
160
|
+
directive = rule[0] == ?@
|
166
161
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
rules = []
|
162
|
+
if directive
|
163
|
+
node = Tree::DirectiveNode.new(rule, nil)
|
164
|
+
return node if @template.scan(/;/)
|
171
165
|
|
172
|
-
|
173
|
-
|
174
|
-
|
166
|
+
assert_match /\{/
|
167
|
+
whitespace
|
168
|
+
|
169
|
+
rules(node)
|
170
|
+
return node
|
175
171
|
end
|
172
|
+
|
173
|
+
assert_match /\{/
|
174
|
+
node = Tree::RuleNode.new(rule, nil)
|
175
|
+
attributes(node)
|
176
|
+
return node
|
176
177
|
end
|
177
178
|
|
178
179
|
def attributes(rule)
|
data/lib/sass/error.rb
CHANGED
@@ -4,7 +4,7 @@ module Sass
|
|
4
4
|
# and the Sass file that was being parsed (if applicable).
|
5
5
|
# It also provides a handy way to rescue only exceptions raised
|
6
6
|
# because of a faulty template.
|
7
|
-
class SyntaxError <
|
7
|
+
class SyntaxError < StandardError
|
8
8
|
# The line of the Sass template on which the exception was thrown.
|
9
9
|
attr_accessor :sass_line
|
10
10
|
|
data/lib/sass/plugin.rb
CHANGED
@@ -34,6 +34,13 @@ module Sass
|
|
34
34
|
@@options.merge!(value)
|
35
35
|
end
|
36
36
|
|
37
|
+
# Get the options ready to be passed to the Sass::Engine
|
38
|
+
def engine_options(additional_options = {})
|
39
|
+
opts = options.dup.merge(additional_options)
|
40
|
+
opts[:load_paths] = load_paths(opts)
|
41
|
+
opts
|
42
|
+
end
|
43
|
+
|
37
44
|
# Checks each stylesheet in <tt>options[:css_location]</tt>
|
38
45
|
# to see if it needs updating,
|
39
46
|
# and updates it using the corresponding template
|
@@ -53,10 +60,7 @@ module Sass
|
|
53
60
|
File.delete(css) if File.exists?(css)
|
54
61
|
|
55
62
|
filename = template_filename(name)
|
56
|
-
|
57
|
-
l_options[:filename] = filename
|
58
|
-
l_options[:load_paths] = load_paths
|
59
|
-
engine = Engine.new(File.read(filename), l_options)
|
63
|
+
engine = Engine.new(File.read(filename), engine_options(:filename => filename))
|
60
64
|
result = begin
|
61
65
|
engine.render
|
62
66
|
rescue Exception => e
|
@@ -64,7 +68,7 @@ module Sass
|
|
64
68
|
end
|
65
69
|
|
66
70
|
# Create any directories that might be necessary
|
67
|
-
dirs = [
|
71
|
+
dirs = [options[:css_location]]
|
68
72
|
name.split("/")[0...-1].each { |dir| dirs << "#{dirs[-1]}/#{dir}" }
|
69
73
|
dirs.each { |dir| Dir.mkdir(dir) unless File.exist?(dir) }
|
70
74
|
|
@@ -78,8 +82,8 @@ module Sass
|
|
78
82
|
|
79
83
|
private
|
80
84
|
|
81
|
-
def load_paths
|
82
|
-
(
|
85
|
+
def load_paths(opts = options)
|
86
|
+
(opts[:load_paths] || []) + [options[:template_location]]
|
83
87
|
end
|
84
88
|
|
85
89
|
def exception_string(e)
|
data/lib/sass/plugin/merb.rb
CHANGED
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Kernel.load File.join(File.dirname(__FILE__), '..', 'init.rb')
|
data/test/haml/engine_test.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require File.dirname(__FILE__) + '/../test_helper'
|
3
3
|
|
4
4
|
class EngineTest < Test::Unit::TestCase
|
5
|
-
# A map of erroneous
|
5
|
+
# A map of erroneous Haml documents to the error messages they should produce.
|
6
6
|
# The error messages may be arrays;
|
7
7
|
# if so, the second element should be the line number that should be reported for the error.
|
8
8
|
# If this isn't provided, the tests will assume the line number should be the last line of the document.
|
@@ -34,13 +34,7 @@ END
|
|
34
34
|
"%a/ b" => "Self-closing tags can't have content.",
|
35
35
|
" %p foo" => "Indenting at the beginning of the document is illegal.",
|
36
36
|
" %p foo" => "Indenting at the beginning of the document is illegal.",
|
37
|
-
"- end" =>
|
38
|
-
You don't need to use "- end" in Haml. Use indentation instead:
|
39
|
-
- if foo?
|
40
|
-
%strong Foo!
|
41
|
-
- else
|
42
|
-
Not foo.
|
43
|
-
END
|
37
|
+
"- end" => "You don't need to use \"- end\" in Haml. Use indentation instead:\n- if foo?\n %strong Foo!\n- else\n Not foo.",
|
44
38
|
" \n\t\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3],
|
45
39
|
|
46
40
|
# Regression tests
|
@@ -64,9 +58,19 @@ END
|
|
64
58
|
def render(text, options = {}, &block)
|
65
59
|
scope = options.delete(:scope) || Object.new
|
66
60
|
locals = options.delete(:locals) || {}
|
67
|
-
|
61
|
+
engine(text, options).to_html(scope, locals, &block)
|
68
62
|
end
|
69
|
-
|
63
|
+
|
64
|
+
def engine(text, options = {})
|
65
|
+
unless options[:filename]
|
66
|
+
# use caller method name as fake filename. useful for debugging
|
67
|
+
i = -1
|
68
|
+
caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0
|
69
|
+
options[:filename] = "(#{$1})"
|
70
|
+
end
|
71
|
+
Haml::Engine.new(text, options)
|
72
|
+
end
|
73
|
+
|
70
74
|
def test_empty_render_should_remain_empty
|
71
75
|
assert_equal('', render(''))
|
72
76
|
end
|
@@ -99,7 +103,7 @@ END
|
|
99
103
|
end
|
100
104
|
|
101
105
|
def test_multi_render
|
102
|
-
engine =
|
106
|
+
engine = engine("%strong Hi there!")
|
103
107
|
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
104
108
|
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
105
109
|
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
@@ -190,6 +194,10 @@ SOURCE
|
|
190
194
|
assert_equal("<p>foo & bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
|
191
195
|
end
|
192
196
|
|
197
|
+
def test_ampersand_equals_should_escape_before_preserve
|
198
|
+
assert_equal("<textarea>foo
bar</textarea>\n", render('%textarea&= "foo\nbar"', :escape_html => false))
|
199
|
+
end
|
200
|
+
|
193
201
|
def test_bang_equals_should_not_escape
|
194
202
|
assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
|
195
203
|
end
|
@@ -266,14 +274,14 @@ SOURCE
|
|
266
274
|
render("\n\n = abc", :filename => 'test', :line => 2)
|
267
275
|
rescue Exception => e
|
268
276
|
assert_kind_of Haml::SyntaxError, e
|
269
|
-
assert_match
|
277
|
+
assert_match(/test:4/, e.backtrace.first)
|
270
278
|
end
|
271
279
|
|
272
280
|
begin
|
273
281
|
render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
|
274
282
|
rescue Exception => e
|
275
283
|
assert_kind_of NoMethodError, e
|
276
|
-
assert_match
|
284
|
+
assert_match(/test:6/, e.backtrace.first)
|
277
285
|
end
|
278
286
|
end
|
279
287
|
|
@@ -360,12 +368,15 @@ SOURCE
|
|
360
368
|
def test_exceptions
|
361
369
|
EXCEPTION_MAP.each do |key, value|
|
362
370
|
begin
|
363
|
-
render(key)
|
371
|
+
render(key, :filename => "(exception test for #{key.inspect})")
|
364
372
|
rescue Exception => err
|
365
373
|
value = [value] unless value.is_a?(Array)
|
374
|
+
expected_message, line_no = value
|
375
|
+
line_no ||= key.split("\n").length
|
376
|
+
line_reported = err.backtrace[0].gsub(/\(.+\):/, '').to_i
|
366
377
|
|
367
|
-
assert_equal(
|
368
|
-
assert_equal(
|
378
|
+
assert_equal(expected_message, err.message, "Line: #{key}")
|
379
|
+
assert_equal(line_no, line_reported, "Line: #{key}")
|
369
380
|
else
|
370
381
|
assert(false, "Exception not raised for\n#{key}")
|
371
382
|
end
|
@@ -375,7 +386,7 @@ SOURCE
|
|
375
386
|
def test_exception_line
|
376
387
|
render("a\nb\n!!!\n c\nd")
|
377
388
|
rescue Haml::SyntaxError => e
|
378
|
-
assert_equal("(
|
389
|
+
assert_equal("(test_exception_line):4", e.backtrace[0])
|
379
390
|
else
|
380
391
|
assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
|
381
392
|
end
|
@@ -383,7 +394,7 @@ SOURCE
|
|
383
394
|
def test_exception
|
384
395
|
render("%p\n hi\n %a= undefined\n= 12")
|
385
396
|
rescue Exception => e
|
386
|
-
assert_match("(
|
397
|
+
assert_match("(test_exception):3", e.backtrace[0])
|
387
398
|
else
|
388
399
|
# Test failed... should have raised an exception
|
389
400
|
assert(false)
|
@@ -392,7 +403,7 @@ SOURCE
|
|
392
403
|
def test_compile_error
|
393
404
|
render("a\nb\n- fee)\nc")
|
394
405
|
rescue Exception => e
|
395
|
-
assert_match(/^compile error\n\(
|
406
|
+
assert_match(/^compile error\n\(test_compile_error\):3: syntax error/i, e.message)
|
396
407
|
else
|
397
408
|
assert(false,
|
398
409
|
'"a\nb\n- fee)\nc" doesn\'t produce an exception!')
|
@@ -409,76 +420,6 @@ SOURCE
|
|
409
420
|
render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
|
410
421
|
end
|
411
422
|
|
412
|
-
def test_no_bluecloth
|
413
|
-
Kernel.module_eval do
|
414
|
-
def gem_original_require_with_bluecloth(file)
|
415
|
-
raise LoadError if file == 'bluecloth'
|
416
|
-
gem_original_require_without_bluecloth(file)
|
417
|
-
end
|
418
|
-
alias_method :gem_original_require_without_bluecloth, :gem_original_require
|
419
|
-
alias_method :gem_original_require, :gem_original_require_with_bluecloth
|
420
|
-
end
|
421
|
-
|
422
|
-
begin
|
423
|
-
assert_equal("<h1>Foo</h1>\t<p>- a\n- b</p>\n",
|
424
|
-
Haml::Engine.new(":markdown\n Foo\n ===\n - a\n - b").to_html)
|
425
|
-
rescue Haml::Error => e
|
426
|
-
if e.message == "Can't run Markdown filter; required 'bluecloth' or 'redcloth', but none were found"
|
427
|
-
puts "\nCouldn't require 'bluecloth' or 'redcloth'; skipping a test."
|
428
|
-
else
|
429
|
-
raise e
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
Kernel.module_eval do
|
434
|
-
alias_method :gem_original_require, :gem_original_require_without_bluecloth
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
def test_no_redcloth
|
439
|
-
Kernel.module_eval do
|
440
|
-
def gem_original_require_with_redcloth(file)
|
441
|
-
raise LoadError if file == 'redcloth'
|
442
|
-
gem_original_require_without_redcloth(file)
|
443
|
-
end
|
444
|
-
alias_method :gem_original_require_without_redcloth, :gem_original_require
|
445
|
-
alias_method :gem_original_require, :gem_original_require_with_redcloth
|
446
|
-
end
|
447
|
-
|
448
|
-
begin
|
449
|
-
Haml::Engine.new(":redcloth\n _foo_").to_html
|
450
|
-
rescue Haml::Error
|
451
|
-
else
|
452
|
-
assert(false, "No exception raised!")
|
453
|
-
end
|
454
|
-
|
455
|
-
Kernel.module_eval do
|
456
|
-
alias_method :gem_original_require, :gem_original_require_without_redcloth
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
def test_no_redcloth_or_bluecloth
|
461
|
-
Kernel.module_eval do
|
462
|
-
def gem_original_require_with_redcloth_and_bluecloth(file)
|
463
|
-
raise LoadError if file == 'redcloth' || file == 'bluecloth'
|
464
|
-
gem_original_require_without_redcloth_and_bluecloth(file)
|
465
|
-
end
|
466
|
-
alias_method :gem_original_require_without_redcloth_and_bluecloth, :gem_original_require
|
467
|
-
alias_method :gem_original_require, :gem_original_require_with_redcloth_and_bluecloth
|
468
|
-
end
|
469
|
-
|
470
|
-
begin
|
471
|
-
Haml::Engine.new(":markdown\n _foo_").to_html
|
472
|
-
rescue Haml::Error
|
473
|
-
else
|
474
|
-
assert(false, "No exception raised!")
|
475
|
-
end
|
476
|
-
|
477
|
-
Kernel.module_eval do
|
478
|
-
alias_method :gem_original_require, :gem_original_require_without_redcloth_and_bluecloth
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
423
|
def test_empty_filter
|
483
424
|
assert_equal(<<END, render(':javascript'))
|
484
425
|
<script type='text/javascript'>
|
@@ -537,28 +478,28 @@ END
|
|
537
478
|
|
538
479
|
def test_yield_should_work_with_def_method
|
539
480
|
s = "foo"
|
540
|
-
|
481
|
+
engine("= yield\n= upcase").def_method(s, :render)
|
541
482
|
assert_equal("12\nFOO\n", s.render { 12 })
|
542
483
|
end
|
543
484
|
|
544
485
|
def test_def_method_with_module
|
545
|
-
|
486
|
+
engine("= yield\n= upcase").def_method(String, :render_haml)
|
546
487
|
assert_equal("12\nFOO\n", "foo".render_haml { 12 })
|
547
488
|
end
|
548
489
|
|
549
490
|
def test_def_method_locals
|
550
491
|
obj = Object.new
|
551
|
-
|
492
|
+
engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
|
552
493
|
assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", obj.render(:foo => 1, :baz => 2, :boom => 3))
|
553
494
|
end
|
554
495
|
|
555
496
|
def test_render_proc_locals
|
556
|
-
proc =
|
497
|
+
proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
|
557
498
|
assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", proc[:foo => 1, :baz => 2, :boom => 3])
|
558
499
|
end
|
559
500
|
|
560
501
|
def test_render_proc_with_binding
|
561
|
-
assert_equal("FOO\n",
|
502
|
+
assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call)
|
562
503
|
end
|
563
504
|
|
564
505
|
def test_ugly_true
|
@@ -585,7 +526,7 @@ END
|
|
585
526
|
end
|
586
527
|
|
587
528
|
def test_arbitrary_output_option
|
588
|
-
assert_raise(Haml::Error, "Invalid output format :html1") {
|
529
|
+
assert_raise(Haml::Error, "Invalid output format :html1") { engine("%br", :format => :html1) }
|
589
530
|
end
|
590
531
|
|
591
532
|
# HTML 4.0
|
@@ -614,7 +555,7 @@ END
|
|
614
555
|
|
615
556
|
# because anything before the doctype triggers quirks mode in IE
|
616
557
|
def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
|
617
|
-
assert_no_match
|
558
|
+
assert_no_match(/^\s+/, render("!!! xml\n!!!", :format => :html4))
|
618
559
|
end
|
619
560
|
|
620
561
|
# HTML5
|
data/test/haml/html2haml_test.rb
CHANGED
@@ -52,7 +52,8 @@ class Html2HamlTest < Test::Unit::TestCase
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def assert_equal_attributes(expected, result)
|
55
|
-
|
55
|
+
expected_attr, result_attr = [expected, result].map { |s| s.gsub!(/\{ (.+) \}/, ''); $1.split(', ').sort }
|
56
|
+
assert_equal expected_attr, result_attr
|
56
57
|
assert_equal expected, result
|
57
58
|
end
|
58
59
|
end
|
@@ -1,24 +1,9 @@
|
|
1
1
|
<style>
|
2
|
-
p {
|
3
|
-
border-style: dotted;
|
4
|
-
border-width: 22px;
|
5
|
-
border-color: #ff00ff; }
|
2
|
+
p { border-style: dotted; border-width: 22px; border-color: #ff00ff; }
|
6
3
|
|
7
|
-
h1 {
|
8
|
-
font-weight: normal; }
|
4
|
+
h1 { font-weight: normal; }
|
9
5
|
</style>
|
10
6
|
TESTING HAHAHAHA!
|
11
|
-
<h1>Foo</h1>
|
12
|
-
|
13
|
-
|
14
|
-
<pre><code>This is preformatted!
Look at that!
Wowie-zowie!</code></pre>
|
15
|
-
|
16
|
-
|
17
|
-
<p><strong>boldilicious!</strong></p>
|
18
|
-
<h1>Yeah</h1>
|
19
|
-
|
20
|
-
|
21
|
-
<p><em>pretty much the same as above</em></p>
|
22
7
|
<p>
|
23
8
|
<script type='text/javascript'>
|
24
9
|
//<![CDATA[
|
@@ -67,12 +52,6 @@ This
|
|
67
52
|
|
68
53
|
</ul>
|
69
54
|
<div class='res'>178</div>
|
70
|
-
<p>
|
71
|
-
<p>I like preserved text:</p>
|
72
|
-
|
73
|
-
|
74
|
-
<pre><code>Foo
 Bar!
Baz</code></pre>
|
75
|
-
</p>
|
76
55
|
<ul>
|
77
56
|
<li>Foo</li>
|
78
57
|
<li>Bar</li>
|