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/haml/buffer.rb
CHANGED
@@ -52,7 +52,7 @@ module Haml
|
|
52
52
|
# instance_eval.
|
53
53
|
def push_script(result, tabulation, flattened)
|
54
54
|
if flattened
|
55
|
-
result =
|
55
|
+
result = Haml::Helpers.find_and_preserve(result)
|
56
56
|
end
|
57
57
|
unless result.nil?
|
58
58
|
result = result.to_s
|
@@ -71,8 +71,8 @@ module Haml
|
|
71
71
|
# element, formats it, and adds it to the buffer.
|
72
72
|
def open_tag(name, tabulation, atomic, try_one_line, class_id, attributes_hash, obj_ref, flattened)
|
73
73
|
attributes = {}
|
74
|
-
attributes.merge!(parse_object_ref(obj_ref)) if obj_ref
|
75
74
|
attributes.merge!(parse_class_and_id(class_id)) unless class_id.nil? || class_id.empty?
|
75
|
+
attributes.merge!(parse_object_ref(obj_ref, attributes[:id], attributes[:class])) if obj_ref
|
76
76
|
attributes.merge!(attributes_hash) if attributes_hash
|
77
77
|
|
78
78
|
@one_liner_pending = false
|
@@ -157,20 +157,30 @@ module Haml
|
|
157
157
|
|
158
158
|
# Takes an array of objects and uses the class and id of the first
|
159
159
|
# one to create an attributes hash.
|
160
|
-
def parse_object_ref(ref)
|
160
|
+
def parse_object_ref(ref, old_id, old_class)
|
161
161
|
ref = ref[0]
|
162
162
|
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
163
163
|
return {} if ref.nil?
|
164
164
|
class_name = ref.class.to_s.underscore
|
165
|
-
|
165
|
+
id = "#{class_name}_#{ref.id}"
|
166
|
+
|
167
|
+
if old_class
|
168
|
+
class_name += " #{old_class}"
|
169
|
+
end
|
170
|
+
|
171
|
+
if old_id
|
172
|
+
id = "#{old_id}_#{id}"
|
173
|
+
end
|
174
|
+
|
175
|
+
{:id => id, :class => class_name}
|
166
176
|
end
|
167
177
|
|
168
178
|
# Takes a hash and builds a list of XHTML attributes from it, returning
|
169
179
|
# the result.
|
170
180
|
def build_attributes(attributes = {})
|
171
181
|
result = attributes.collect do |a,v|
|
172
|
-
|
173
|
-
|
182
|
+
v = v.to_s
|
183
|
+
unless v.nil? || v.empty?
|
174
184
|
attr_wrapper = @options[:attr_wrapper]
|
175
185
|
if v.include? attr_wrapper
|
176
186
|
if v.include? @other_quote_char
|
@@ -190,35 +200,28 @@ module Haml
|
|
190
200
|
def one_liner?(value)
|
191
201
|
value.length <= ONE_LINER_LENGTH && value.scan(/\n/).empty?
|
192
202
|
end
|
193
|
-
|
194
|
-
# Isolates the whitespace-sensitive tags in the string and uses Haml::Helpers#flatten
|
195
|
-
# to convert any endlines inside them into html entities.
|
196
|
-
def find_and_flatten(input)
|
197
|
-
input = input.to_s
|
198
|
-
input.scan(/<(textarea|code|pre)[^>]*>(.*?)<\/\1>/im) do |tag, contents|
|
199
|
-
input = input.gsub(contents, Haml::Helpers.flatten(contents))
|
200
|
-
end
|
201
|
-
input
|
202
|
-
end
|
203
203
|
end
|
204
204
|
end
|
205
205
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
206
|
+
unless String.methods.include? 'old_comp'
|
207
|
+
class String # :nodoc
|
208
|
+
alias_method :old_comp, :<=>
|
209
|
+
|
210
|
+
def <=>(other)
|
211
|
+
if other.is_a? NilClass
|
212
|
+
-1
|
213
|
+
else
|
214
|
+
old_comp(other)
|
215
|
+
end
|
213
216
|
end
|
214
217
|
end
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
218
|
+
|
219
|
+
class NilClass # :nodoc:
|
220
|
+
include Comparable
|
221
|
+
|
222
|
+
def <=>(other)
|
223
|
+
other.nil? ? 0 : 1
|
224
|
+
end
|
222
225
|
end
|
223
226
|
end
|
224
227
|
|
data/lib/haml/engine.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'haml/helpers'
|
2
|
+
require 'haml/buffer'
|
3
|
+
require 'haml/filters'
|
4
|
+
require 'haml/error'
|
3
5
|
|
4
6
|
module Haml
|
5
|
-
# This is the class where all the parsing and processing of the
|
7
|
+
# This is the class where all the parsing and processing of the Haml
|
6
8
|
# template is done. It can be directly used by the user by creating a
|
7
|
-
# new instance and calling to_html to render the template. For example:
|
9
|
+
# new instance and calling <tt>to_html</tt> to render the template. For example:
|
8
10
|
#
|
9
|
-
# template = File.
|
11
|
+
# template = File.read('templates/really_cool_template.haml')
|
10
12
|
# haml_engine = Haml::Engine.new(template)
|
11
13
|
# output = haml_engine.to_html
|
12
14
|
# puts output
|
@@ -18,34 +20,37 @@ module Haml
|
|
18
20
|
attr :options, true
|
19
21
|
|
20
22
|
# Designates an XHTML/XML element.
|
21
|
-
ELEMENT =
|
23
|
+
ELEMENT = ?%
|
22
24
|
|
23
25
|
# Designates a <tt><div></tt> element with the given class.
|
24
|
-
DIV_CLASS =
|
26
|
+
DIV_CLASS = ?.
|
25
27
|
|
26
28
|
# Designates a <tt><div></tt> element with the given id.
|
27
|
-
DIV_ID =
|
29
|
+
DIV_ID = ?#
|
28
30
|
|
29
31
|
# Designates an XHTML/XML comment.
|
30
|
-
COMMENT =
|
32
|
+
COMMENT = ?/
|
31
33
|
|
32
34
|
# Designates an XHTML doctype.
|
33
|
-
DOCTYPE =
|
35
|
+
DOCTYPE = ?!
|
34
36
|
|
35
37
|
# Designates script, the result of which is output.
|
36
|
-
SCRIPT =
|
38
|
+
SCRIPT = ?=
|
37
39
|
|
38
40
|
# Designates script, the result of which is flattened and output.
|
39
|
-
FLAT_SCRIPT =
|
41
|
+
FLAT_SCRIPT = ?~
|
40
42
|
|
41
43
|
# Designates script which is run but not output.
|
42
|
-
SILENT_SCRIPT =
|
44
|
+
SILENT_SCRIPT = ?-
|
43
45
|
|
44
46
|
# When following SILENT_SCRIPT, designates a comment that is not output.
|
45
|
-
SILENT_COMMENT =
|
47
|
+
SILENT_COMMENT = ?#
|
46
48
|
|
47
49
|
# Designates a non-parsed line.
|
48
|
-
ESCAPE =
|
50
|
+
ESCAPE = ?\\
|
51
|
+
|
52
|
+
# Designates a block of filtered text.
|
53
|
+
FILTER = ?:
|
49
54
|
|
50
55
|
# Designates a non-parsed line. Not actually a character.
|
51
56
|
PLAIN_TEXT = -1
|
@@ -61,16 +66,17 @@ module Haml
|
|
61
66
|
SCRIPT,
|
62
67
|
FLAT_SCRIPT,
|
63
68
|
SILENT_SCRIPT,
|
64
|
-
ESCAPE
|
69
|
+
ESCAPE,
|
70
|
+
FILTER
|
65
71
|
]
|
66
72
|
|
67
73
|
# The value of the character that designates that a line is part
|
68
74
|
# of a multiline string.
|
69
|
-
MULTILINE_CHAR_VALUE =
|
75
|
+
MULTILINE_CHAR_VALUE = ?|
|
70
76
|
|
71
77
|
# Characters that designate that a multiline string may be about
|
72
78
|
# to begin.
|
73
|
-
MULTILINE_STARTERS = SPECIAL_CHARACTERS - [
|
79
|
+
MULTILINE_STARTERS = SPECIAL_CHARACTERS - [?/]
|
74
80
|
|
75
81
|
# Keywords that appear in the middle of a Ruby block with lowered
|
76
82
|
# indentation. If a block has been started using indentation,
|
@@ -86,39 +92,87 @@ module Haml
|
|
86
92
|
# is a member of this array.
|
87
93
|
MID_BLOCK_KEYWORDS = ['else', 'elsif', 'rescue', 'ensure', 'when']
|
88
94
|
|
95
|
+
# The Regex that matches an HTML comment command.
|
96
|
+
COMMENT_REGEX = /\/(\[[a-zA-Z0-9 \.]*\])?(.*)/
|
97
|
+
|
98
|
+
# The Regex that matches a Doctype command.
|
99
|
+
DOCTYPE_REGEX = /([0-9]\.[0-9])?[\s]*([a-zA-Z]*)/
|
100
|
+
|
101
|
+
# The Regex that matches an HTML tag command.
|
102
|
+
TAG_REGEX = /[%]([-:_a-zA-Z0-9]+)([-_a-zA-Z0-9\.\#]*)(\{.*\})?(\[.*\])?([=\/\~]?)?(.*)?/
|
103
|
+
|
104
|
+
FLAT_WARNING = <<END
|
105
|
+
Haml deprecation warning:
|
106
|
+
The ~ command is deprecated and will be removed in future Haml versions.
|
107
|
+
Use the :preserve filter, the preserve helper, or the find_and_preserve
|
108
|
+
helper instead.
|
109
|
+
END
|
110
|
+
|
89
111
|
# Creates a new instace of Haml::Engine that will compile the given
|
90
112
|
# template string when <tt>to_html</tt> is called.
|
91
|
-
# See
|
113
|
+
# See README for available options.
|
92
114
|
#
|
93
115
|
#--
|
94
116
|
# When adding options, remember to add information about them
|
95
|
-
# to
|
117
|
+
# to README!
|
96
118
|
#++
|
97
119
|
#
|
98
120
|
def initialize(template, options = {})
|
99
121
|
@options = {
|
100
122
|
:suppress_eval => false,
|
101
123
|
:attr_wrapper => "'",
|
102
|
-
:locals => {}
|
103
|
-
|
124
|
+
:locals => {},
|
125
|
+
:filters => {
|
126
|
+
'sass' => Sass::Engine,
|
127
|
+
'plain' => Haml::Filters::Plain,
|
128
|
+
'preserve' => Haml::Filters::Preserve
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
unless @options[:suppress_eval]
|
133
|
+
@options[:filters].merge!({
|
134
|
+
'erb' => ERB,
|
135
|
+
'ruby' => Haml::Filters::Ruby
|
136
|
+
})
|
137
|
+
end
|
138
|
+
|
139
|
+
if !NOT_LOADED.include? 'redcloth'
|
140
|
+
@options[:filters].merge!({
|
141
|
+
'redcloth' => RedCloth,
|
142
|
+
'textile' => Haml::Filters::Textile,
|
143
|
+
'markdown' => Haml::Filters::Markdown
|
144
|
+
})
|
145
|
+
end
|
146
|
+
if !NOT_LOADED.include? 'bluecloth'
|
147
|
+
@options[:filters]['markdown'] = Haml::Filters::Markdown
|
148
|
+
end
|
149
|
+
|
150
|
+
@options.rec_merge! options
|
151
|
+
|
104
152
|
@precompiled = @options[:precompiled]
|
105
153
|
|
106
154
|
@template = template.strip #String
|
107
155
|
@to_close_stack = []
|
108
156
|
@output_tabs = 0
|
109
157
|
@template_tabs = 0
|
158
|
+
@index = 0
|
110
159
|
|
111
160
|
# This is the base tabulation of the currently active
|
112
161
|
# flattened block. -1 signifies that there is no such block.
|
113
162
|
@flat_spaces = -1
|
114
163
|
|
115
|
-
|
116
|
-
|
117
|
-
|
164
|
+
begin
|
165
|
+
# Only do the first round of pre-compiling if we really need to.
|
166
|
+
# They might be passing in the precompiled string.
|
167
|
+
do_precompile if @precompiled.nil? && (@precompiled = String.new)
|
168
|
+
rescue Haml::Error => e
|
169
|
+
e.add_backtrace_entry(@index, @options[:filename])
|
170
|
+
raise e
|
171
|
+
end
|
118
172
|
end
|
119
173
|
|
120
174
|
# Processes the template and returns the result as a string.
|
121
|
-
def
|
175
|
+
def render(scope = Object.new, &block)
|
122
176
|
@scope_object = scope
|
123
177
|
@buffer = Haml::Buffer.new(@options)
|
124
178
|
|
@@ -139,6 +193,8 @@ module Haml
|
|
139
193
|
@buffer.buffer
|
140
194
|
end
|
141
195
|
|
196
|
+
alias_method :to_html, :render
|
197
|
+
|
142
198
|
private
|
143
199
|
|
144
200
|
#Precompile each line
|
@@ -153,26 +209,38 @@ module Haml
|
|
153
209
|
old_index = nil
|
154
210
|
old_spaces = nil
|
155
211
|
old_tabs = nil
|
156
|
-
|
212
|
+
old_uline = nil
|
213
|
+
(@template + "\n-#\n-#").each_with_index do |line, index|
|
157
214
|
spaces, tabs = count_soft_tabs(line)
|
158
|
-
|
215
|
+
uline = line.lstrip[0...-1]
|
216
|
+
line = uline.rstrip
|
159
217
|
|
160
218
|
if !line.empty?
|
161
219
|
if old_line
|
162
220
|
block_opened = tabs > old_tabs && !line.empty?
|
163
221
|
|
164
|
-
suppress_render = handle_multiline(old_tabs, old_line, old_index)
|
222
|
+
suppress_render = handle_multiline(old_tabs, old_line, old_index) unless @flat_spaces != -1
|
165
223
|
|
166
224
|
if !suppress_render
|
167
225
|
line_empty = old_line.empty?
|
226
|
+
|
168
227
|
process_indent(old_tabs, old_line) unless line_empty
|
169
228
|
flat = @flat_spaces != -1
|
170
229
|
|
230
|
+
|
231
|
+
if !flat && old_spaces != old_tabs * 2
|
232
|
+
raise SyntaxError.new("Illegal Indentation: Only two space characters are allowed as tabulation.")
|
233
|
+
end
|
234
|
+
|
171
235
|
if flat
|
172
|
-
push_flat(
|
236
|
+
push_flat(old_uline, old_spaces)
|
173
237
|
elsif !line_empty
|
174
238
|
process_line(old_line, old_index, block_opened)
|
175
239
|
end
|
240
|
+
|
241
|
+
if @flat_spaces == -1 && tabs - old_tabs > 1
|
242
|
+
raise SyntaxError.new("Illegal Indentation: Indenting more than once per line is illegal.")
|
243
|
+
end
|
176
244
|
end
|
177
245
|
end
|
178
246
|
|
@@ -180,10 +248,16 @@ module Haml
|
|
180
248
|
old_index = index
|
181
249
|
old_spaces = spaces
|
182
250
|
old_tabs = tabs
|
251
|
+
old_uline = uline
|
183
252
|
elsif @flat_spaces != -1
|
184
|
-
|
185
|
-
|
186
|
-
|
253
|
+
process_indent(old_tabs, old_line) unless old_line.empty?
|
254
|
+
|
255
|
+
if @flat_spaces != -1
|
256
|
+
push_flat(old_line, old_spaces)
|
257
|
+
old_line = ''
|
258
|
+
old_uline = ''
|
259
|
+
old_spaces = 0
|
260
|
+
end
|
187
261
|
end
|
188
262
|
end
|
189
263
|
|
@@ -207,40 +281,52 @@ module Haml
|
|
207
281
|
end
|
208
282
|
end
|
209
283
|
|
210
|
-
# Processes a single line of
|
284
|
+
# Processes a single line of Haml.
|
211
285
|
#
|
212
286
|
# This method doesn't return anything; it simply processes the line and
|
213
287
|
# adds the appropriate code to <tt>@precompiled</tt>.
|
214
288
|
def process_line(line, index, block_opened)
|
289
|
+
@index = index + 1
|
290
|
+
@block_opened = block_opened
|
291
|
+
|
215
292
|
case line[0]
|
216
293
|
when DIV_CLASS, DIV_ID
|
217
|
-
render_div(line
|
294
|
+
render_div(line)
|
218
295
|
when ELEMENT
|
219
|
-
render_tag(line
|
296
|
+
render_tag(line)
|
220
297
|
when COMMENT
|
221
298
|
render_comment(line)
|
222
299
|
when SCRIPT
|
223
|
-
|
300
|
+
sub_line = line[1..-1]
|
301
|
+
if sub_line[0] == SCRIPT
|
302
|
+
push_script(sub_line[1..-1].strip.dump.gsub('\\#', '#'), false)
|
303
|
+
else
|
304
|
+
push_script(sub_line, false)
|
305
|
+
end
|
224
306
|
when FLAT_SCRIPT
|
225
|
-
|
307
|
+
warn(FLAT_WARNING) unless defined?(Test::Unit)
|
308
|
+
push_flat_script(line[1..-1])
|
226
309
|
when SILENT_SCRIPT
|
227
310
|
sub_line = line[1..-1]
|
228
311
|
unless sub_line[0] == SILENT_COMMENT
|
229
|
-
push_silent(sub_line,
|
230
|
-
if block_opened && !mid_block_keyword?(line)
|
312
|
+
push_silent(sub_line, true)
|
313
|
+
if @block_opened && !mid_block_keyword?(line)
|
231
314
|
push_and_tabulate([:script])
|
232
315
|
end
|
233
316
|
end
|
317
|
+
when FILTER
|
318
|
+
name = line[1..-1].downcase
|
319
|
+
start_filtered(options[:filters][name] || name)
|
234
320
|
when DOCTYPE
|
235
321
|
if line[0...3] == '!!!'
|
236
322
|
render_doctype(line)
|
237
323
|
else
|
238
|
-
|
324
|
+
push_plain line
|
239
325
|
end
|
240
326
|
when ESCAPE
|
241
|
-
|
327
|
+
push_plain line[1..-1]
|
242
328
|
else
|
243
|
-
|
329
|
+
push_plain line
|
244
330
|
end
|
245
331
|
end
|
246
332
|
|
@@ -307,20 +393,15 @@ module Haml
|
|
307
393
|
@scope_object.instance_eval @precompiled
|
308
394
|
@scope_object._haml_render &block
|
309
395
|
rescue Exception => e
|
396
|
+
class << e
|
397
|
+
include Haml::Error
|
398
|
+
end
|
399
|
+
|
400
|
+
lineno = @scope_object.haml_lineno
|
401
|
+
|
310
402
|
# Get information from the exception and format it so that
|
311
403
|
# Rails can understand it.
|
312
404
|
compile_error = e.message.scan(/\(eval\):([0-9]*):in `[-_a-zA-Z]*': compile error/)[0]
|
313
|
-
filename = "(haml)"
|
314
|
-
if @scope_object.methods.include? "haml_filename"
|
315
|
-
# For some reason that I can't figure out,
|
316
|
-
# @scope_object.methods.include? "haml_filename" && @scope_object.haml_filename
|
317
|
-
# is false when it shouldn't be. Nested if statements work, though.
|
318
|
-
|
319
|
-
if @scope_object.haml_filename
|
320
|
-
filename = "#{@scope_object.haml_filename}.haml"
|
321
|
-
end
|
322
|
-
end
|
323
|
-
lineno = @scope_object.haml_lineno
|
324
405
|
|
325
406
|
if compile_error
|
326
407
|
eval_line = compile_error[0].to_i
|
@@ -328,7 +409,7 @@ module Haml
|
|
328
409
|
lineno = line_marker.scan(/[0-9]+/)[0].to_i if line_marker
|
329
410
|
end
|
330
411
|
|
331
|
-
e.
|
412
|
+
e.add_backtrace_entry(lineno, @options[:filename])
|
332
413
|
raise e
|
333
414
|
end
|
334
415
|
|
@@ -340,9 +421,9 @@ module Haml
|
|
340
421
|
|
341
422
|
# Evaluates <tt>text</tt> in the context of <tt>@scope_object</tt>, but
|
342
423
|
# does not output the result.
|
343
|
-
def push_silent(text,
|
344
|
-
if
|
345
|
-
@precompiled << "@haml_lineno = #{index
|
424
|
+
def push_silent(text, add_index = false)
|
425
|
+
if add_index
|
426
|
+
@precompiled << "@haml_lineno = #{@index}\n#{text}\n"
|
346
427
|
else
|
347
428
|
# Not really DRY, but probably faster
|
348
429
|
@precompiled << "#{text}\n"
|
@@ -355,10 +436,24 @@ module Haml
|
|
355
436
|
@precompiled << "_hamlout.push_text(#{text.dump}, #{@output_tabs})\n"
|
356
437
|
end
|
357
438
|
|
439
|
+
# Renders a block of text as plain text.
|
440
|
+
# Also checks for an illegally opened block.
|
441
|
+
def push_plain(text)
|
442
|
+
if @block_opened
|
443
|
+
raise SyntaxError.new("Illegal Nesting: Nesting within plain text is illegal.")
|
444
|
+
end
|
445
|
+
push_text text
|
446
|
+
end
|
447
|
+
|
358
448
|
# Adds +text+ to <tt>@buffer</tt> while flattening text.
|
359
449
|
def push_flat(text, spaces)
|
360
450
|
tabulation = spaces - @flat_spaces
|
361
|
-
|
451
|
+
tabulation = tabulation > -1 ? tabulation : 0
|
452
|
+
if @filter_buffer
|
453
|
+
@filter_buffer << "#{' ' * tabulation}#{text}\n"
|
454
|
+
else
|
455
|
+
@precompiled << "_hamlout.push_text(#{text.dump}, #{tabulation}, true)\n"
|
456
|
+
end
|
362
457
|
end
|
363
458
|
|
364
459
|
# Causes <tt>text</tt> to be evaluated in the context of
|
@@ -366,11 +461,11 @@ module Haml
|
|
366
461
|
#
|
367
462
|
# If <tt>flattened</tt> is true, Haml::Helpers#find_and_flatten is run on
|
368
463
|
# the result before it is added to <tt>@buffer</tt>
|
369
|
-
def push_script(text, flattened
|
464
|
+
def push_script(text, flattened)
|
370
465
|
unless options[:suppress_eval]
|
371
|
-
push_silent("haml_temp = #{text}",
|
466
|
+
push_silent("haml_temp = #{text}", true)
|
372
467
|
out = "haml_temp = _hamlout.push_script(haml_temp, #{@output_tabs}, #{flattened})\n"
|
373
|
-
if block_opened
|
468
|
+
if @block_opened
|
374
469
|
push_and_tabulate([:loud, out])
|
375
470
|
else
|
376
471
|
@precompiled << out
|
@@ -380,10 +475,13 @@ module Haml
|
|
380
475
|
|
381
476
|
# Causes <tt>text</tt> to be evaluated, and Haml::Helpers#find_and_flatten
|
382
477
|
# to be run on it afterwards.
|
383
|
-
def push_flat_script(text
|
478
|
+
def push_flat_script(text)
|
384
479
|
unless text.empty?
|
385
|
-
push_script(text, true
|
480
|
+
push_script(text, true)
|
386
481
|
else
|
482
|
+
unless @block_opened
|
483
|
+
raise SyntaxError.new('Filters must have nested text.')
|
484
|
+
end
|
387
485
|
start_flat(false)
|
388
486
|
end
|
389
487
|
end
|
@@ -402,6 +500,8 @@ module Haml
|
|
402
500
|
close_flat value
|
403
501
|
when :loud
|
404
502
|
close_loud value
|
503
|
+
when :filtered
|
504
|
+
close_filtered value
|
405
505
|
end
|
406
506
|
end
|
407
507
|
|
@@ -439,15 +539,40 @@ module Haml
|
|
439
539
|
|
440
540
|
# Closes a loud Ruby block.
|
441
541
|
def close_loud(command)
|
442
|
-
push_silent
|
542
|
+
push_silent 'end'
|
443
543
|
@precompiled << command
|
444
544
|
@template_tabs -= 1
|
445
545
|
end
|
446
546
|
|
547
|
+
# Closes a filtered block.
|
548
|
+
def close_filtered(filter)
|
549
|
+
@flat_spaces = -1
|
550
|
+
if filter.is_a? String
|
551
|
+
if filter == 'redcloth' || filter == 'markdown' || filter == 'textile'
|
552
|
+
raise HamlError.new("You must have the RedCloth gem installed to use #{filter}")
|
553
|
+
else
|
554
|
+
raise HamlError.new("Filter \"#{filter}\" is not defined!")
|
555
|
+
end
|
556
|
+
else
|
557
|
+
filtered = filter.new(@filter_buffer).render
|
558
|
+
|
559
|
+
unless filter == Haml::Filters::Preserve
|
560
|
+
push_text(filtered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
|
561
|
+
else
|
562
|
+
push_silent("_hamlout.buffer << #{filtered.dump} << \"\\n\"\n")
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
@filter_buffer = nil
|
567
|
+
@template_tabs -= 1
|
568
|
+
end
|
569
|
+
|
447
570
|
# Parses a line that will render as an XHTML tag, and adds the code that will
|
448
571
|
# render that tag to <tt>@precompiled</tt>.
|
449
|
-
def render_tag(line
|
450
|
-
|
572
|
+
def render_tag(line)
|
573
|
+
matched = false
|
574
|
+
line.scan(TAG_REGEX) do |tag_name, attributes, attributes_hash, object_ref, action, value|
|
575
|
+
matched = true
|
451
576
|
value = value.to_s
|
452
577
|
|
453
578
|
case action
|
@@ -460,11 +585,24 @@ module Haml
|
|
460
585
|
end
|
461
586
|
|
462
587
|
flattened = (action == '~')
|
588
|
+
|
589
|
+
warn(FLAT_WARNING) if flattened && !defined?(Test::Unit)
|
590
|
+
|
463
591
|
value_exists = !value.empty?
|
464
592
|
attributes_hash = "nil" unless attributes_hash
|
465
593
|
object_ref = "nil" unless object_ref
|
466
594
|
|
467
|
-
|
595
|
+
if @block_opened
|
596
|
+
if atomic
|
597
|
+
raise SyntaxError.new("Illegal Nesting: Nesting within an atomic tag is illegal.")
|
598
|
+
elsif action == '=' || value_exists
|
599
|
+
raise SyntaxError.new("Illegal Nesting: Nesting within a tag that already has content is illegal.")
|
600
|
+
end
|
601
|
+
elsif parse && !value_exists
|
602
|
+
raise SyntaxError.new("No tag content to parse.")
|
603
|
+
end
|
604
|
+
|
605
|
+
push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{@output_tabs}, #{atomic.inspect}, #{value_exists.inspect}, #{attributes.inspect}, #{attributes_hash}, #{object_ref}, #{flattened.inspect})", true
|
468
606
|
|
469
607
|
unless atomic
|
470
608
|
push_and_tabulate([:element, tag_name])
|
@@ -472,7 +610,7 @@ module Haml
|
|
472
610
|
|
473
611
|
if value_exists
|
474
612
|
if parse
|
475
|
-
push_script(value, flattened
|
613
|
+
push_script(value, flattened)
|
476
614
|
else
|
477
615
|
push_text(value)
|
478
616
|
end
|
@@ -482,18 +620,27 @@ module Haml
|
|
482
620
|
end
|
483
621
|
end
|
484
622
|
end
|
623
|
+
|
624
|
+
unless matched
|
625
|
+
raise SyntaxError.new("Invalid tag: \"#{line}\"")
|
626
|
+
end
|
485
627
|
end
|
486
628
|
|
487
629
|
# Renders a line that creates an XHTML tag and has an implicit div because of
|
488
630
|
# <tt>.</tt> or <tt>#</tt>.
|
489
|
-
def render_div(line
|
490
|
-
render_tag('%div' + line
|
631
|
+
def render_div(line)
|
632
|
+
render_tag('%div' + line)
|
491
633
|
end
|
492
634
|
|
493
635
|
# Renders an XHTML comment.
|
494
636
|
def render_comment(line)
|
495
|
-
conditional, content = line.scan(
|
496
|
-
content
|
637
|
+
conditional, content = line.scan(COMMENT_REGEX)[0]
|
638
|
+
content.strip!
|
639
|
+
|
640
|
+
if @block_opened && !content.empty?
|
641
|
+
raise SyntaxError.new('Illegal Nesting: Nesting within a tag that already has content is illegal.')
|
642
|
+
end
|
643
|
+
|
497
644
|
try_one_line = !content.empty?
|
498
645
|
push_silent "_hamlout.open_comment(#{try_one_line}, #{conditional.inspect}, #{@output_tabs})"
|
499
646
|
@output_tabs += 1
|
@@ -506,13 +653,16 @@ module Haml
|
|
506
653
|
|
507
654
|
# Renders an XHTML doctype or XML shebang.
|
508
655
|
def render_doctype(line)
|
656
|
+
if @block_opened
|
657
|
+
raise SyntaxError.new("Illegal Nesting: Nesting within a header command is illegal.")
|
658
|
+
end
|
509
659
|
line = line[3..-1].lstrip.downcase
|
510
660
|
if line[0...3] == "xml"
|
511
661
|
encoding = line.split[1] || "utf-8"
|
512
662
|
wrapper = @options[:attr_wrapper]
|
513
663
|
doctype = "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{encoding}#{wrapper} ?>"
|
514
664
|
else
|
515
|
-
version, type = line.scan(
|
665
|
+
version, type = line.scan(DOCTYPE_REGEX)[0]
|
516
666
|
if version == "1.1"
|
517
667
|
doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
518
668
|
else
|
@@ -541,10 +691,23 @@ module Haml
|
|
541
691
|
@flat_spaces = @template_tabs * 2
|
542
692
|
end
|
543
693
|
|
694
|
+
# Starts a filtered block.
|
695
|
+
def start_filtered(filter)
|
696
|
+
unless @block_opened
|
697
|
+
raise SyntaxError.new('Filters must have nested text.')
|
698
|
+
end
|
699
|
+
push_and_tabulate([:filtered, filter])
|
700
|
+
@flat_spaces = @template_tabs * 2
|
701
|
+
@filter_buffer = String.new
|
702
|
+
end
|
703
|
+
|
544
704
|
# Counts the tabulation of a line.
|
545
705
|
def count_soft_tabs(line)
|
546
706
|
spaces = line.index(/[^ ]/)
|
547
|
-
|
707
|
+
if line[spaces] == ?\t
|
708
|
+
raise SyntaxError.new("Illegal Indentation: Only two space characters are allowed as tabulation.")
|
709
|
+
end
|
710
|
+
[spaces, spaces/2]
|
548
711
|
end
|
549
712
|
|
550
713
|
# Pushes value onto <tt>@to_close_stack</tt> and increases
|
@@ -555,3 +718,23 @@ module Haml
|
|
555
718
|
end
|
556
719
|
end
|
557
720
|
end
|
721
|
+
|
722
|
+
class Hash # :nodoc:
|
723
|
+
# Same as Hash#merge!, but recursively merges sub-hashes.
|
724
|
+
def rec_merge!(other)
|
725
|
+
other.each do |key, value|
|
726
|
+
myval = self[key]
|
727
|
+
if value.is_a?(Hash) && myval.is_a?(Hash)
|
728
|
+
myval.rec_merge!(value)
|
729
|
+
else
|
730
|
+
self[key] = value
|
731
|
+
end
|
732
|
+
end
|
733
|
+
self
|
734
|
+
end
|
735
|
+
|
736
|
+
def rec_merge(other)
|
737
|
+
toret = self.clone
|
738
|
+
toret.rec_merge! other
|
739
|
+
end
|
740
|
+
end
|