haml 1.0.5 → 1.5.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 +229 -0
- data/Rakefile +56 -60
- data/VERSION +1 -1
- data/bin/haml +4 -14
- data/bin/html2haml +89 -0
- data/bin/sass +8 -0
- data/init.rb +5 -1
- data/lib/haml.rb +643 -0
- data/lib/haml/buffer.rb +33 -30
- data/lib/haml/engine.rb +258 -75
- data/lib/haml/error.rb +43 -0
- data/lib/haml/exec.rb +181 -0
- data/lib/haml/filters.rb +89 -0
- data/lib/haml/helpers.rb +19 -5
- data/lib/haml/helpers/action_view_mods.rb +28 -4
- data/lib/haml/template.rb +13 -27
- data/lib/sass.rb +418 -0
- data/lib/sass/constant.rb +190 -0
- data/lib/sass/constant/color.rb +77 -0
- data/lib/sass/constant/literal.rb +51 -0
- data/lib/sass/constant/number.rb +87 -0
- data/lib/sass/constant/operation.rb +30 -0
- data/lib/sass/constant/string.rb +18 -0
- data/lib/sass/engine.rb +179 -0
- data/lib/sass/error.rb +35 -0
- data/lib/sass/plugin.rb +119 -0
- data/lib/sass/tree/attr_node.rb +44 -0
- data/lib/sass/tree/node.rb +29 -0
- data/lib/sass/tree/rule_node.rb +47 -0
- data/lib/sass/tree/value_node.rb +12 -0
- data/test/benchmark.rb +16 -19
- data/test/haml/engine_test.rb +220 -0
- data/test/{helper_test.rb → haml/helper_test.rb} +9 -8
- data/test/{mocks → haml/mocks}/article.rb +0 -0
- data/test/{results → haml/results}/content_for_layout.xhtml +0 -0
- data/test/{results → haml/results}/eval_suppressed.xhtml +0 -0
- data/test/haml/results/filters.xhtml +57 -0
- data/test/{results → haml/results}/helpers.xhtml +10 -0
- data/test/haml/results/helpful.xhtml +8 -0
- data/test/{results → haml/results}/just_stuff.xhtml +5 -0
- data/test/{results → haml/results}/list.xhtml +0 -0
- data/test/{results → haml/results}/original_engine.xhtml +1 -1
- data/test/{results → haml/results}/partials.xhtml +0 -0
- data/test/{results → haml/results}/silent_script.xhtml +0 -0
- data/test/{results → haml/results}/standard.xhtml +2 -1
- data/test/{results → haml/results}/tag_parsing.xhtml +0 -0
- data/test/{results → haml/results}/very_basic.xhtml +0 -0
- data/test/haml/results/whitespace_handling.xhtml +104 -0
- data/test/{rhtml → haml/rhtml}/standard.rhtml +4 -1
- data/test/{runner.rb → haml/runner.rb} +1 -1
- data/test/{template_test.rb → haml/template_test.rb} +28 -23
- data/test/{templates → haml/templates}/_partial.haml +0 -0
- data/test/{templates → haml/templates}/_text_area.haml +0 -0
- data/test/haml/templates/breakage.haml +8 -0
- data/test/{templates → haml/templates}/content_for_layout.haml +0 -0
- data/test/{templates → haml/templates}/eval_suppressed.haml +0 -0
- data/test/haml/templates/filters.haml +53 -0
- data/test/{templates → haml/templates}/helpers.haml +10 -1
- data/test/{templates → haml/templates}/helpful.haml +3 -0
- data/test/{templates → haml/templates}/just_stuff.haml +7 -0
- data/test/{templates → haml/templates}/list.haml +0 -0
- data/test/haml/templates/original_engine.haml +17 -0
- data/test/{templates → haml/templates}/partialize.haml +0 -0
- data/test/{templates → haml/templates}/partials.haml +0 -0
- data/test/{templates → haml/templates}/silent_script.haml +0 -0
- data/test/{templates → haml/templates}/standard.haml +3 -1
- data/test/{templates → haml/templates}/tag_parsing.haml +0 -0
- data/test/{templates → haml/templates}/very_basic.haml +0 -0
- data/test/haml/templates/whitespace_handling.haml +137 -0
- data/test/profile.rb +36 -18
- data/test/sass/engine_test.rb +87 -0
- data/test/sass/plugin_test.rb +103 -0
- data/test/sass/results/basic.css +9 -0
- data/test/sass/results/compact.css +5 -0
- data/test/sass/results/complex.css +86 -0
- data/test/sass/results/constants.css +12 -0
- data/test/sass/results/expanded.css +18 -0
- data/test/sass/results/nested.css +14 -0
- data/test/sass/templates/basic.sass +23 -0
- data/test/sass/templates/bork.sass +2 -0
- data/test/sass/templates/compact.sass +15 -0
- data/test/sass/templates/complex.sass +291 -0
- data/test/sass/templates/constants.sass +80 -0
- data/test/sass/templates/expanded.sass +15 -0
- data/test/sass/templates/nested.sass +15 -0
- metadata +98 -48
- data/REFERENCE +0 -662
- data/test/engine_test.rb +0 -93
- data/test/results/helpful.xhtml +0 -5
- data/test/results/whitespace_handling.xhtml +0 -51
- data/test/templates/original_engine.haml +0 -17
- data/test/templates/whitespace_handling.haml +0 -66
data/lib/sass/error.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sass
|
2
|
+
# Sass::SyntaxError encapsulates information about the exception,
|
3
|
+
# such as the line of the Sass template it was raised on
|
4
|
+
# and the Sass file that was being parsed (if applicable).
|
5
|
+
# It also provides a handy way to rescue only exceptions raised
|
6
|
+
# because of a faulty template.
|
7
|
+
class SyntaxError < StandardError
|
8
|
+
# The line of the Sass template on which the exception was thrown.
|
9
|
+
attr_accessor :sass_line
|
10
|
+
|
11
|
+
# The name of the file that was being parsed when the exception was raised.
|
12
|
+
# This will be nil unless Sass is being used as an ActionView plugin.
|
13
|
+
attr_reader :sass_filename
|
14
|
+
|
15
|
+
# Creates a new SyntaxError.
|
16
|
+
# +lineno+ should be the line of the Sass template on which the error occurred.
|
17
|
+
def initialize(msg, lineno = nil)
|
18
|
+
@message = msg
|
19
|
+
@sass_line = lineno
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds a properly formatted entry to the exception's backtrace.
|
23
|
+
# +filename+ should be the file in which the error occurred,
|
24
|
+
# if applicable (defaults to "(sass)").
|
25
|
+
def add_backtrace_entry(filename) # :nodoc:
|
26
|
+
@sass_filename = filename
|
27
|
+
self.backtrace ||= []
|
28
|
+
self.backtrace.unshift "#{filename || '(sass)'}:#{@sass_line}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s # :nodoc:
|
32
|
+
@message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/sass/plugin.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'sass/engine'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'action_controller'
|
4
|
+
|
5
|
+
RAILS_ROOT = '. 'unless self.class.const_defined?('RAILS_ROOT')
|
6
|
+
RAILS_ENV = 'production' unless self.class.const_defined?('RAILS_ENV')
|
7
|
+
|
8
|
+
module Sass
|
9
|
+
# This module contains methods that ActionController calls
|
10
|
+
# to automatically update Sass templates that need updating.
|
11
|
+
# It wasn't designed to be used outside of the context of ActionController.
|
12
|
+
module Plugin
|
13
|
+
class << self
|
14
|
+
@@options = {
|
15
|
+
:template_location => RAILS_ROOT + '/public/stylesheets/sass',
|
16
|
+
:css_location => RAILS_ROOT + '/public/stylesheets',
|
17
|
+
:always_update => false,
|
18
|
+
:always_check => RAILS_ENV != "production"
|
19
|
+
}
|
20
|
+
|
21
|
+
# Gets various options for Sass. See README for details.
|
22
|
+
#--
|
23
|
+
# TODO: *DOCUMENT OPTIONS*
|
24
|
+
#++
|
25
|
+
def options
|
26
|
+
@@options
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets various options for Sass.
|
30
|
+
def options=(value)
|
31
|
+
@@options.merge!(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks each stylesheet in <tt>options[:css_location]</tt>
|
35
|
+
# to see if it needs updating,
|
36
|
+
# and updates it using the corresponding template
|
37
|
+
# from <tt>options[:templates]</tt>
|
38
|
+
# if it does.
|
39
|
+
def update_stylesheets
|
40
|
+
Dir[options[:template_location] + '/*.sass'].each do |file|
|
41
|
+
name = File.basename(file)[0...-5]
|
42
|
+
|
43
|
+
if options[:always_update] || stylesheet_needs_update?(name)
|
44
|
+
css = css_filename(name)
|
45
|
+
File.delete(css) if File.exists?(css)
|
46
|
+
|
47
|
+
filename = template_filename(name)
|
48
|
+
l_options = @@options.dup
|
49
|
+
l_options[:filename] = filename
|
50
|
+
engine = Engine.new(File.read(filename), l_options)
|
51
|
+
begin
|
52
|
+
result = engine.render
|
53
|
+
rescue Exception => e
|
54
|
+
if RAILS_ENV != "production"
|
55
|
+
e_string = "#{e.class}: #{e.message}"
|
56
|
+
|
57
|
+
if e.is_a? Sass::SyntaxError
|
58
|
+
e_string << "\non line #{e.sass_line}"
|
59
|
+
|
60
|
+
if e.sass_filename
|
61
|
+
e_string << " of #{e.sass_filename}"
|
62
|
+
|
63
|
+
if File.exists?(e.sass_filename)
|
64
|
+
e_string << "\n\n"
|
65
|
+
|
66
|
+
min = [e.sass_line - 5, 0].max
|
67
|
+
File.read(e.sass_filename).rstrip.split("\n")[
|
68
|
+
min .. e.sass_line + 5
|
69
|
+
].each_with_index do |line, i|
|
70
|
+
e_string << "#{min + i + 1}: #{line}\n"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
result = "/*\n#{e_string}\n\nBacktrace:\n#{e.backtrace.join("\n")}\n*/"
|
76
|
+
else
|
77
|
+
result = "/* Internal stylesheet error */"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Dir.mkdir(l_options[:css_location]) unless File.exist?(l_options[:css_location])
|
82
|
+
File.open(css, 'w') do |file|
|
83
|
+
file.print(result)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def template_filename(name)
|
92
|
+
"#{@@options[:template_location]}/#{name}.sass"
|
93
|
+
end
|
94
|
+
|
95
|
+
def css_filename(name)
|
96
|
+
"#{@@options[:css_location]}/#{name}.css"
|
97
|
+
end
|
98
|
+
|
99
|
+
def stylesheet_needs_update?(name)
|
100
|
+
!File.exists?(css_filename(name)) || (File.mtime(template_filename(name)) - 2) > File.mtime(css_filename(name))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# This module refers to the ActionController module that's part of Ruby on Rails.
|
107
|
+
# Sass can be used as an alternate templating engine for Rails,
|
108
|
+
# and includes some modifications to make this more doable.
|
109
|
+
# The documentation can be found
|
110
|
+
# here[http://rubyonrails.org/api/classes/ActionController/Base.html].
|
111
|
+
module ActionController
|
112
|
+
class Base # :nodoc:
|
113
|
+
alias_method :sass_old_process, :process
|
114
|
+
def process(*args)
|
115
|
+
Sass::Plugin.update_stylesheets if Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
|
116
|
+
sass_old_process(*args)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'sass/tree/node'
|
2
|
+
|
3
|
+
module Sass::Tree
|
4
|
+
class AttrNode < ValueNode
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(name, value, style)
|
8
|
+
@name = name
|
9
|
+
super(value, style)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s(parent_name = nil)
|
13
|
+
if name[-1] == ?: || value[-1] == ?;
|
14
|
+
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (This isn't CSS!)", @line)
|
15
|
+
end
|
16
|
+
real_name = name
|
17
|
+
real_name = "#{parent_name}-#{real_name}" if parent_name
|
18
|
+
if children.size > 0
|
19
|
+
to_return = String.new
|
20
|
+
children.each do |kid|
|
21
|
+
if @style == :compact
|
22
|
+
to_return << "#{kid.to_s(real_name)} "
|
23
|
+
else
|
24
|
+
to_return << "#{kid.to_s(real_name)}\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
to_return << "\n" unless @style == :compact
|
28
|
+
to_return[0...-1]
|
29
|
+
else
|
30
|
+
if value.length < 1
|
31
|
+
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump}", @line)
|
32
|
+
end
|
33
|
+
|
34
|
+
"#{real_name}: #{value};"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def declaration
|
41
|
+
":#{name} #{value}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sass
|
2
|
+
module Tree
|
3
|
+
class Node
|
4
|
+
attr_accessor :children
|
5
|
+
attr_accessor :line
|
6
|
+
|
7
|
+
def initialize(style)
|
8
|
+
@style = style
|
9
|
+
@children = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(child)
|
13
|
+
@children << child
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
result = String.new
|
18
|
+
children.each do |child|
|
19
|
+
if child.is_a? AttrNode
|
20
|
+
raise SyntaxError.new('Attributes aren\'t allowed at the root of a document.', child.line)
|
21
|
+
end
|
22
|
+
|
23
|
+
result += "#{child.to_s(1)}\n"
|
24
|
+
end
|
25
|
+
result[0...-1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sass/tree/node'
|
2
|
+
require 'sass/tree/attr_node'
|
3
|
+
|
4
|
+
module Sass::Tree
|
5
|
+
class RuleNode < ValueNode
|
6
|
+
alias_method :rule, :value
|
7
|
+
alias_method :rule=, :value=
|
8
|
+
|
9
|
+
def to_s(tabs, super_rules = nil)
|
10
|
+
attributes = []
|
11
|
+
sub_rules = []
|
12
|
+
total_rule = if super_rules
|
13
|
+
super_rules.split(/,\s*/).collect! do |s|
|
14
|
+
self.rule.split(/,\s*/).collect! {|r| "#{s} #{r}"}.join(", ")
|
15
|
+
end.join(", ")
|
16
|
+
else
|
17
|
+
self.rule
|
18
|
+
end
|
19
|
+
|
20
|
+
children.each do |child|
|
21
|
+
if child.is_a? AttrNode
|
22
|
+
attributes << child
|
23
|
+
else
|
24
|
+
sub_rules << child
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
to_return = ''
|
29
|
+
unless attributes.empty?
|
30
|
+
if @style == :compact
|
31
|
+
to_return << "#{total_rule} { #{attributes.join(' ')} }\n"
|
32
|
+
else
|
33
|
+
spaces = (@style == :expanded ? 2 : tabs * 2)
|
34
|
+
old_spaces = ' ' * (spaces - 2)
|
35
|
+
spaces = ' ' * spaces
|
36
|
+
|
37
|
+
attributes = attributes.join("\n").gsub("\n", "\n#{spaces}").rstrip
|
38
|
+
end_attrs = (@style == :expanded ? "\n" : ' ')
|
39
|
+
to_return << "#{old_spaces}#{total_rule} {\n#{spaces}#{attributes}#{end_attrs}}\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
sub_rules.each { |sub| to_return << sub.to_s(tabs + 1, total_rule) }
|
44
|
+
to_return
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/benchmark.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../lib/haml
|
1
|
+
require File.dirname(__FILE__) + '/../lib/haml'
|
2
|
+
require 'haml/template'
|
3
|
+
require 'sass/engine'
|
2
4
|
require 'rubygems'
|
3
5
|
require 'active_support'
|
4
6
|
require 'action_view'
|
@@ -19,26 +21,15 @@ module Haml
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
# Benchmarks
|
23
|
-
# looks for a haml template in ./templates and an rhtml template in
|
24
|
-
# ./rhtml with the name <tt>template_name</tt>. Otherwise, uses
|
25
|
-
# <tt>haml_template</tt> and <tt>rhtml_template</tt> as the location of
|
26
|
-
# the templates.
|
24
|
+
# Benchmarks haml against ERb, and Sass on its own.
|
27
25
|
#
|
28
26
|
# Returns the results of the benchmarking as a string.
|
29
27
|
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if other_template.nil?
|
36
|
-
haml_template = "templates/#{template_name}"
|
37
|
-
rhtml_template = "rhtml/#{template_name}"
|
38
|
-
else
|
39
|
-
haml_template = template_name
|
40
|
-
rhtml_template = other_template
|
41
|
-
end
|
28
|
+
def benchmark(runs = 100)
|
29
|
+
template_name = 'standard'
|
30
|
+
haml_template = "haml/templates/#{template_name}"
|
31
|
+
rhtml_template = "haml/rhtml/#{template_name}"
|
32
|
+
sass_template = File.dirname(__FILE__) + "/sass/templates/complex.sass"
|
42
33
|
|
43
34
|
old_stdout = $stdout
|
44
35
|
$stdout = StringIO.new
|
@@ -48,10 +39,16 @@ module Haml
|
|
48
39
|
b.report("erb:") { runs.times { @base.render rhtml_template } }
|
49
40
|
end
|
50
41
|
|
51
|
-
#puts times.inspect
|
42
|
+
#puts times[0].inspect, times[1].inspect
|
52
43
|
ratio = sprintf("%g", times[0].to_a[5] / times[1].to_a[5])
|
53
44
|
puts "Haml/ERB: " + ratio
|
54
45
|
|
46
|
+
puts '', '-' * 50, 'Sass on its own', '-' * 50
|
47
|
+
|
48
|
+
Benchmark.bmbm do |b|
|
49
|
+
b.report("sass:") { runs.times { Sass::Engine.new(File.read(sass_template)).render } }
|
50
|
+
end
|
51
|
+
|
55
52
|
$stdout.pos = 0
|
56
53
|
to_return = $stdout.read
|
57
54
|
$stdout = old_stdout
|
@@ -0,0 +1,220 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require File.dirname(__FILE__) + '/../../lib/haml'
|
5
|
+
require 'haml/engine'
|
6
|
+
|
7
|
+
class EngineTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def render(text, options = {})
|
10
|
+
Haml::Engine.new(text, options).to_html
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_empty_render_should_remain_empty
|
14
|
+
assert_equal('', render(''))
|
15
|
+
end
|
16
|
+
|
17
|
+
# This is ugly because Hashes are unordered; we don't always know the order
|
18
|
+
# in which attributes will be returned.
|
19
|
+
# There is probably a better way to do this.
|
20
|
+
def test_attributes_should_render_correctly
|
21
|
+
assert_equal("<div class='atlantis' style='ugly'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
|
22
|
+
rescue
|
23
|
+
assert_equal("<div style='ugly' class='atlantis'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_ruby_code_should_work_inside_attributes
|
27
|
+
author = 'hcatlin'
|
28
|
+
assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_nil_should_render_empty_tag
|
32
|
+
assert_equal("<div class='no_attributes'>\n</div>",
|
33
|
+
render(".no_attributes{:nil => nil}").chomp)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_strings_should_get_stripped_inside_tags
|
37
|
+
assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
|
38
|
+
render(".stripped This should have no spaces in front of it").chomp)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_one_liner_should_be_one_line
|
42
|
+
assert_equal("<p>Hello</p>", render('%p Hello').chomp)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_long_liner_should_not_print_on_one_line
|
46
|
+
assert_equal("<div>\n #{'x' * 51}\n</div>", render("%div #{'x' * 51}").chomp)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_multi_render
|
50
|
+
engine = Haml::Engine.new("%strong Hi there!")
|
51
|
+
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
52
|
+
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
53
|
+
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Options tests
|
57
|
+
|
58
|
+
def test_stop_eval
|
59
|
+
assert_equal("", render("= 'Hello'", :suppress_eval => true))
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_attr_wrapper
|
63
|
+
assert_equal("<p strange=*attrs*>\n</p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
|
64
|
+
assert_equal("<p escaped='quo\"te'>\n</p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
|
65
|
+
assert_equal("<p escaped=\"q'uo"te\">\n</p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
|
66
|
+
assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_locals
|
70
|
+
assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_precompiled
|
74
|
+
precompiled = <<-END
|
75
|
+
def _haml_render
|
76
|
+
_hamlout = @haml_stack[-1]
|
77
|
+
_erbout = _hamlout.buffer
|
78
|
+
|
79
|
+
_hamlout.open_tag("p", 0, nil, true, "", nil, nil, false)
|
80
|
+
@haml_lineno = 1
|
81
|
+
haml_temp = "Haml Rocks Socks"
|
82
|
+
haml_temp = _hamlout.push_script(haml_temp, 1, false)
|
83
|
+
_hamlout.close_tag("p", 0)
|
84
|
+
end
|
85
|
+
END
|
86
|
+
|
87
|
+
assert_equal("<p>Haml Rocks Socks</p>\n", render("%h1 I shall not be rendered", :precompiled => precompiled))
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_comps
|
91
|
+
assert_equal(-1, "foo" <=> nil)
|
92
|
+
assert_equal(1, nil <=> "foo")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_rec_merge
|
96
|
+
hash1 = {1=>2, 3=>{5=>7, 8=>9}}
|
97
|
+
hash1_2 = hash1.clone
|
98
|
+
hash2 = {4=>5, 3=>{5=>2, 16=>12}}
|
99
|
+
hash3 = {1=>2, 4=>5, 3=>{5=>2, 8=>9, 16=>12}}
|
100
|
+
|
101
|
+
assert_equal(hash3, hash1.rec_merge(hash2))
|
102
|
+
assert_equal(hash1_2, hash1)
|
103
|
+
hash1.rec_merge!(hash2)
|
104
|
+
assert_equal(hash3, hash1)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_exception_type
|
108
|
+
begin
|
109
|
+
render("%p hi\n= undefined")
|
110
|
+
rescue Exception => e
|
111
|
+
assert(e.is_a?(Haml::Error))
|
112
|
+
assert_equal(2, e.haml_line)
|
113
|
+
assert_equal(nil, e.haml_filename)
|
114
|
+
assert_equal('(haml):2', e.backtrace[0])
|
115
|
+
else
|
116
|
+
# Test failed... should have raised an exception
|
117
|
+
assert(false)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_syntax_errors
|
122
|
+
errs = [ "!!!\n a", "a\n b", "a\n:foo\nb", "/ a\n b",
|
123
|
+
"% a", "%p a\n b", "a\n%p=\nb", "%p=\n a",
|
124
|
+
"a\n%p~\nb", "a\n~\nb", "%p/\n a", "%p\n \t%a b",
|
125
|
+
"%a\n b\nc", "%a\n b\nc",
|
126
|
+
":notafilter\n This isn't\n a filter!",
|
127
|
+
]
|
128
|
+
errs.each do |err|
|
129
|
+
begin
|
130
|
+
render(err)
|
131
|
+
rescue Exception => e
|
132
|
+
assert(e.is_a?(Haml::Error),
|
133
|
+
"#{err.dump} doesn't produce Haml::SyntaxError!")
|
134
|
+
else
|
135
|
+
assert(false,
|
136
|
+
"#{err.dump} doesn't produce an exception!")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_compile_error
|
142
|
+
begin
|
143
|
+
render("a\nb\n- fee do\nc")
|
144
|
+
rescue Exception => e
|
145
|
+
assert_equal(3, e.haml_line)
|
146
|
+
else
|
147
|
+
assert(false,
|
148
|
+
'"a\nb\n- fee do\nc" doesn\'t produce an exception!')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_no_bluecloth
|
153
|
+
old_markdown = false
|
154
|
+
if defined?(Haml::Filters::Markdown)
|
155
|
+
old_markdown = Haml::Filters::Markdown
|
156
|
+
end
|
157
|
+
|
158
|
+
Kernel.module_eval do
|
159
|
+
alias_method :haml_old_require, :gem_original_require
|
160
|
+
|
161
|
+
def gem_original_require(file)
|
162
|
+
raise LoadError if file == 'bluecloth'
|
163
|
+
haml_old_require(file)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
if old_markdown
|
168
|
+
Haml::Filters.instance_eval do
|
169
|
+
remove_const 'Markdown'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# This is purposefully redundant, so it doesn't stop
|
174
|
+
# haml/filters from being required later on.
|
175
|
+
require 'haml/../haml/filters'
|
176
|
+
|
177
|
+
assert_equal("<h1>Foo</h1>\t<p>- a\n- b</p>\n",
|
178
|
+
Haml::Engine.new(":markdown\n Foo\n ===\n - a\n - b").to_html)
|
179
|
+
|
180
|
+
Haml::Filters.instance_eval do
|
181
|
+
remove_const 'Markdown'
|
182
|
+
end
|
183
|
+
|
184
|
+
Haml::Filters.const_set('Markdown', old_markdown) if old_markdown
|
185
|
+
|
186
|
+
Kernel.module_eval do
|
187
|
+
alias_method :gem_original_require, :haml_old_require
|
188
|
+
end
|
189
|
+
|
190
|
+
NOT_LOADED.delete 'bluecloth'
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_no_redcloth
|
194
|
+
Kernel.module_eval do
|
195
|
+
alias_method :haml_old_require2, :gem_original_require
|
196
|
+
|
197
|
+
def gem_original_require(file)
|
198
|
+
raise LoadError if file == 'redcloth'
|
199
|
+
haml_old_require2(file)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# This is purposefully redundant, so it doesn't stop
|
204
|
+
# haml/filters from being required later on.
|
205
|
+
require 'haml/../haml/../haml/filters'
|
206
|
+
|
207
|
+
begin
|
208
|
+
Haml::Engine.new(":redcloth\n _foo_").to_html
|
209
|
+
rescue Haml::HamlError
|
210
|
+
else
|
211
|
+
assert(false, "No exception raised!")
|
212
|
+
end
|
213
|
+
|
214
|
+
Kernel.module_eval do
|
215
|
+
alias_method :gem_original_require2, :haml_old_require
|
216
|
+
end
|
217
|
+
|
218
|
+
NOT_LOADED.delete 'redcloth'
|
219
|
+
end
|
220
|
+
end
|