merbjedi-haml 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/FAQ +138 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +332 -0
- data/REVISION +1 -0
- data/Rakefile +184 -0
- data/VERSION +1 -0
- data/bin/css2sass +7 -0
- data/bin/haml +9 -0
- data/bin/html2haml +7 -0
- data/bin/sass +8 -0
- data/extra/haml-mode.el +434 -0
- data/extra/sass-mode.el +98 -0
- data/init.rb +8 -0
- data/lib/haml.rb +1025 -0
- data/lib/haml/buffer.rb +255 -0
- data/lib/haml/engine.rb +268 -0
- data/lib/haml/error.rb +22 -0
- data/lib/haml/exec.rb +395 -0
- data/lib/haml/filters.rb +276 -0
- data/lib/haml/helpers.rb +465 -0
- data/lib/haml/helpers/action_view_extensions.rb +45 -0
- data/lib/haml/helpers/action_view_mods.rb +181 -0
- data/lib/haml/html.rb +218 -0
- data/lib/haml/precompiler.rb +896 -0
- data/lib/haml/shared.rb +45 -0
- data/lib/haml/template.rb +51 -0
- data/lib/haml/template/patch.rb +58 -0
- data/lib/haml/template/plugin.rb +72 -0
- data/lib/haml/util.rb +77 -0
- data/lib/haml/version.rb +47 -0
- data/lib/sass.rb +1062 -0
- data/lib/sass/css.rb +388 -0
- data/lib/sass/engine.rb +501 -0
- data/lib/sass/environment.rb +33 -0
- data/lib/sass/error.rb +35 -0
- data/lib/sass/plugin.rb +203 -0
- data/lib/sass/plugin/merb.rb +56 -0
- data/lib/sass/plugin/rails.rb +24 -0
- data/lib/sass/repl.rb +44 -0
- data/lib/sass/script.rb +38 -0
- data/lib/sass/script/bool.rb +13 -0
- data/lib/sass/script/color.rb +97 -0
- data/lib/sass/script/funcall.rb +28 -0
- data/lib/sass/script/functions.rb +122 -0
- data/lib/sass/script/lexer.rb +144 -0
- data/lib/sass/script/literal.rb +60 -0
- data/lib/sass/script/number.rb +231 -0
- data/lib/sass/script/operation.rb +30 -0
- data/lib/sass/script/parser.rb +142 -0
- data/lib/sass/script/string.rb +42 -0
- data/lib/sass/script/unary_operation.rb +21 -0
- data/lib/sass/script/variable.rb +20 -0
- data/lib/sass/tree/attr_node.rb +64 -0
- data/lib/sass/tree/comment_node.rb +30 -0
- data/lib/sass/tree/debug_node.rb +22 -0
- data/lib/sass/tree/directive_node.rb +50 -0
- data/lib/sass/tree/file_node.rb +27 -0
- data/lib/sass/tree/for_node.rb +29 -0
- data/lib/sass/tree/if_node.rb +27 -0
- data/lib/sass/tree/mixin_def_node.rb +18 -0
- data/lib/sass/tree/mixin_node.rb +34 -0
- data/lib/sass/tree/node.rb +97 -0
- data/lib/sass/tree/rule_node.rb +120 -0
- data/lib/sass/tree/variable_node.rb +24 -0
- data/lib/sass/tree/while_node.rb +20 -0
- data/rails/init.rb +1 -0
- data/test/benchmark.rb +99 -0
- data/test/haml/engine_test.rb +852 -0
- data/test/haml/helper_test.rb +224 -0
- data/test/haml/html2haml_test.rb +92 -0
- data/test/haml/markaby/standard.mab +52 -0
- data/test/haml/mocks/article.rb +6 -0
- data/test/haml/results/content_for_layout.xhtml +15 -0
- data/test/haml/results/eval_suppressed.xhtml +9 -0
- data/test/haml/results/filters.xhtml +62 -0
- data/test/haml/results/helpers.xhtml +93 -0
- data/test/haml/results/helpful.xhtml +10 -0
- data/test/haml/results/just_stuff.xhtml +68 -0
- data/test/haml/results/list.xhtml +12 -0
- data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +20 -0
- data/test/haml/results/partial_layout.xhtml +5 -0
- data/test/haml/results/partials.xhtml +21 -0
- data/test/haml/results/render_layout.xhtml +3 -0
- data/test/haml/results/silent_script.xhtml +74 -0
- data/test/haml/results/standard.xhtml +42 -0
- data/test/haml/results/tag_parsing.xhtml +23 -0
- data/test/haml/results/very_basic.xhtml +5 -0
- data/test/haml/results/whitespace_handling.xhtml +89 -0
- data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
- data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
- data/test/haml/rhtml/action_view.rhtml +62 -0
- data/test/haml/rhtml/standard.rhtml +54 -0
- data/test/haml/template_test.rb +204 -0
- data/test/haml/templates/_av_partial_1.haml +9 -0
- data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
- data/test/haml/templates/_av_partial_2.haml +5 -0
- data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
- data/test/haml/templates/_layout.erb +3 -0
- data/test/haml/templates/_layout_for_partial.haml +3 -0
- data/test/haml/templates/_partial.haml +8 -0
- data/test/haml/templates/_text_area.haml +3 -0
- data/test/haml/templates/action_view.haml +47 -0
- data/test/haml/templates/action_view_ugly.haml +47 -0
- data/test/haml/templates/breakage.haml +8 -0
- data/test/haml/templates/content_for_layout.haml +10 -0
- data/test/haml/templates/eval_suppressed.haml +11 -0
- data/test/haml/templates/filters.haml +66 -0
- data/test/haml/templates/helpers.haml +95 -0
- data/test/haml/templates/helpful.haml +11 -0
- data/test/haml/templates/just_stuff.haml +83 -0
- data/test/haml/templates/list.haml +12 -0
- data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/original_engine.haml +17 -0
- data/test/haml/templates/partial_layout.haml +3 -0
- data/test/haml/templates/partialize.haml +1 -0
- data/test/haml/templates/partials.haml +12 -0
- data/test/haml/templates/render_layout.haml +2 -0
- data/test/haml/templates/silent_script.haml +40 -0
- data/test/haml/templates/standard.haml +42 -0
- data/test/haml/templates/standard_ugly.haml +42 -0
- data/test/haml/templates/tag_parsing.haml +21 -0
- data/test/haml/templates/very_basic.haml +4 -0
- data/test/haml/templates/whitespace_handling.haml +87 -0
- data/test/linked_rails.rb +12 -0
- data/test/sass/css2sass_test.rb +193 -0
- data/test/sass/engine_test.rb +752 -0
- data/test/sass/functions_test.rb +96 -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 +208 -0
- data/test/sass/results/alt.css +4 -0
- data/test/sass/results/basic.css +9 -0
- data/test/sass/results/compact.css +5 -0
- data/test/sass/results/complex.css +87 -0
- data/test/sass/results/compressed.css +1 -0
- data/test/sass/results/expanded.css +19 -0
- data/test/sass/results/import.css +29 -0
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/results/nested.css +22 -0
- data/test/sass/results/parent_ref.css +13 -0
- data/test/sass/results/script.css +16 -0
- data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
- data/test/sass/results/subdir/subdir.css +3 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/script_test.rb +152 -0
- data/test/sass/templates/_partial.sass +2 -0
- data/test/sass/templates/alt.sass +16 -0
- data/test/sass/templates/basic.sass +23 -0
- data/test/sass/templates/bork.sass +2 -0
- data/test/sass/templates/bork2.sass +2 -0
- data/test/sass/templates/compact.sass +17 -0
- data/test/sass/templates/complex.sass +309 -0
- data/test/sass/templates/compressed.sass +15 -0
- data/test/sass/templates/expanded.sass +17 -0
- data/test/sass/templates/import.sass +11 -0
- data/test/sass/templates/importee.sass +19 -0
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/sass/templates/nested.sass +25 -0
- data/test/sass/templates/parent_ref.sass +25 -0
- data/test/sass/templates/script.sass +101 -0
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
- data/test/sass/templates/subdir/subdir.sass +6 -0
- data/test/sass/templates/units.sass +11 -0
- data/test/test_helper.rb +21 -0
- metadata +273 -0
data/lib/haml/buffer.rb
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
module Haml
|
2
|
+
# This class is used only internally. It holds the buffer of XHTML that
|
3
|
+
# is eventually output by Haml::Engine's to_html method. It's called
|
4
|
+
# from within the precompiled code, and helps reduce the amount of
|
5
|
+
# processing done within instance_eval'd code.
|
6
|
+
class Buffer
|
7
|
+
include Haml::Helpers
|
8
|
+
include Haml::Util
|
9
|
+
|
10
|
+
# The string that holds the compiled XHTML. This is aliased as
|
11
|
+
# _erbout for compatibility with ERB-specific code.
|
12
|
+
attr_accessor :buffer
|
13
|
+
|
14
|
+
# The options hash passed in from Haml::Engine.
|
15
|
+
attr_accessor :options
|
16
|
+
|
17
|
+
# The Buffer for the enclosing Haml document.
|
18
|
+
# This is set for partials and similar sorts of nested templates.
|
19
|
+
# It's nil at the top level (see #toplevel?).
|
20
|
+
attr_accessor :upper
|
21
|
+
|
22
|
+
# See #active?
|
23
|
+
attr_writer :active
|
24
|
+
|
25
|
+
# True if the format is XHTML
|
26
|
+
def xhtml?
|
27
|
+
not html?
|
28
|
+
end
|
29
|
+
|
30
|
+
# True if the format is any flavor of HTML
|
31
|
+
def html?
|
32
|
+
html4? or html5?
|
33
|
+
end
|
34
|
+
|
35
|
+
# True if the format is HTML4
|
36
|
+
def html4?
|
37
|
+
@options[:format] == :html4
|
38
|
+
end
|
39
|
+
|
40
|
+
# True if the format is HTML5
|
41
|
+
def html5?
|
42
|
+
@options[:format] == :html5
|
43
|
+
end
|
44
|
+
|
45
|
+
# True if this buffer is a top-level template,
|
46
|
+
# as opposed to a nested partial.
|
47
|
+
def toplevel?
|
48
|
+
upper.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
# True if this buffer is currently being used to render a Haml template.
|
52
|
+
# However, this returns false if a subtemplate is being rendered,
|
53
|
+
# even if it's a subtemplate of this buffer's template.
|
54
|
+
def active?
|
55
|
+
@active
|
56
|
+
end
|
57
|
+
|
58
|
+
# Gets the current tabulation of the document.
|
59
|
+
def tabulation
|
60
|
+
@real_tabs + @tabulation
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets the current tabulation of the document.
|
64
|
+
def tabulation=(val)
|
65
|
+
val = val - @real_tabs
|
66
|
+
@tabulation = val > -1 ? val : 0
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new buffer.
|
70
|
+
def initialize(upper = nil, options = {})
|
71
|
+
@active = true
|
72
|
+
@upper = upper
|
73
|
+
@options = {
|
74
|
+
:attr_wrapper => "'",
|
75
|
+
:ugly => false,
|
76
|
+
:format => :xhtml
|
77
|
+
}.merge options
|
78
|
+
@buffer = ""
|
79
|
+
@tabulation = 0
|
80
|
+
|
81
|
+
# The number of tabs that Engine thinks we should have
|
82
|
+
# @real_tabs + @tabulation is the number of tabs actually output
|
83
|
+
@real_tabs = 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def push_text(text, tab_change, dont_tab_up)
|
87
|
+
if @tabulation > 0
|
88
|
+
# Have to push every line in by the extra user set tabulation.
|
89
|
+
# Don't push lines with just whitespace, though,
|
90
|
+
# because that screws up precompiled indentation.
|
91
|
+
text.gsub!(/^(?!\s+$)/m, tabs)
|
92
|
+
text.sub!(tabs, '') if dont_tab_up
|
93
|
+
end
|
94
|
+
|
95
|
+
@buffer << text
|
96
|
+
@real_tabs += tab_change
|
97
|
+
end
|
98
|
+
|
99
|
+
def adjust_tabs(tab_change)
|
100
|
+
@real_tabs += tab_change
|
101
|
+
end
|
102
|
+
|
103
|
+
Haml::Util.def_static_method(self, :format_script, [:result],
|
104
|
+
:preserve_script, :in_tag, :preserve_tag, :escape_html,
|
105
|
+
:nuke_inner_whitespace, :interpolated, :ugly, <<RUBY)
|
106
|
+
<% unless ugly %>
|
107
|
+
# If we're interpolated,
|
108
|
+
# then the custom tabulation is handled in #push_text.
|
109
|
+
# The easiest way to avoid it here is to reset @tabulation.
|
110
|
+
<% if interpolated %>
|
111
|
+
old_tabulation = @tabulation
|
112
|
+
@tabulation = 0
|
113
|
+
<% end %>
|
114
|
+
|
115
|
+
tabulation = @real_tabs
|
116
|
+
result = result.to_s.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
|
117
|
+
<% else %>
|
118
|
+
result = result.to_s<% if nuke_inner_whitespace %>.strip<% end %>
|
119
|
+
<% end %>
|
120
|
+
|
121
|
+
<% if escape_html %> result = html_escape(result) <% end %>
|
122
|
+
|
123
|
+
<% if preserve_tag %>
|
124
|
+
result = Haml::Helpers.preserve(result)
|
125
|
+
<% elsif preserve_script %>
|
126
|
+
result = Haml::Helpers.find_and_preserve(result, options[:preserve])
|
127
|
+
<% end %>
|
128
|
+
|
129
|
+
<% if ugly %>
|
130
|
+
return result
|
131
|
+
<% else %>
|
132
|
+
|
133
|
+
has_newline = result.include?("\\n")
|
134
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
135
|
+
<% unless preserve_tag %> if !has_newline <% end %>
|
136
|
+
@real_tabs -= 1
|
137
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
138
|
+
return result
|
139
|
+
<% unless preserve_tag %> end <% end %>
|
140
|
+
<% end %>
|
141
|
+
|
142
|
+
# Precompiled tabulation may be wrong
|
143
|
+
<% if !interpolated && !in_tag %>
|
144
|
+
result = tabs + result if @tabulation > 0
|
145
|
+
<% end %>
|
146
|
+
|
147
|
+
if has_newline
|
148
|
+
result = result.gsub "\\n", "\\n" + tabs(tabulation)
|
149
|
+
|
150
|
+
# Add tabulation if it wasn't precompiled
|
151
|
+
<% if in_tag && !nuke_inner_whitespace %> result = tabs(tabulation) + result <% end %>
|
152
|
+
end
|
153
|
+
|
154
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
155
|
+
result = "\\n\#{result}\\n\#{tabs(tabulation-1)}"
|
156
|
+
@real_tabs -= 1
|
157
|
+
<% end %>
|
158
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
159
|
+
result
|
160
|
+
<% end %>
|
161
|
+
RUBY
|
162
|
+
|
163
|
+
# Takes the various information about the opening tag for an
|
164
|
+
# element, formats it, and adds it to the buffer.
|
165
|
+
def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
|
166
|
+
nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
|
167
|
+
tabulation = @real_tabs
|
168
|
+
|
169
|
+
attributes = class_id
|
170
|
+
attributes_hashes.each do |old|
|
171
|
+
self.class.merge_attrs(attributes, to_hash(old.map {|k, v| [k.to_s, v]}))
|
172
|
+
end
|
173
|
+
self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
|
174
|
+
|
175
|
+
if self_closing && xhtml?
|
176
|
+
str = " />" + (nuke_outer_whitespace ? "" : "\n")
|
177
|
+
else
|
178
|
+
str = ">" + ((if self_closing && html?
|
179
|
+
nuke_outer_whitespace
|
180
|
+
else
|
181
|
+
try_one_line || preserve_tag || nuke_inner_whitespace
|
182
|
+
end) ? "" : "\n")
|
183
|
+
end
|
184
|
+
|
185
|
+
attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
|
186
|
+
@buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
|
187
|
+
|
188
|
+
if content
|
189
|
+
@buffer << "#{content}</#{name}>" << (nuke_outer_whitespace ? "" : "\n")
|
190
|
+
return
|
191
|
+
end
|
192
|
+
|
193
|
+
@real_tabs += 1 unless self_closing || nuke_inner_whitespace
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.merge_attrs(to, from)
|
197
|
+
if to['id'] && from['id']
|
198
|
+
to['id'] << '_' << from.delete('id')
|
199
|
+
elsif to['id'] || from['id']
|
200
|
+
from['id'] ||= to['id']
|
201
|
+
end
|
202
|
+
|
203
|
+
if to['class'] && from['class']
|
204
|
+
# Make sure we don't duplicate class names
|
205
|
+
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
|
206
|
+
elsif to['class'] || from['class']
|
207
|
+
from['class'] ||= to['class']
|
208
|
+
end
|
209
|
+
|
210
|
+
to.merge!(from)
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
|
215
|
+
# Some of these methods are exposed as public class methods
|
216
|
+
# so they can be re-used in helpers.
|
217
|
+
|
218
|
+
@@tab_cache = {}
|
219
|
+
# Gets <tt>count</tt> tabs. Mostly for internal use.
|
220
|
+
def tabs(count = 0)
|
221
|
+
tabs = [count + @tabulation, 0].max
|
222
|
+
@@tab_cache[tabs] ||= ' ' * tabs
|
223
|
+
end
|
224
|
+
|
225
|
+
# Takes an array of objects and uses the class and id of the first
|
226
|
+
# one to create an attributes hash.
|
227
|
+
# The second object, if present, is used as a prefix,
|
228
|
+
# just like you can do with dom_id() and dom_class() in Rails
|
229
|
+
def parse_object_ref(ref)
|
230
|
+
prefix = ref[1]
|
231
|
+
ref = ref[0]
|
232
|
+
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
233
|
+
return {} if ref.nil?
|
234
|
+
class_name = underscore(ref.class)
|
235
|
+
id = "#{class_name}_#{ref.id || 'new'}"
|
236
|
+
if prefix
|
237
|
+
class_name = "#{ prefix }_#{ class_name}"
|
238
|
+
id = "#{ prefix }_#{ id }"
|
239
|
+
end
|
240
|
+
|
241
|
+
{'id' => id, 'class' => class_name}
|
242
|
+
end
|
243
|
+
|
244
|
+
# Changes a word from camel case to underscores.
|
245
|
+
# Based on the method of the same name in Rails' Inflector,
|
246
|
+
# but copied here so it'll run properly without Rails.
|
247
|
+
def underscore(camel_cased_word)
|
248
|
+
camel_cased_word.to_s.gsub(/::/, '_').
|
249
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
250
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
251
|
+
tr("-", "_").
|
252
|
+
downcase
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
data/lib/haml/engine.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'haml/helpers'
|
2
|
+
require 'haml/buffer'
|
3
|
+
require 'haml/precompiler'
|
4
|
+
require 'haml/filters'
|
5
|
+
require 'haml/error'
|
6
|
+
|
7
|
+
module Haml
|
8
|
+
# This is the class where all the parsing and processing of the Haml
|
9
|
+
# template is done. It can be directly used by the user by creating a
|
10
|
+
# new instance and calling <tt>to_html</tt> to render the template. For example:
|
11
|
+
#
|
12
|
+
# template = File.read('templates/really_cool_template.haml')
|
13
|
+
# haml_engine = Haml::Engine.new(template)
|
14
|
+
# output = haml_engine.to_html
|
15
|
+
# puts output
|
16
|
+
class Engine
|
17
|
+
include Precompiler
|
18
|
+
|
19
|
+
# Allow reading and writing of the options hash
|
20
|
+
attr :options, true
|
21
|
+
|
22
|
+
# This string contains the source code that is evaluated
|
23
|
+
# to produce the Haml document.
|
24
|
+
attr :precompiled, true
|
25
|
+
|
26
|
+
# A string containing the indentation used for the Haml document.
|
27
|
+
# nil if the indentation is ambiguous
|
28
|
+
# (for example, for a single-level document).
|
29
|
+
attr :indentation, true
|
30
|
+
|
31
|
+
# True if the format is XHTML
|
32
|
+
def xhtml?
|
33
|
+
not html?
|
34
|
+
end
|
35
|
+
|
36
|
+
# True if the format is any flavor of HTML
|
37
|
+
def html?
|
38
|
+
html4? or html5?
|
39
|
+
end
|
40
|
+
|
41
|
+
# True if the format is HTML4
|
42
|
+
def html4?
|
43
|
+
@options[:format] == :html4
|
44
|
+
end
|
45
|
+
|
46
|
+
# True if the format is HTML5
|
47
|
+
def html5?
|
48
|
+
@options[:format] == :html5
|
49
|
+
end
|
50
|
+
|
51
|
+
# Creates a new instace of Haml::Engine that will compile the given
|
52
|
+
# template string when <tt>render</tt> is called.
|
53
|
+
# See the Haml module documentation for available options.
|
54
|
+
#
|
55
|
+
#--
|
56
|
+
# When adding options, remember to add information about them
|
57
|
+
# to lib/haml.rb!
|
58
|
+
#++
|
59
|
+
#
|
60
|
+
def initialize(template, options = {})
|
61
|
+
@options = {
|
62
|
+
:suppress_eval => false,
|
63
|
+
:attr_wrapper => "'",
|
64
|
+
|
65
|
+
# Don't forget to update the docs in lib/haml.rb if you update these
|
66
|
+
:autoclose => %w[meta img link br hr input area param col base],
|
67
|
+
:preserve => %w[textarea pre],
|
68
|
+
|
69
|
+
:filename => '(haml)',
|
70
|
+
:line => 1,
|
71
|
+
:ugly => false,
|
72
|
+
:format => :xhtml,
|
73
|
+
:escape_html => false
|
74
|
+
}
|
75
|
+
@options.merge! options
|
76
|
+
@index = 0
|
77
|
+
|
78
|
+
unless [:xhtml, :html4, :html5].include?(@options[:format])
|
79
|
+
raise Haml::Error, "Invalid format #{@options[:format].inspect}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# :eod is a special end-of-document marker
|
83
|
+
@template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
|
84
|
+
@template_index = 0
|
85
|
+
@to_close_stack = []
|
86
|
+
@output_tabs = 0
|
87
|
+
@template_tabs = 0
|
88
|
+
@flat = false
|
89
|
+
@newlines = 0
|
90
|
+
@precompiled = ''
|
91
|
+
@to_merge = []
|
92
|
+
@tab_change = 0
|
93
|
+
@temp_count = 0
|
94
|
+
|
95
|
+
if @options[:filters]
|
96
|
+
warn <<END
|
97
|
+
DEPRECATION WARNING:
|
98
|
+
The Haml :filters option is deprecated and will be removed in version 2.2.
|
99
|
+
Filters are now automatically registered.
|
100
|
+
END
|
101
|
+
end
|
102
|
+
|
103
|
+
precompile
|
104
|
+
rescue Haml::Error => e
|
105
|
+
e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
|
106
|
+
raise
|
107
|
+
end
|
108
|
+
|
109
|
+
# Processes the template and returns the result as a string.
|
110
|
+
#
|
111
|
+
# +scope+ is the context in which the template is evaluated.
|
112
|
+
# If it's a Binding or Proc object,
|
113
|
+
# Haml uses it as the second argument to Kernel#eval;
|
114
|
+
# otherwise, Haml just uses its #instance_eval context.
|
115
|
+
#
|
116
|
+
# Note that Haml modifies the evaluation context
|
117
|
+
# (either the scope object or the "self" object of the scope binding).
|
118
|
+
# It extends Haml::Helpers, and various instance variables are set
|
119
|
+
# (all prefixed with "haml").
|
120
|
+
# For example:
|
121
|
+
#
|
122
|
+
# s = "foobar"
|
123
|
+
# Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
|
124
|
+
#
|
125
|
+
# # s now extends Haml::Helpers
|
126
|
+
# s.responds_to?(:html_attrs) #=> true
|
127
|
+
#
|
128
|
+
# +locals+ is a hash of local variables to make available to the template.
|
129
|
+
# For example:
|
130
|
+
#
|
131
|
+
# Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"
|
132
|
+
#
|
133
|
+
# If a block is passed to render,
|
134
|
+
# that block is run when +yield+ is called
|
135
|
+
# within the template.
|
136
|
+
#
|
137
|
+
# Due to some Ruby quirks,
|
138
|
+
# if scope is a Binding or Proc object and a block is given,
|
139
|
+
# the evaluation context may not be quite what the user expects.
|
140
|
+
# In particular, it's equivalent to passing <tt>eval("self", scope)</tt> as scope.
|
141
|
+
# This won't have an effect in most cases,
|
142
|
+
# but if you're relying on local variables defined in the context of scope,
|
143
|
+
# they won't work.
|
144
|
+
def render(scope = Object.new, locals = {}, &block)
|
145
|
+
buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
|
146
|
+
|
147
|
+
if scope.is_a?(Binding) || scope.is_a?(Proc)
|
148
|
+
scope_object = eval("self", scope)
|
149
|
+
scope = scope_object.instance_eval{binding} if block_given?
|
150
|
+
else
|
151
|
+
scope_object = scope
|
152
|
+
scope = scope_object.instance_eval{binding}
|
153
|
+
end
|
154
|
+
|
155
|
+
set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
|
156
|
+
|
157
|
+
scope_object.instance_eval do
|
158
|
+
extend Haml::Helpers
|
159
|
+
@haml_buffer = buffer
|
160
|
+
end
|
161
|
+
|
162
|
+
eval(@precompiled, scope, @options[:filename], @options[:line])
|
163
|
+
|
164
|
+
# Get rid of the current buffer
|
165
|
+
scope_object.instance_eval do
|
166
|
+
@haml_buffer = buffer.upper
|
167
|
+
end
|
168
|
+
|
169
|
+
buffer.buffer
|
170
|
+
end
|
171
|
+
alias_method :to_html, :render
|
172
|
+
|
173
|
+
# Returns a proc that, when called,
|
174
|
+
# renders the template and returns the result as a string.
|
175
|
+
#
|
176
|
+
# +scope+ works the same as it does for render.
|
177
|
+
#
|
178
|
+
# The first argument of the returned proc is a hash of local variable names to values.
|
179
|
+
# However, due to an unfortunate Ruby quirk,
|
180
|
+
# the local variables which can be assigned must be pre-declared.
|
181
|
+
# This is done with the +local_names+ argument.
|
182
|
+
# For example:
|
183
|
+
#
|
184
|
+
# # This works
|
185
|
+
# Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
|
186
|
+
# #=> "<p>Hello!</p>"
|
187
|
+
#
|
188
|
+
# # This doesn't
|
189
|
+
# Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
|
190
|
+
# #=> NameError: undefined local variable or method `foo'
|
191
|
+
#
|
192
|
+
# The proc doesn't take a block;
|
193
|
+
# any yields in the template will fail.
|
194
|
+
def render_proc(scope = Object.new, *local_names)
|
195
|
+
if scope.is_a?(Binding) || scope.is_a?(Proc)
|
196
|
+
scope_object = eval("self", scope)
|
197
|
+
else
|
198
|
+
scope_object = scope
|
199
|
+
scope = scope_object.instance_eval{binding}
|
200
|
+
end
|
201
|
+
|
202
|
+
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
|
203
|
+
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
|
204
|
+
end
|
205
|
+
|
206
|
+
# Defines a method on +object+
|
207
|
+
# with the given name
|
208
|
+
# that renders the template and returns the result as a string.
|
209
|
+
#
|
210
|
+
# If +object+ is a class or module,
|
211
|
+
# the method will instead by defined as an instance method.
|
212
|
+
# For example:
|
213
|
+
#
|
214
|
+
# t = Time.now
|
215
|
+
# Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render)
|
216
|
+
# t.render #=> "<p>\n Today's date is\n <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"
|
217
|
+
#
|
218
|
+
# Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
|
219
|
+
# "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
|
220
|
+
#
|
221
|
+
# The first argument of the defined method is a hash of local variable names to values.
|
222
|
+
# However, due to an unfortunate Ruby quirk,
|
223
|
+
# the local variables which can be assigned must be pre-declared.
|
224
|
+
# This is done with the +local_names+ argument.
|
225
|
+
# For example:
|
226
|
+
#
|
227
|
+
# # This works
|
228
|
+
# obj = Object.new
|
229
|
+
# Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
|
230
|
+
# obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"
|
231
|
+
#
|
232
|
+
# # This doesn't
|
233
|
+
# obj = Object.new
|
234
|
+
# Haml::Engine.new("%p= foo").def_method(obj, :render)
|
235
|
+
# obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
|
236
|
+
#
|
237
|
+
# Note that Haml modifies the evaluation context
|
238
|
+
# (either the scope object or the "self" object of the scope binding).
|
239
|
+
# It extends Haml::Helpers, and various instance variables are set
|
240
|
+
# (all prefixed with "haml").
|
241
|
+
def def_method(object, name, *local_names)
|
242
|
+
method = object.is_a?(Module) ? :module_eval : :instance_eval
|
243
|
+
|
244
|
+
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
|
245
|
+
@options[:filename], @options[:line])
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def set_locals(locals, scope, scope_object)
|
251
|
+
scope_object.send(:instance_variable_set, '@_haml_locals', locals)
|
252
|
+
set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
|
253
|
+
eval(set_locals, scope)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Returns a hash of options that Haml::Buffer cares about.
|
257
|
+
# This should remain loadable from #inspect.
|
258
|
+
def options_for_buffer
|
259
|
+
{
|
260
|
+
:autoclose => @options[:autoclose],
|
261
|
+
:preserve => @options[:preserve],
|
262
|
+
:attr_wrapper => @options[:attr_wrapper],
|
263
|
+
:ugly => @options[:ugly],
|
264
|
+
:format => @options[:format]
|
265
|
+
}
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|