haml 1.8.0 → 2.0.3
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 +1 -1
- data/{README → README.rdoc} +66 -3
- data/REVISION +1 -0
- data/Rakefile +115 -147
- data/VERSION +1 -1
- data/bin/css2sass +0 -0
- data/bin/haml +2 -1
- data/bin/html2haml +0 -0
- data/bin/sass +0 -0
- data/init.rb +6 -1
- data/lib/haml/buffer.rb +122 -64
- data/lib/haml/engine.rb +77 -46
- data/lib/haml/error.rb +15 -6
- data/lib/haml/exec.rb +61 -10
- data/lib/haml/filters.rb +229 -74
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +109 -24
- data/lib/haml/helpers.rb +137 -76
- data/lib/haml/html.rb +8 -8
- data/lib/haml/precompiler.rb +280 -153
- data/lib/haml/template/patch.rb +10 -3
- data/lib/haml/template/plugin.rb +61 -10
- data/lib/haml/template.rb +14 -9
- data/lib/haml.rb +483 -214
- data/lib/sass/constant/color.rb +13 -13
- data/lib/sass/constant/literal.rb +8 -7
- data/lib/sass/constant/nil.rb +9 -0
- data/lib/sass/constant/number.rb +10 -10
- data/lib/sass/constant/operation.rb +4 -4
- data/lib/sass/constant/string.rb +3 -3
- data/lib/sass/constant.rb +46 -77
- data/lib/sass/css.rb +130 -56
- data/lib/sass/engine.rb +131 -43
- data/lib/sass/plugin/merb.rb +48 -12
- data/lib/sass/plugin/rails.rb +10 -4
- data/lib/sass/plugin.rb +33 -10
- data/lib/sass/tree/attr_node.rb +5 -5
- data/lib/sass/tree/directive_node.rb +2 -7
- data/lib/sass/tree/node.rb +1 -12
- data/lib/sass/tree/rule_node.rb +39 -31
- data/lib/sass/tree/value_node.rb +1 -1
- data/lib/sass.rb +194 -19
- data/rails/init.rb +1 -0
- data/test/benchmark.rb +67 -80
- data/test/haml/engine_test.rb +368 -152
- data/test/haml/helper_test.rb +68 -16
- data/test/haml/html2haml_test.rb +3 -4
- data/test/haml/results/content_for_layout.xhtml +1 -2
- data/test/haml/results/eval_suppressed.xhtml +2 -4
- data/test/haml/results/filters.xhtml +38 -30
- data/test/haml/results/helpers.xhtml +4 -8
- data/test/haml/results/just_stuff.xhtml +8 -7
- 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 +3 -7
- data/test/haml/results/partials.xhtml +1 -0
- data/test/haml/results/tag_parsing.xhtml +1 -6
- data/test/haml/results/very_basic.xhtml +2 -4
- data/test/haml/results/whitespace_handling.xhtml +13 -21
- data/test/haml/template_test.rb +42 -57
- data/test/haml/templates/_partial.haml +1 -0
- data/test/haml/templates/filters.haml +39 -21
- data/test/haml/templates/helpers.haml +10 -10
- data/test/haml/templates/just_stuff.haml +8 -3
- data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/partials.haml +1 -1
- data/test/haml/templates/tag_parsing.haml +0 -3
- data/test/haml/templates/whitespace_handling.haml +10 -10
- data/test/sass/engine_test.rb +97 -39
- data/test/sass/plugin_test.rb +4 -7
- data/test/sass/results/constants.css +2 -0
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/templates/constants.sass +3 -0
- data/test/sass/templates/import.sass +4 -1
- data/test/sass/templates/importee.sass +4 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/test_helper.rb +18 -0
- metadata +70 -53
- data/lib/haml/helpers/action_view_mods.rb.rej +0 -30
- data/lib/haml/util.rb +0 -18
- data/lib/sass/constant.rb.rej +0 -42
- data/test/haml/runner.rb +0 -16
- data/test/profile.rb +0 -65
- data/test/sass/engine_test.rb.rej +0 -18
data/lib/haml/buffer.rb
CHANGED
|
@@ -6,11 +6,6 @@ module Haml
|
|
|
6
6
|
class Buffer
|
|
7
7
|
include Haml::Helpers
|
|
8
8
|
|
|
9
|
-
# Set the maximum length for a line to be considered a one-liner.
|
|
10
|
-
# Lines <= the maximum will be rendered on one line,
|
|
11
|
-
# i.e. <tt><p>Hello world</p></tt>
|
|
12
|
-
ONE_LINER_LENGTH = 50
|
|
13
|
-
|
|
14
9
|
# The string that holds the compiled XHTML. This is aliased as
|
|
15
10
|
# _erbout for compatibility with ERB-specific code.
|
|
16
11
|
attr_accessor :buffer
|
|
@@ -18,6 +13,47 @@ module Haml
|
|
|
18
13
|
# The options hash passed in from Haml::Engine.
|
|
19
14
|
attr_accessor :options
|
|
20
15
|
|
|
16
|
+
# The Buffer for the enclosing Haml document.
|
|
17
|
+
# This is set for partials and similar sorts of nested templates.
|
|
18
|
+
# It's nil at the top level (see #toplevel?).
|
|
19
|
+
attr_accessor :upper
|
|
20
|
+
|
|
21
|
+
# See #active?
|
|
22
|
+
attr_writer :active
|
|
23
|
+
|
|
24
|
+
# True if the format is XHTML
|
|
25
|
+
def xhtml?
|
|
26
|
+
not html?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# True if the format is any flavor of HTML
|
|
30
|
+
def html?
|
|
31
|
+
html4? or html5?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# True if the format is HTML4
|
|
35
|
+
def html4?
|
|
36
|
+
@options[:format] == :html4
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# True if the format is HTML5
|
|
40
|
+
def html5?
|
|
41
|
+
@options[:format] == :html5
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# True if this buffer is a top-level template,
|
|
45
|
+
# as opposed to a nested partial.
|
|
46
|
+
def toplevel?
|
|
47
|
+
upper.nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# True if this buffer is currently being used to render a Haml template.
|
|
51
|
+
# However, this returns false if a subtemplate is being rendered,
|
|
52
|
+
# even if it's a subtemplate of this buffer's template.
|
|
53
|
+
def active?
|
|
54
|
+
@active
|
|
55
|
+
end
|
|
56
|
+
|
|
21
57
|
# Gets the current tabulation of the document.
|
|
22
58
|
def tabulation
|
|
23
59
|
@real_tabs + @tabulation
|
|
@@ -30,9 +66,13 @@ module Haml
|
|
|
30
66
|
end
|
|
31
67
|
|
|
32
68
|
# Creates a new buffer.
|
|
33
|
-
def initialize(options = {})
|
|
69
|
+
def initialize(upper = nil, options = {})
|
|
70
|
+
@active = true
|
|
71
|
+
@upper = upper
|
|
34
72
|
@options = {
|
|
35
|
-
:attr_wrapper => "'"
|
|
73
|
+
:attr_wrapper => "'",
|
|
74
|
+
:ugly => false,
|
|
75
|
+
:format => :xhtml
|
|
36
76
|
}.merge options
|
|
37
77
|
@buffer = ""
|
|
38
78
|
@tabulation = 0
|
|
@@ -44,56 +84,72 @@ module Haml
|
|
|
44
84
|
|
|
45
85
|
# Renders +text+ with the proper tabulation. This also deals with
|
|
46
86
|
# making a possible one-line tag one line or not.
|
|
47
|
-
def push_text(text, tab_change = 0)
|
|
48
|
-
if
|
|
49
|
-
# Have to push every line in by the extra user set tabulation
|
|
50
|
-
|
|
87
|
+
def push_text(text, dont_tab_up = false, tab_change = 0)
|
|
88
|
+
if @tabulation > 0 && !@options[:ugly]
|
|
89
|
+
# Have to push every line in by the extra user set tabulation.
|
|
90
|
+
# Don't push lines with just whitespace, though,
|
|
91
|
+
# because that screws up precompiled indentation.
|
|
92
|
+
text.gsub!(/^(?!\s+$)/m, tabs)
|
|
93
|
+
text.sub!(tabs, '') if dont_tab_up
|
|
51
94
|
end
|
|
52
|
-
|
|
53
|
-
@buffer <<
|
|
95
|
+
|
|
96
|
+
@buffer << text
|
|
54
97
|
@real_tabs += tab_change
|
|
98
|
+
@dont_tab_up_next_line = false
|
|
55
99
|
end
|
|
56
100
|
|
|
57
101
|
# Properly formats the output of a script that was run in the
|
|
58
102
|
# instance_eval.
|
|
59
|
-
def push_script(result,
|
|
103
|
+
def push_script(result, preserve_script, in_tag = false, preserve_tag = false,
|
|
104
|
+
escape_html = false, nuke_inner_whitespace = false)
|
|
60
105
|
tabulation = @real_tabs
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
result = result[0...-1]
|
|
106
|
+
|
|
107
|
+
result = result.to_s.rstrip
|
|
108
|
+
result = html_escape(result) if escape_html
|
|
109
|
+
|
|
110
|
+
if preserve_tag
|
|
111
|
+
result = Haml::Helpers.preserve(result)
|
|
112
|
+
elsif preserve_script
|
|
113
|
+
result = Haml::Helpers.find_and_preserve(result, options[:preserve])
|
|
70
114
|
end
|
|
71
|
-
|
|
72
|
-
|
|
115
|
+
|
|
116
|
+
has_newline = result.include?("\n")
|
|
117
|
+
if in_tag && !nuke_inner_whitespace && (@options[:ugly] || !has_newline || preserve_tag)
|
|
73
118
|
@buffer << result
|
|
74
|
-
@buffer << "</#{close_tag}>\n"
|
|
75
119
|
@real_tabs -= 1
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
@buffer << "\n" if in_tag && !nuke_inner_whitespace
|
|
124
|
+
|
|
125
|
+
# Precompiled tabulation may be wrong
|
|
126
|
+
if @tabulation > 0 && !in_tag
|
|
127
|
+
result = tabs + result
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
if has_newline && !@options[:ugly]
|
|
131
|
+
result = result.gsub "\n", "\n" + tabs(tabulation)
|
|
132
|
+
|
|
133
|
+
# Add tabulation if it wasn't precompiled
|
|
134
|
+
result = tabs(tabulation) + result if in_tag && !nuke_inner_whitespace
|
|
135
|
+
end
|
|
136
|
+
@buffer << "#{result}"
|
|
137
|
+
@buffer << "\n" unless nuke_inner_whitespace
|
|
138
|
+
|
|
139
|
+
if in_tag && !nuke_inner_whitespace
|
|
140
|
+
# We never get here if @options[:ugly] is true
|
|
141
|
+
@buffer << tabs(tabulation-1)
|
|
142
|
+
@real_tabs -= 1
|
|
88
143
|
end
|
|
89
144
|
nil
|
|
90
145
|
end
|
|
91
146
|
|
|
92
147
|
# Takes the various information about the opening tag for an
|
|
93
148
|
# element, formats it, and adds it to the buffer.
|
|
94
|
-
def open_tag(name,
|
|
149
|
+
def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
|
|
150
|
+
nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
|
|
95
151
|
tabulation = @real_tabs
|
|
96
|
-
|
|
152
|
+
|
|
97
153
|
attributes = class_id
|
|
98
154
|
attributes_hashes.each do |attributes_hash|
|
|
99
155
|
attributes_hash.keys.each { |key| attributes_hash[key.to_s] = attributes_hash.delete(key) }
|
|
@@ -101,65 +157,67 @@ module Haml
|
|
|
101
157
|
end
|
|
102
158
|
self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
|
|
103
159
|
|
|
104
|
-
if
|
|
105
|
-
str = "
|
|
106
|
-
elsif try_one_line
|
|
107
|
-
str = ">"
|
|
160
|
+
if self_closing
|
|
161
|
+
str = " />" + (nuke_outer_whitespace ? "" : "\n")
|
|
108
162
|
else
|
|
109
|
-
str = "
|
|
163
|
+
str = ">" + (try_one_line || preserve_tag || nuke_inner_whitespace ? "" : "\n")
|
|
110
164
|
end
|
|
111
|
-
|
|
165
|
+
|
|
166
|
+
attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
|
|
167
|
+
@buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
|
|
168
|
+
|
|
112
169
|
if content
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
else
|
|
116
|
-
@buffer << "\n#{tabs(@real_tabs+1)}#{content}\n#{tabs(@real_tabs)}</#{name}>\n"
|
|
117
|
-
end
|
|
118
|
-
else
|
|
119
|
-
@real_tabs += 1
|
|
170
|
+
@buffer << "#{content}</#{name}>" << (nuke_outer_whitespace ? "" : "\n")
|
|
171
|
+
return
|
|
120
172
|
end
|
|
173
|
+
|
|
174
|
+
@real_tabs += 1 unless self_closing || nuke_inner_whitespace
|
|
121
175
|
end
|
|
122
176
|
|
|
123
177
|
def self.merge_attrs(to, from)
|
|
124
178
|
if to['id'] && from['id']
|
|
125
179
|
to['id'] << '_' << from.delete('id')
|
|
180
|
+
elsif to['id'] || from['id']
|
|
181
|
+
from['id'] ||= to['id']
|
|
126
182
|
end
|
|
127
183
|
|
|
128
184
|
if to['class'] && from['class']
|
|
129
185
|
# Make sure we don't duplicate class names
|
|
130
186
|
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
|
|
187
|
+
elsif to['class'] || from['class']
|
|
188
|
+
from['class'] ||= to['class']
|
|
131
189
|
end
|
|
132
190
|
|
|
133
191
|
to.merge!(from)
|
|
134
192
|
end
|
|
135
193
|
|
|
194
|
+
private
|
|
195
|
+
|
|
136
196
|
# Some of these methods are exposed as public class methods
|
|
137
197
|
# so they can be re-used in helpers.
|
|
138
198
|
|
|
139
|
-
# Returns whether or not the given value is short enough to be rendered
|
|
140
|
-
# on one line.
|
|
141
|
-
def self.one_liner?(value)
|
|
142
|
-
value.length <= ONE_LINER_LENGTH && value.scan(/\n/).empty?
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
private
|
|
146
|
-
|
|
147
199
|
@@tab_cache = {}
|
|
148
200
|
# Gets <tt>count</tt> tabs. Mostly for internal use.
|
|
149
|
-
def tabs(count)
|
|
150
|
-
tabs = count + @tabulation
|
|
151
|
-
' ' * tabs
|
|
201
|
+
def tabs(count = 0)
|
|
202
|
+
tabs = [count + @tabulation, 0].max
|
|
152
203
|
@@tab_cache[tabs] ||= ' ' * tabs
|
|
153
204
|
end
|
|
154
205
|
|
|
155
206
|
# Takes an array of objects and uses the class and id of the first
|
|
156
207
|
# one to create an attributes hash.
|
|
208
|
+
# The second object, if present, is used as a prefix,
|
|
209
|
+
# just like you can do with dom_id() and dom_class() in Rails
|
|
157
210
|
def parse_object_ref(ref)
|
|
211
|
+
prefix = ref[1]
|
|
158
212
|
ref = ref[0]
|
|
159
213
|
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
|
160
214
|
return {} if ref.nil?
|
|
161
215
|
class_name = underscore(ref.class)
|
|
162
216
|
id = "#{class_name}_#{ref.id || 'new'}"
|
|
217
|
+
if prefix
|
|
218
|
+
class_name = "#{ prefix }_#{ class_name}"
|
|
219
|
+
id = "#{ prefix }_#{ id }"
|
|
220
|
+
end
|
|
163
221
|
|
|
164
222
|
{'id' => id, 'class' => class_name}
|
|
165
223
|
end
|
data/lib/haml/engine.rb
CHANGED
|
@@ -3,7 +3,6 @@ require 'haml/buffer'
|
|
|
3
3
|
require 'haml/precompiler'
|
|
4
4
|
require 'haml/filters'
|
|
5
5
|
require 'haml/error'
|
|
6
|
-
require 'haml/util'
|
|
7
6
|
|
|
8
7
|
module Haml
|
|
9
8
|
# This is the class where all the parsing and processing of the Haml
|
|
@@ -20,57 +19,87 @@ module Haml
|
|
|
20
19
|
# Allow reading and writing of the options hash
|
|
21
20
|
attr :options, true
|
|
22
21
|
|
|
22
|
+
# This string contains the source code that is evaluated
|
|
23
|
+
# to produce the Haml document.
|
|
24
|
+
attr :precompiled, true
|
|
25
|
+
|
|
26
|
+
# True if the format is XHTML
|
|
27
|
+
def xhtml?
|
|
28
|
+
not html?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# True if the format is any flavor of HTML
|
|
32
|
+
def html?
|
|
33
|
+
html4? or html5?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# True if the format is HTML4
|
|
37
|
+
def html4?
|
|
38
|
+
@options[:format] == :html4
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# True if the format is HTML5
|
|
42
|
+
def html5?
|
|
43
|
+
@options[:format] == :html5
|
|
44
|
+
end
|
|
45
|
+
|
|
23
46
|
# Creates a new instace of Haml::Engine that will compile the given
|
|
24
47
|
# template string when <tt>render</tt> is called.
|
|
25
|
-
# See
|
|
48
|
+
# See the Haml module documentation for available options.
|
|
26
49
|
#
|
|
27
50
|
#--
|
|
28
51
|
# When adding options, remember to add information about them
|
|
29
|
-
# to
|
|
52
|
+
# to lib/haml.rb!
|
|
30
53
|
#++
|
|
31
54
|
#
|
|
32
55
|
def initialize(template, options = {})
|
|
33
56
|
@options = {
|
|
34
57
|
:suppress_eval => false,
|
|
35
58
|
:attr_wrapper => "'",
|
|
36
|
-
:autoclose => ['meta', 'img', 'link', 'br', 'hr', 'input', 'area'],
|
|
37
|
-
:filters => {
|
|
38
|
-
'sass' => Sass::Engine,
|
|
39
|
-
'plain' => Haml::Filters::Plain,
|
|
40
|
-
'preserve' => Haml::Filters::Preserve,
|
|
41
|
-
'redcloth' => Haml::Filters::RedCloth,
|
|
42
|
-
'textile' => Haml::Filters::Textile,
|
|
43
|
-
'markdown' => Haml::Filters::Markdown },
|
|
44
|
-
:filename => '(haml)'
|
|
45
|
-
}
|
|
46
|
-
@options.rec_merge! options
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
'ruby' => Haml::Filters::Ruby
|
|
52
|
-
})
|
|
53
|
-
end
|
|
54
|
-
@options[:filters].rec_merge! options[:filters] if options[:filters]
|
|
60
|
+
# Don't forget to update the docs in lib/haml.rb if you update these
|
|
61
|
+
:autoclose => %w[meta img link br hr input area param col base],
|
|
62
|
+
:preserve => %w[textarea pre],
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
:filename => '(haml)',
|
|
65
|
+
:line => 1,
|
|
66
|
+
:ugly => false,
|
|
67
|
+
:format => :xhtml,
|
|
68
|
+
:escape_html => false
|
|
69
|
+
}
|
|
70
|
+
@options.merge! options
|
|
71
|
+
@index = 0
|
|
72
|
+
|
|
73
|
+
unless [:xhtml, :html4, :html5].include?(@options[:format])
|
|
74
|
+
raise Haml::Error, "Invalid format #{@options[:format].inspect}"
|
|
62
75
|
end
|
|
63
76
|
|
|
64
|
-
@template = template.
|
|
77
|
+
@template = template.rstrip + "\n-#\n-#"
|
|
65
78
|
@to_close_stack = []
|
|
66
79
|
@output_tabs = 0
|
|
67
80
|
@template_tabs = 0
|
|
68
|
-
@index = 0
|
|
69
81
|
@flat_spaces = -1
|
|
82
|
+
@flat = false
|
|
83
|
+
@newlines = 0
|
|
84
|
+
@precompiled = ''
|
|
85
|
+
@merged_text = ''
|
|
86
|
+
@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.1.
|
|
96
|
+
Filters are now automatically registered.
|
|
97
|
+
END
|
|
98
|
+
end
|
|
70
99
|
|
|
71
100
|
precompile
|
|
72
|
-
rescue Haml::Error
|
|
73
|
-
|
|
101
|
+
rescue Haml::Error => e
|
|
102
|
+
e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
|
|
74
103
|
raise
|
|
75
104
|
end
|
|
76
105
|
|
|
@@ -80,7 +109,7 @@ END
|
|
|
80
109
|
# If it's a Binding or Proc object,
|
|
81
110
|
# Haml uses it as the second argument to Kernel#eval;
|
|
82
111
|
# otherwise, Haml just uses its #instance_eval context.
|
|
83
|
-
#
|
|
112
|
+
#
|
|
84
113
|
# Note that Haml modifies the evaluation context
|
|
85
114
|
# (either the scope object or the "self" object of the scope binding).
|
|
86
115
|
# It extends Haml::Helpers, and various instance variables are set
|
|
@@ -110,8 +139,7 @@ END
|
|
|
110
139
|
# but if you're relying on local variables defined in the context of scope,
|
|
111
140
|
# they won't work.
|
|
112
141
|
def render(scope = Object.new, locals = {}, &block)
|
|
113
|
-
|
|
114
|
-
buffer = Haml::Buffer.new(options_for_buffer)
|
|
142
|
+
buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
|
|
115
143
|
|
|
116
144
|
if scope.is_a?(Binding) || scope.is_a?(Proc)
|
|
117
145
|
scope_object = eval("self", scope)
|
|
@@ -125,17 +153,14 @@ END
|
|
|
125
153
|
|
|
126
154
|
scope_object.instance_eval do
|
|
127
155
|
extend Haml::Helpers
|
|
128
|
-
@
|
|
129
|
-
@haml_stack.push(buffer)
|
|
130
|
-
@haml_is_haml = true
|
|
156
|
+
@haml_buffer = buffer
|
|
131
157
|
end
|
|
132
158
|
|
|
133
|
-
eval(@precompiled, scope, @options[:filename],
|
|
159
|
+
eval(@precompiled, scope, @options[:filename], @options[:line])
|
|
134
160
|
|
|
135
161
|
# Get rid of the current buffer
|
|
136
162
|
scope_object.instance_eval do
|
|
137
|
-
@
|
|
138
|
-
@haml_is_haml = false
|
|
163
|
+
@haml_buffer = buffer.upper
|
|
139
164
|
end
|
|
140
165
|
|
|
141
166
|
buffer.buffer
|
|
@@ -172,7 +197,7 @@ END
|
|
|
172
197
|
end
|
|
173
198
|
|
|
174
199
|
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
|
|
175
|
-
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename],
|
|
200
|
+
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
|
|
176
201
|
end
|
|
177
202
|
|
|
178
203
|
# Defines a method on +object+
|
|
@@ -189,7 +214,7 @@ END
|
|
|
189
214
|
#
|
|
190
215
|
# Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
|
|
191
216
|
# "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
|
|
192
|
-
#
|
|
217
|
+
#
|
|
193
218
|
# The first argument of the defined method is a hash of local variable names to values.
|
|
194
219
|
# However, due to an unfortunate Ruby quirk,
|
|
195
220
|
# the local variables which can be assigned must be pre-declared.
|
|
@@ -205,7 +230,7 @@ END
|
|
|
205
230
|
# obj = Object.new
|
|
206
231
|
# Haml::Engine.new("%p= foo").def_method(obj, :render)
|
|
207
232
|
# obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
|
|
208
|
-
#
|
|
233
|
+
#
|
|
209
234
|
# Note that Haml modifies the evaluation context
|
|
210
235
|
# (either the scope object or the "self" object of the scope binding).
|
|
211
236
|
# It extends Haml::Helpers, and various instance variables are set
|
|
@@ -214,7 +239,7 @@ END
|
|
|
214
239
|
method = object.is_a?(Module) ? :module_eval : :instance_eval
|
|
215
240
|
|
|
216
241
|
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
|
|
217
|
-
@options[:filename],
|
|
242
|
+
@options[:filename], @options[:line])
|
|
218
243
|
end
|
|
219
244
|
|
|
220
245
|
private
|
|
@@ -226,9 +251,15 @@ END
|
|
|
226
251
|
end
|
|
227
252
|
|
|
228
253
|
# Returns a hash of options that Haml::Buffer cares about.
|
|
229
|
-
# This should remain loadable
|
|
254
|
+
# This should remain loadable from #inspect.
|
|
230
255
|
def options_for_buffer
|
|
231
|
-
{
|
|
256
|
+
{
|
|
257
|
+
:autoclose => @options[:autoclose],
|
|
258
|
+
:preserve => @options[:preserve],
|
|
259
|
+
:attr_wrapper => @options[:attr_wrapper],
|
|
260
|
+
:ugly => @options[:ugly],
|
|
261
|
+
:format => @options[:format]
|
|
262
|
+
}
|
|
232
263
|
end
|
|
233
264
|
end
|
|
234
265
|
end
|
data/lib/haml/error.rb
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
module Haml
|
|
2
|
-
#
|
|
3
|
-
class Error < StandardError
|
|
2
|
+
# An exception raised by Haml code.
|
|
3
|
+
class Error < StandardError
|
|
4
|
+
# :stopdoc:
|
|
5
|
+
|
|
6
|
+
# By default, an error is taken to refer to the line of the template
|
|
7
|
+
# that was being processed when the exception was raised.
|
|
8
|
+
# However, if line is non-nil, it + 1 is used instead.
|
|
9
|
+
attr_reader :line
|
|
10
|
+
|
|
11
|
+
def initialize(message = nil, line = nil)
|
|
12
|
+
super(message)
|
|
13
|
+
@line = line
|
|
14
|
+
end
|
|
15
|
+
# :startdoc:
|
|
16
|
+
end
|
|
4
17
|
|
|
5
18
|
# SyntaxError is the type of exception raised when Haml encounters an
|
|
6
19
|
# ill-formatted document.
|
|
7
20
|
# It's not particularly interesting, except in that it includes Haml::Error.
|
|
8
21
|
class SyntaxError < Haml::Error; end
|
|
9
|
-
|
|
10
|
-
# HamlError is the type of exception raised when Haml encounters an error
|
|
11
|
-
# not of a syntactical nature, such as an undefined Filter.
|
|
12
|
-
class HamlError < Haml::Error; end
|
|
13
22
|
end
|
data/lib/haml/exec.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/../haml'
|
|
2
1
|
require 'optparse'
|
|
2
|
+
require 'fileutils'
|
|
3
3
|
|
|
4
4
|
module Haml
|
|
5
5
|
# This module contains code for working with the
|
|
@@ -21,7 +21,7 @@ module Haml
|
|
|
21
21
|
@opts.parse!(@args)
|
|
22
22
|
|
|
23
23
|
process_result
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
@options
|
|
26
26
|
rescue Exception => e
|
|
27
27
|
raise e if e.is_a? SystemExit
|
|
@@ -43,9 +43,13 @@ module Haml
|
|
|
43
43
|
protected
|
|
44
44
|
|
|
45
45
|
def get_line(exception)
|
|
46
|
+
# SyntaxErrors have weird line reporting
|
|
47
|
+
# when there's trailing whitespace,
|
|
48
|
+
# which there is for Haml documents.
|
|
49
|
+
return exception.message.scan(/:(\d+)/)[0] if exception.is_a?(::SyntaxError)
|
|
46
50
|
exception.backtrace[0].scan(/:(\d+)/)[0]
|
|
47
51
|
end
|
|
48
|
-
|
|
52
|
+
|
|
49
53
|
private
|
|
50
54
|
|
|
51
55
|
def set_opts(opts)
|
|
@@ -63,7 +67,7 @@ module Haml
|
|
|
63
67
|
end
|
|
64
68
|
|
|
65
69
|
opts.on_tail("-v", "--version", "Print version") do
|
|
66
|
-
puts("Haml "
|
|
70
|
+
puts("Haml #{::Haml.version[:string]}")
|
|
67
71
|
exit
|
|
68
72
|
end
|
|
69
73
|
end
|
|
@@ -110,7 +114,7 @@ Description:
|
|
|
110
114
|
|
|
111
115
|
Options:
|
|
112
116
|
END
|
|
113
|
-
|
|
117
|
+
|
|
114
118
|
opts.on('--rails RAILS_DIR', "Install Haml and Sass from the Gem to a Rails project") do |dir|
|
|
115
119
|
original_dir = dir
|
|
116
120
|
|
|
@@ -124,8 +128,9 @@ END
|
|
|
124
128
|
dir = File.join(dir, 'haml')
|
|
125
129
|
|
|
126
130
|
if File.exists?(dir)
|
|
127
|
-
|
|
128
|
-
exit
|
|
131
|
+
print "Directory #{dir} already exists, overwrite [y/N]? "
|
|
132
|
+
exit if gets !~ /y/i
|
|
133
|
+
FileUtils.rm_rf(dir)
|
|
129
134
|
end
|
|
130
135
|
|
|
131
136
|
begin
|
|
@@ -145,6 +150,7 @@ END
|
|
|
145
150
|
end
|
|
146
151
|
|
|
147
152
|
opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
|
|
153
|
+
require 'stringio'
|
|
148
154
|
@options[:check_syntax] = true
|
|
149
155
|
@options[:output] = StringIO.new
|
|
150
156
|
end
|
|
@@ -170,7 +176,7 @@ END
|
|
|
170
176
|
super
|
|
171
177
|
|
|
172
178
|
opts.on('-t', '--style NAME',
|
|
173
|
-
'Output style. Can be nested (default), compact, or expanded.') do |name|
|
|
179
|
+
'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
|
|
174
180
|
@options[:for_engine][:style] = name.to_sym
|
|
175
181
|
end
|
|
176
182
|
end
|
|
@@ -204,6 +210,35 @@ END
|
|
|
204
210
|
def initialize(args)
|
|
205
211
|
super
|
|
206
212
|
@name = "Haml"
|
|
213
|
+
@options[:requires] = []
|
|
214
|
+
@options[:load_paths] = []
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def set_opts(opts)
|
|
218
|
+
super
|
|
219
|
+
|
|
220
|
+
opts.on('-t', '--style NAME',
|
|
221
|
+
'Output style. Can be indented (default) or ugly.') do |name|
|
|
222
|
+
@options[:for_engine][:ugly] = true if name.to_sym == :ugly
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
opts.on('-f', '--format NAME',
|
|
226
|
+
'Output format. Can be xhtml (default), html4, or html5.') do |name|
|
|
227
|
+
@options[:for_engine][:format] = name.to_sym
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
opts.on('-e', '--escape-html',
|
|
231
|
+
'Escape HTML characters (like ampersands and angle brackets) by default.') do
|
|
232
|
+
@options[:for_engine][:escape_html] = true
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
opts.on('-r', '--require FILE', "Same as 'ruby -r'.") do |file|
|
|
236
|
+
@options[:requires] << file
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
opts.on('-I', '--load-path PATH', "Same as 'ruby -I'.") do |path|
|
|
240
|
+
@options[:load_paths] << path
|
|
241
|
+
end
|
|
207
242
|
end
|
|
208
243
|
|
|
209
244
|
def process_result
|
|
@@ -220,13 +255,16 @@ END
|
|
|
220
255
|
puts "Syntax OK"
|
|
221
256
|
return
|
|
222
257
|
end
|
|
258
|
+
|
|
259
|
+
@options[:load_paths].each {|p| $LOAD_PATH << p}
|
|
260
|
+
@options[:requires].each {|f| require f}
|
|
223
261
|
result = engine.to_html
|
|
224
262
|
rescue Exception => e
|
|
225
263
|
raise e if @options[:trace]
|
|
226
264
|
|
|
227
265
|
case e
|
|
228
266
|
when ::Haml::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}"
|
|
229
|
-
when ::Haml::
|
|
267
|
+
when ::Haml::Error; raise "Haml error on line #{get_line e}: #{e.message}"
|
|
230
268
|
else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace."
|
|
231
269
|
end
|
|
232
270
|
end
|
|
@@ -266,6 +304,10 @@ END
|
|
|
266
304
|
@module_opts[:rhtml] = true
|
|
267
305
|
end
|
|
268
306
|
|
|
307
|
+
opts.on('--no-rhtml', "Don't parse RHTML tags.") do
|
|
308
|
+
@options[:no_rhtml] = true
|
|
309
|
+
end
|
|
310
|
+
|
|
269
311
|
opts.on('-x', '--xhtml', 'Parse the input using the more strict XHTML parser.') do
|
|
270
312
|
@module_opts[:xhtml] = true
|
|
271
313
|
end
|
|
@@ -279,6 +321,9 @@ END
|
|
|
279
321
|
input = @options[:input]
|
|
280
322
|
output = @options[:output]
|
|
281
323
|
|
|
324
|
+
@module_opts[:rhtml] ||= input.respond_to?(:path) && input.path =~ /\.(rhtml|erb)$/
|
|
325
|
+
@module_opts[:rhtml] &&= @options[:no_rhtml] != false
|
|
326
|
+
|
|
282
327
|
output.write(::Haml::HTML.new(input, @module_opts).render)
|
|
283
328
|
end
|
|
284
329
|
end
|
|
@@ -289,6 +334,8 @@ END
|
|
|
289
334
|
def initialize(args)
|
|
290
335
|
super
|
|
291
336
|
|
|
337
|
+
@module_opts = {}
|
|
338
|
+
|
|
292
339
|
require 'sass/css'
|
|
293
340
|
end
|
|
294
341
|
|
|
@@ -301,6 +348,10 @@ Description: Transforms a CSS file into corresponding Sass code.
|
|
|
301
348
|
Options:
|
|
302
349
|
END
|
|
303
350
|
|
|
351
|
+
opts.on('-a', '--alternate', 'Output using alternative Sass syntax (margin: 1px)') do
|
|
352
|
+
@module_opts[:alternate] = true
|
|
353
|
+
end
|
|
354
|
+
|
|
304
355
|
super
|
|
305
356
|
end
|
|
306
357
|
|
|
@@ -310,7 +361,7 @@ END
|
|
|
310
361
|
input = @options[:input]
|
|
311
362
|
output = @options[:output]
|
|
312
363
|
|
|
313
|
-
output.write(::Sass::CSS.new(input).render)
|
|
364
|
+
output.write(::Sass::CSS.new(input, @module_opts).render)
|
|
314
365
|
end
|
|
315
366
|
end
|
|
316
367
|
end
|