haml 2.0.10 → 2.2.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/.yardopts +5 -0
- data/MIT-LICENSE +1 -1
- data/README.md +347 -0
- data/Rakefile +124 -19
- data/VERSION +1 -1
- data/VERSION_NAME +1 -0
- data/extra/haml-mode.el +397 -78
- data/extra/sass-mode.el +148 -36
- data/extra/update_watch.rb +13 -0
- data/lib/haml.rb +15 -993
- data/lib/haml/buffer.rb +131 -84
- data/lib/haml/engine.rb +129 -97
- data/lib/haml/error.rb +7 -7
- data/lib/haml/exec.rb +127 -42
- data/lib/haml/filters.rb +107 -42
- data/lib/haml/helpers.rb +210 -156
- data/lib/haml/helpers/action_view_extensions.rb +34 -39
- data/lib/haml/helpers/action_view_mods.rb +132 -139
- data/lib/haml/html.rb +77 -65
- data/lib/haml/precompiler.rb +404 -213
- data/lib/haml/shared.rb +78 -0
- data/lib/haml/template.rb +14 -14
- data/lib/haml/template/patch.rb +2 -2
- data/lib/haml/template/plugin.rb +2 -3
- data/lib/haml/util.rb +211 -6
- data/lib/haml/version.rb +30 -13
- data/lib/sass.rb +7 -856
- data/lib/sass/css.rb +169 -161
- data/lib/sass/engine.rb +344 -328
- data/lib/sass/environment.rb +79 -0
- data/lib/sass/error.rb +33 -11
- data/lib/sass/files.rb +139 -0
- data/lib/sass/plugin.rb +160 -117
- data/lib/sass/plugin/merb.rb +7 -6
- data/lib/sass/plugin/rails.rb +5 -6
- data/lib/sass/repl.rb +58 -0
- data/lib/sass/script.rb +59 -0
- data/lib/sass/script/bool.rb +17 -0
- data/lib/sass/script/color.rb +183 -0
- data/lib/sass/script/funcall.rb +50 -0
- data/lib/sass/script/functions.rb +198 -0
- data/lib/sass/script/lexer.rb +178 -0
- data/lib/sass/script/literal.rb +177 -0
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +381 -0
- data/lib/sass/script/operation.rb +45 -0
- data/lib/sass/script/parser.rb +172 -0
- data/lib/sass/script/string.rb +12 -0
- data/lib/sass/script/unary_operation.rb +34 -0
- data/lib/sass/script/variable.rb +31 -0
- data/lib/sass/tree/comment_node.rb +73 -10
- data/lib/sass/tree/debug_node.rb +30 -0
- data/lib/sass/tree/directive_node.rb +42 -17
- data/lib/sass/tree/file_node.rb +41 -0
- data/lib/sass/tree/for_node.rb +48 -0
- data/lib/sass/tree/if_node.rb +54 -0
- data/lib/sass/tree/mixin_def_node.rb +29 -0
- data/lib/sass/tree/mixin_node.rb +48 -0
- data/lib/sass/tree/node.rb +214 -11
- data/lib/sass/tree/prop_node.rb +109 -0
- data/lib/sass/tree/rule_node.rb +178 -51
- data/lib/sass/tree/variable_node.rb +34 -0
- data/lib/sass/tree/while_node.rb +31 -0
- data/test/haml/engine_test.rb +331 -36
- data/test/haml/helper_test.rb +12 -1
- data/test/haml/results/content_for_layout.xhtml +0 -3
- data/test/haml/results/filters.xhtml +2 -0
- data/test/haml/results/list.xhtml +1 -1
- data/test/haml/template_test.rb +7 -2
- data/test/haml/templates/content_for_layout.haml +0 -2
- data/test/haml/templates/list.haml +1 -1
- data/test/haml/util_test.rb +92 -0
- data/test/sass/css2sass_test.rb +69 -24
- data/test/sass/engine_test.rb +586 -64
- data/test/sass/functions_test.rb +125 -0
- data/test/sass/more_results/more1.css +9 -0
- data/test/sass/more_results/more1_with_line_comments.css +26 -0
- data/test/sass/more_results/more_import.css +29 -0
- data/test/sass/more_templates/_more_partial.sass +2 -0
- data/test/sass/more_templates/more1.sass +23 -0
- data/test/sass/more_templates/more_import.sass +11 -0
- data/test/sass/plugin_test.rb +81 -28
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/{constants.css → script.css} +4 -4
- data/test/sass/results/subdir/subdir.css +2 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/script_test.rb +258 -0
- data/test/sass/templates/import.sass +1 -1
- data/test/sass/templates/importee.sass +7 -2
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/{constants.sass → script.sass} +11 -10
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/subdir.sass +2 -2
- data/test/sass/templates/units.sass +11 -0
- data/test/test_helper.rb +14 -0
- metadata +77 -19
- data/FAQ +0 -138
- data/README.rdoc +0 -319
- data/lib/sass/constant.rb +0 -216
- data/lib/sass/constant/color.rb +0 -101
- data/lib/sass/constant/literal.rb +0 -54
- data/lib/sass/constant/nil.rb +0 -9
- data/lib/sass/constant/number.rb +0 -87
- data/lib/sass/constant/operation.rb +0 -30
- data/lib/sass/constant/string.rb +0 -22
- data/lib/sass/tree/attr_node.rb +0 -57
- data/lib/sass/tree/value_node.rb +0 -20
data/lib/haml/buffer.rb
CHANGED
@@ -1,84 +1,97 @@
|
|
1
1
|
module Haml
|
2
|
-
# This class is used only internally. It holds the buffer of
|
3
|
-
# is eventually output
|
4
|
-
# from within the precompiled code,
|
5
|
-
# processing done within instance_eval
|
2
|
+
# This class is used only internally. It holds the buffer of HTML that
|
3
|
+
# is eventually output as the resulting document.
|
4
|
+
# It's called from within the precompiled code,
|
5
|
+
# and helps reduce the amount of processing done within `instance_eval`ed code.
|
6
6
|
class Buffer
|
7
7
|
include Haml::Helpers
|
8
|
+
include Haml::Util
|
8
9
|
|
9
|
-
# The string that holds the compiled
|
10
|
-
# _erbout for compatibility with ERB-specific code.
|
10
|
+
# The string that holds the compiled HTML. This is aliased as
|
11
|
+
# `_erbout` for compatibility with ERB-specific code.
|
12
|
+
#
|
13
|
+
# @return [String]
|
11
14
|
attr_accessor :buffer
|
12
15
|
|
13
|
-
# The options hash passed in from Haml::Engine.
|
16
|
+
# The options hash passed in from {Haml::Engine}.
|
17
|
+
#
|
18
|
+
# @return [Hash<String, Object>]
|
19
|
+
# @see Haml::Engine#options_for_buffer
|
14
20
|
attr_accessor :options
|
15
21
|
|
16
|
-
# The Buffer for the enclosing Haml document.
|
22
|
+
# The {Buffer} for the enclosing Haml document.
|
17
23
|
# This is set for partials and similar sorts of nested templates.
|
18
|
-
# It's nil at the top level (see #toplevel?).
|
24
|
+
# It's `nil` at the top level (see \{#toplevel?}).
|
25
|
+
#
|
26
|
+
# @return [Buffer]
|
19
27
|
attr_accessor :upper
|
20
28
|
|
21
29
|
# nil if there's no capture_haml block running,
|
22
30
|
# and the position at which it's beginning the capture if there is one.
|
31
|
+
#
|
32
|
+
# @return [Fixnum, nil]
|
23
33
|
attr_accessor :capture_position
|
24
34
|
|
25
|
-
#
|
35
|
+
# @return [Boolean]
|
36
|
+
# @see #active?
|
26
37
|
attr_writer :active
|
27
38
|
|
28
|
-
#
|
39
|
+
# @return [Boolean] Whether or not the format is XHTML
|
29
40
|
def xhtml?
|
30
41
|
not html?
|
31
42
|
end
|
32
43
|
|
33
|
-
#
|
44
|
+
# @return [Boolean] Whether or not the format is any flavor of HTML
|
34
45
|
def html?
|
35
46
|
html4? or html5?
|
36
47
|
end
|
37
48
|
|
38
|
-
#
|
49
|
+
# @return [Boolean] Whether or not the format is HTML4
|
39
50
|
def html4?
|
40
51
|
@options[:format] == :html4
|
41
52
|
end
|
42
53
|
|
43
|
-
#
|
54
|
+
# @return [Boolean] Whether or not the format is HTML5.
|
44
55
|
def html5?
|
45
56
|
@options[:format] == :html5
|
46
57
|
end
|
47
58
|
|
48
|
-
#
|
49
|
-
#
|
59
|
+
# @return [Boolean] Whether or not this buffer is a top-level template,
|
60
|
+
# as opposed to a nested partial
|
50
61
|
def toplevel?
|
51
62
|
upper.nil?
|
52
63
|
end
|
53
64
|
|
54
|
-
#
|
55
|
-
#
|
65
|
+
# Whether or not this buffer is currently being used to render a Haml template.
|
66
|
+
# Returns `false` if a subtemplate is being rendered,
|
56
67
|
# even if it's a subtemplate of this buffer's template.
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
57
70
|
def active?
|
58
71
|
@active
|
59
72
|
end
|
60
73
|
|
61
|
-
#
|
74
|
+
# @return [Fixnum] The current indentation level of the document
|
62
75
|
def tabulation
|
63
76
|
@real_tabs + @tabulation
|
64
77
|
end
|
65
78
|
|
66
79
|
# Sets the current tabulation of the document.
|
80
|
+
#
|
81
|
+
# @param val [Fixnum] The new tabulation
|
67
82
|
def tabulation=(val)
|
68
83
|
val = val - @real_tabs
|
69
84
|
@tabulation = val > -1 ? val : 0
|
70
85
|
end
|
71
86
|
|
72
|
-
#
|
87
|
+
# @param upper [Buffer] The parent buffer
|
88
|
+
# @param options [Hash<Symbol, Object>] An options hash.
|
89
|
+
# See {Haml::Engine#options\_for\_buffer}
|
73
90
|
def initialize(upper = nil, options = {})
|
74
91
|
@active = true
|
75
92
|
@upper = upper
|
76
|
-
@options =
|
77
|
-
|
78
|
-
:ugly => false,
|
79
|
-
:format => :xhtml
|
80
|
-
}.merge options
|
81
|
-
@buffer = ""
|
93
|
+
@options = options
|
94
|
+
@buffer = ruby1_8? ? "" : "".encode(Encoding.find(options[:encoding]))
|
82
95
|
@tabulation = 0
|
83
96
|
|
84
97
|
# The number of tabs that Engine thinks we should have
|
@@ -86,10 +99,15 @@ module Haml
|
|
86
99
|
@real_tabs = 0
|
87
100
|
end
|
88
101
|
|
89
|
-
#
|
90
|
-
#
|
91
|
-
|
92
|
-
|
102
|
+
# Appends text to the buffer, properly tabulated.
|
103
|
+
# Also modifies the document's indentation.
|
104
|
+
#
|
105
|
+
# @param text [String] The text to append
|
106
|
+
# @param tab_change [Fixnum] The number of tabs by which to increase
|
107
|
+
# or decrease the document's indentation
|
108
|
+
# @param dont_tab_up [Boolean] If true, don't indent the first line of `text`
|
109
|
+
def push_text(text, tab_change, dont_tab_up)
|
110
|
+
if @tabulation > 0
|
93
111
|
# Have to push every line in by the extra user set tabulation.
|
94
112
|
# Don't push lines with just whitespace, though,
|
95
113
|
# because that screws up precompiled indentation.
|
@@ -99,65 +117,85 @@ module Haml
|
|
99
117
|
|
100
118
|
@buffer << text
|
101
119
|
@real_tabs += tab_change
|
102
|
-
@dont_tab_up_next_line = false
|
103
120
|
end
|
104
121
|
|
105
|
-
#
|
106
|
-
#
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
result = result.lstrip if nuke_inner_whitespace
|
113
|
-
result = html_escape(result) if escape_html
|
122
|
+
# Modifies the indentation of the document.
|
123
|
+
#
|
124
|
+
# @param tab_change [Fixnum] The number of tabs by which to increase
|
125
|
+
# or decrease the document's indentation
|
126
|
+
def adjust_tabs(tab_change)
|
127
|
+
@real_tabs += tab_change
|
128
|
+
end
|
114
129
|
|
115
|
-
|
130
|
+
Haml::Util.def_static_method(self, :format_script, [:result],
|
131
|
+
:preserve_script, :in_tag, :preserve_tag, :escape_html,
|
132
|
+
:nuke_inner_whitespace, :interpolated, :ugly, <<RUBY)
|
133
|
+
<% unless ugly %>
|
134
|
+
# If we're interpolated,
|
135
|
+
# then the custom tabulation is handled in #push_text.
|
136
|
+
# The easiest way to avoid it here is to reset @tabulation.
|
137
|
+
<% if interpolated %>
|
138
|
+
old_tabulation = @tabulation
|
139
|
+
@tabulation = 0
|
140
|
+
<% end %>
|
141
|
+
|
142
|
+
tabulation = @real_tabs
|
143
|
+
result = result.to_s.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
|
144
|
+
<% else %>
|
145
|
+
result = result.to_s<% if nuke_inner_whitespace %>.strip<% end %>
|
146
|
+
<% end %>
|
147
|
+
|
148
|
+
<% if escape_html %> result = html_escape(result) <% end %>
|
149
|
+
|
150
|
+
<% if preserve_tag %>
|
116
151
|
result = Haml::Helpers.preserve(result)
|
117
|
-
elsif preserve_script
|
152
|
+
<% elsif preserve_script %>
|
118
153
|
result = Haml::Helpers.find_and_preserve(result, options[:preserve])
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
+
<% end %>
|
155
|
+
|
156
|
+
<% if ugly %>
|
157
|
+
return result
|
158
|
+
<% else %>
|
159
|
+
|
160
|
+
has_newline = result.include?("\\n")
|
161
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
162
|
+
<% unless preserve_tag %> if !has_newline <% end %>
|
163
|
+
@real_tabs -= 1
|
164
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
165
|
+
return result
|
166
|
+
<% unless preserve_tag %> end <% end %>
|
167
|
+
<% end %>
|
168
|
+
|
169
|
+
# Precompiled tabulation may be wrong
|
170
|
+
<% if !interpolated && !in_tag %>
|
171
|
+
result = tabs + result if @tabulation > 0
|
172
|
+
<% end %>
|
173
|
+
|
174
|
+
if has_newline
|
175
|
+
result = result.gsub "\\n", "\\n" + tabs(tabulation)
|
176
|
+
|
177
|
+
# Add tabulation if it wasn't precompiled
|
178
|
+
<% if in_tag && !nuke_inner_whitespace %> result = tabs(tabulation) + result <% end %>
|
179
|
+
end
|
180
|
+
|
181
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
182
|
+
result = "\\n\#{result}\\n\#{tabs(tabulation-1)}"
|
183
|
+
@real_tabs -= 1
|
184
|
+
<% end %>
|
185
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
186
|
+
result
|
187
|
+
<% end %>
|
188
|
+
RUBY
|
189
|
+
|
190
|
+
# Takes the various information about the opening tag for an element,
|
191
|
+
# formats it, and appends it to the buffer.
|
154
192
|
def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
|
155
193
|
nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
|
156
194
|
tabulation = @real_tabs
|
157
195
|
|
158
196
|
attributes = class_id
|
159
197
|
attributes_hashes.each do |old|
|
160
|
-
self.class.merge_attrs(attributes, old.
|
198
|
+
self.class.merge_attrs(attributes, to_hash(old.map {|k, v| [k.to_s, v]}))
|
161
199
|
end
|
162
200
|
self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
|
163
201
|
|
@@ -193,6 +231,18 @@ module Haml
|
|
193
231
|
buffer << buffer.slice!(capture_position..-1).rstrip
|
194
232
|
end
|
195
233
|
|
234
|
+
# Merges two attribute hashes.
|
235
|
+
# This is the same as `to.merge!(from)`,
|
236
|
+
# except that it merges id and class attributes.
|
237
|
+
#
|
238
|
+
# ids are concatenated with `"_"`,
|
239
|
+
# and classes are concatenated with `" "`.
|
240
|
+
#
|
241
|
+
# Destructively modifies both `to` and `from`.
|
242
|
+
#
|
243
|
+
# @param to [Hash<String, String>] The attribute hash to merge into
|
244
|
+
# @param from [Hash<String, String>] The attribute hash to merge from
|
245
|
+
# @return [Hash<String, String>] `to`, after being merged
|
196
246
|
def self.merge_attrs(to, from)
|
197
247
|
if to['id'] && from['id']
|
198
248
|
to['id'] << '_' << from.delete('id')
|
@@ -202,7 +252,7 @@ module Haml
|
|
202
252
|
|
203
253
|
if to['class'] && from['class']
|
204
254
|
# Make sure we don't duplicate class names
|
205
|
-
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
|
255
|
+
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).sort.join(' ')
|
206
256
|
elsif to['class'] || from['class']
|
207
257
|
from['class'] ||= to['class']
|
208
258
|
end
|
@@ -212,11 +262,8 @@ module Haml
|
|
212
262
|
|
213
263
|
private
|
214
264
|
|
215
|
-
# Some of these methods are exposed as public class methods
|
216
|
-
# so they can be re-used in helpers.
|
217
|
-
|
218
265
|
@@tab_cache = {}
|
219
|
-
# Gets
|
266
|
+
# Gets `count` tabs. Mostly for internal use.
|
220
267
|
def tabs(count = 0)
|
221
268
|
tabs = [count + @tabulation, 0].max
|
222
269
|
@@tab_cache[tabs] ||= ' ' * tabs
|
@@ -225,7 +272,7 @@ module Haml
|
|
225
272
|
# Takes an array of objects and uses the class and id of the first
|
226
273
|
# one to create an attributes hash.
|
227
274
|
# The second object, if present, is used as a prefix,
|
228
|
-
# just like you can do with dom_id() and dom_class() in Rails
|
275
|
+
# just like you can do with `dom_id()` and `dom_class()` in Rails
|
229
276
|
def parse_object_ref(ref)
|
230
277
|
prefix = ref[1]
|
231
278
|
ref = ref[0]
|
data/lib/haml/engine.rb
CHANGED
@@ -5,53 +5,68 @@ require 'haml/filters'
|
|
5
5
|
require 'haml/error'
|
6
6
|
|
7
7
|
module Haml
|
8
|
-
# This is the
|
9
|
-
#
|
10
|
-
# new instance and calling
|
8
|
+
# This is the frontend for using Haml programmatically.
|
9
|
+
# It can be directly used by the user by creating a
|
10
|
+
# new instance and calling \{#render} to render the template.
|
11
|
+
# For example:
|
11
12
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# template = File.read('templates/really_cool_template.haml')
|
14
|
+
# haml_engine = Haml::Engine.new(template)
|
15
|
+
# output = haml_engine.render
|
16
|
+
# puts output
|
16
17
|
class Engine
|
17
18
|
include Precompiler
|
18
19
|
|
19
|
-
#
|
20
|
-
|
20
|
+
# The options hash.
|
21
|
+
# See {file:HAML_REFERENCE.md#haml_options the Haml options documentation}.
|
22
|
+
#
|
23
|
+
# @return [Hash<Symbol, Object>]
|
24
|
+
attr_accessor :options
|
21
25
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
26
|
+
# The indentation used in the Haml document,
|
27
|
+
# or `nil` if the indentation is ambiguous
|
28
|
+
# (for example, for a single-level document).
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
attr_accessor :indentation
|
25
32
|
|
26
|
-
#
|
33
|
+
# @return [Boolean] Whether or not the format is XHTML.
|
27
34
|
def xhtml?
|
28
35
|
not html?
|
29
36
|
end
|
30
37
|
|
31
|
-
#
|
38
|
+
# @return [Boolean] Whether or not the format is any flavor of HTML.
|
32
39
|
def html?
|
33
40
|
html4? or html5?
|
34
41
|
end
|
35
42
|
|
36
|
-
#
|
43
|
+
# @return [Boolean] Whether or not the format is HTML4.
|
37
44
|
def html4?
|
38
45
|
@options[:format] == :html4
|
39
46
|
end
|
40
47
|
|
41
|
-
#
|
48
|
+
# @return [Boolean] Whether or not the format is HTML5.
|
42
49
|
def html5?
|
43
50
|
@options[:format] == :html5
|
44
51
|
end
|
45
52
|
|
46
|
-
#
|
47
|
-
# template string when <tt>render</tt> is called.
|
48
|
-
# See the Haml module documentation for available options.
|
53
|
+
# The source code that is evaluated to produce the Haml document.
|
49
54
|
#
|
50
|
-
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
55
|
+
# In Ruby 1.9, this is automatically converted to the correct encoding
|
56
|
+
# (see {file:HAML_REFERENCE.md#encoding-option the `:encoding` option}).
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
def precompiled
|
60
|
+
return @precompiled if ruby1_8?
|
61
|
+
return @precompiled.encode(Encoding.find(@options[:encoding]))
|
62
|
+
end
|
63
|
+
|
64
|
+
# Precompiles the Haml template.
|
54
65
|
#
|
66
|
+
# @param template [String] The Haml template
|
67
|
+
# @param options [Hash<Symbol, Object>] An options hash;
|
68
|
+
# see {file:HAML_REFERENCE.md#haml_options the Haml options documentation}
|
69
|
+
# @raise [Haml::Error] if there's a Haml syntax error in the template
|
55
70
|
def initialize(template, options = {})
|
56
71
|
@options = {
|
57
72
|
:suppress_eval => false,
|
@@ -65,8 +80,11 @@ module Haml
|
|
65
80
|
:line => 1,
|
66
81
|
:ugly => false,
|
67
82
|
:format => :xhtml,
|
68
|
-
:escape_html => false
|
83
|
+
:escape_html => false,
|
69
84
|
}
|
85
|
+
unless ruby1_8?
|
86
|
+
@options[:encoding] = Encoding.default_internal || "utf-8"
|
87
|
+
end
|
70
88
|
@options.merge! options
|
71
89
|
@index = 0
|
72
90
|
|
@@ -74,28 +92,22 @@ module Haml
|
|
74
92
|
raise Haml::Error, "Invalid format #{@options[:format].inspect}"
|
75
93
|
end
|
76
94
|
|
77
|
-
@
|
95
|
+
if @options[:encoding] && @options[:encoding].is_a?(Encoding)
|
96
|
+
@options[:encoding] = @options[:encoding].name
|
97
|
+
end
|
98
|
+
|
99
|
+
# :eod is a special end-of-document marker
|
100
|
+
@template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
|
101
|
+
@template_index = 0
|
78
102
|
@to_close_stack = []
|
79
103
|
@output_tabs = 0
|
80
104
|
@template_tabs = 0
|
81
|
-
@flat_spaces = -1
|
82
105
|
@flat = false
|
83
106
|
@newlines = 0
|
84
107
|
@precompiled = ''
|
85
|
-
@
|
108
|
+
@to_merge = []
|
86
109
|
@tab_change = 0
|
87
|
-
|
88
|
-
if @template =~ /\A(\s*\n)*[ \t]+\S/
|
89
|
-
raise SyntaxError.new("Indenting at the beginning of the document is illegal.", ($1 || "").count("\n"))
|
90
|
-
end
|
91
|
-
|
92
|
-
if @options[:filters]
|
93
|
-
warn <<END
|
94
|
-
DEPRECATION WARNING:
|
95
|
-
The Haml :filters option is deprecated and will be removed in version 2.2.
|
96
|
-
Filters are now automatically registered.
|
97
|
-
END
|
98
|
-
end
|
110
|
+
@temp_count = 0
|
99
111
|
|
100
112
|
precompile
|
101
113
|
rescue Haml::Error => e
|
@@ -105,39 +117,45 @@ END
|
|
105
117
|
|
106
118
|
# Processes the template and returns the result as a string.
|
107
119
|
#
|
108
|
-
#
|
109
|
-
# If it's a Binding or Proc object,
|
110
|
-
# Haml uses it as the second argument to Kernel#eval
|
111
|
-
# otherwise, Haml just uses its
|
120
|
+
# `scope` is the context in which the template is evaluated.
|
121
|
+
# If it's a `Binding` or `Proc` object,
|
122
|
+
# Haml uses it as the second argument to `Kernel#eval`;
|
123
|
+
# otherwise, Haml just uses its `#instance_eval` context.
|
112
124
|
#
|
113
125
|
# Note that Haml modifies the evaluation context
|
114
|
-
# (either the scope object or the
|
115
|
-
# It extends Haml::Helpers, and various instance variables are set
|
116
|
-
# (all prefixed with
|
126
|
+
# (either the scope object or the `self` object of the scope binding).
|
127
|
+
# It extends {Haml::Helpers}, and various instance variables are set
|
128
|
+
# (all prefixed with `haml_`).
|
117
129
|
# For example:
|
118
130
|
#
|
119
|
-
#
|
120
|
-
#
|
131
|
+
# s = "foobar"
|
132
|
+
# Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
|
121
133
|
#
|
122
|
-
#
|
123
|
-
#
|
134
|
+
# # s now extends Haml::Helpers
|
135
|
+
# s.responds_to?(:html_attrs) #=> true
|
124
136
|
#
|
125
|
-
#
|
137
|
+
# `locals` is a hash of local variables to make available to the template.
|
126
138
|
# For example:
|
127
139
|
#
|
128
|
-
#
|
140
|
+
# Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"
|
129
141
|
#
|
130
142
|
# If a block is passed to render,
|
131
|
-
# that block is run when
|
143
|
+
# that block is run when `yield` is called
|
132
144
|
# within the template.
|
133
145
|
#
|
134
146
|
# Due to some Ruby quirks,
|
135
|
-
# if scope is a Binding or Proc object and a block is given,
|
147
|
+
# if `scope` is a `Binding` or `Proc` object and a block is given,
|
136
148
|
# the evaluation context may not be quite what the user expects.
|
137
|
-
# In particular, it's equivalent to passing
|
149
|
+
# In particular, it's equivalent to passing `eval("self", scope)` as `scope`.
|
138
150
|
# This won't have an effect in most cases,
|
139
|
-
# but if you're relying on local variables defined in the context of scope
|
151
|
+
# but if you're relying on local variables defined in the context of `scope`,
|
140
152
|
# they won't work.
|
153
|
+
#
|
154
|
+
# @param scope [Binding, Proc, Object] The context in which the template is evaluated
|
155
|
+
# @param locals [Hash<Symbol, Object>] Local variables that will be made available
|
156
|
+
# to the template
|
157
|
+
# @param block [#to_proc] A block that can be yielded to within the template
|
158
|
+
# @return [String] The rendered template
|
141
159
|
def render(scope = Object.new, locals = {}, &block)
|
142
160
|
buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
|
143
161
|
|
@@ -156,7 +174,7 @@ END
|
|
156
174
|
@haml_buffer = buffer
|
157
175
|
end
|
158
176
|
|
159
|
-
eval(
|
177
|
+
eval(precompiled, scope, @options[:filename], @options[:line])
|
160
178
|
|
161
179
|
# Get rid of the current buffer
|
162
180
|
scope_object.instance_eval do
|
@@ -170,24 +188,27 @@ END
|
|
170
188
|
# Returns a proc that, when called,
|
171
189
|
# renders the template and returns the result as a string.
|
172
190
|
#
|
173
|
-
#
|
191
|
+
# `scope` works the same as it does for render.
|
174
192
|
#
|
175
193
|
# The first argument of the returned proc is a hash of local variable names to values.
|
176
194
|
# However, due to an unfortunate Ruby quirk,
|
177
195
|
# the local variables which can be assigned must be pre-declared.
|
178
|
-
# This is done with the
|
196
|
+
# This is done with the `local_names` argument.
|
179
197
|
# For example:
|
180
198
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
199
|
+
# # This works
|
200
|
+
# Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
|
201
|
+
# #=> "<p>Hello!</p>"
|
202
|
+
#
|
203
|
+
# # This doesn't
|
204
|
+
# Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
|
205
|
+
# #=> NameError: undefined local variable or method `foo'
|
184
206
|
#
|
185
|
-
#
|
186
|
-
# Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
|
187
|
-
# #=> NameError: undefined local variable or method `foo'
|
207
|
+
# The proc doesn't take a block; any yields in the template will fail.
|
188
208
|
#
|
189
|
-
# The
|
190
|
-
#
|
209
|
+
# @param scope [Binding, Proc, Object] The context in which the template is evaluated
|
210
|
+
# @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
|
211
|
+
# @return [Proc] The proc that will run the template
|
191
212
|
def render_proc(scope = Object.new, *local_names)
|
192
213
|
if scope.is_a?(Binding) || scope.is_a?(Proc)
|
193
214
|
scope_object = eval("self", scope)
|
@@ -200,41 +221,44 @@ END
|
|
200
221
|
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
|
201
222
|
end
|
202
223
|
|
203
|
-
# Defines a method on
|
204
|
-
# with the given name
|
224
|
+
# Defines a method on `object` with the given name
|
205
225
|
# that renders the template and returns the result as a string.
|
206
226
|
#
|
207
|
-
# If
|
227
|
+
# If `object` is a class or module,
|
208
228
|
# the method will instead by defined as an instance method.
|
209
229
|
# For example:
|
210
230
|
#
|
211
|
-
#
|
212
|
-
#
|
213
|
-
#
|
231
|
+
# t = Time.now
|
232
|
+
# Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render)
|
233
|
+
# t.render #=> "<p>\n Today's date is\n <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"
|
214
234
|
#
|
215
|
-
#
|
216
|
-
#
|
235
|
+
# Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
|
236
|
+
# "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
|
217
237
|
#
|
218
238
|
# The first argument of the defined method is a hash of local variable names to values.
|
219
239
|
# However, due to an unfortunate Ruby quirk,
|
220
240
|
# the local variables which can be assigned must be pre-declared.
|
221
|
-
# This is done with the
|
241
|
+
# This is done with the `local_names` argument.
|
222
242
|
# For example:
|
223
243
|
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
244
|
+
# # This works
|
245
|
+
# obj = Object.new
|
246
|
+
# Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
|
247
|
+
# obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"
|
228
248
|
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
249
|
+
# # This doesn't
|
250
|
+
# obj = Object.new
|
251
|
+
# Haml::Engine.new("%p= foo").def_method(obj, :render)
|
252
|
+
# obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
|
233
253
|
#
|
234
254
|
# Note that Haml modifies the evaluation context
|
235
|
-
# (either the scope object or the
|
236
|
-
# It extends Haml::Helpers, and various instance variables are set
|
237
|
-
# (all prefixed with
|
255
|
+
# (either the scope object or the `self` object of the scope binding).
|
256
|
+
# It extends {Haml::Helpers}, and various instance variables are set
|
257
|
+
# (all prefixed with `haml_`).
|
258
|
+
#
|
259
|
+
# @param object [Object, Module] The object on which to define the method
|
260
|
+
# @param name [String, Symbol] The name of the method to define
|
261
|
+
# @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
|
238
262
|
def def_method(object, name, *local_names)
|
239
263
|
method = object.is_a?(Module) ? :module_eval : :instance_eval
|
240
264
|
|
@@ -242,24 +266,32 @@ END
|
|
242
266
|
@options[:filename], @options[:line])
|
243
267
|
end
|
244
268
|
|
245
|
-
|
246
|
-
|
247
|
-
def set_locals(locals, scope, scope_object)
|
248
|
-
scope_object.send(:instance_variable_set, '@_haml_locals', locals)
|
249
|
-
set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
|
250
|
-
eval(set_locals, scope)
|
251
|
-
end
|
269
|
+
protected
|
252
270
|
|
253
|
-
# Returns a
|
254
|
-
#
|
271
|
+
# Returns a subset of \{#options}: those that {Haml::Buffer} cares about.
|
272
|
+
# All of the values here are such that when `#inspect` is called on the hash,
|
273
|
+
# it can be `Kernel#eval`ed to get the same result back.
|
274
|
+
#
|
275
|
+
# See {file:HAML_REFERENCE.md#haml_options the Haml options documentation}.
|
276
|
+
#
|
277
|
+
# @return [Hash<Symbol, Object>] The options hash
|
255
278
|
def options_for_buffer
|
256
279
|
{
|
257
280
|
:autoclose => @options[:autoclose],
|
258
281
|
:preserve => @options[:preserve],
|
259
282
|
:attr_wrapper => @options[:attr_wrapper],
|
260
283
|
:ugly => @options[:ugly],
|
261
|
-
:format => @options[:format]
|
284
|
+
:format => @options[:format],
|
285
|
+
:encoding => @options[:encoding],
|
262
286
|
}
|
263
287
|
end
|
288
|
+
|
289
|
+
private
|
290
|
+
|
291
|
+
def set_locals(locals, scope, scope_object)
|
292
|
+
scope_object.send(:instance_variable_set, '@_haml_locals', locals)
|
293
|
+
set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
|
294
|
+
eval(set_locals, scope)
|
295
|
+
end
|
264
296
|
end
|
265
297
|
end
|