haml 1.8.2 → 2.0.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/FAQ +138 -0
- data/MIT-LICENSE +1 -1
- data/{README → README.rdoc} +66 -3
- data/Rakefile +111 -147
- data/VERSION +1 -1
- data/bin/css2sass +0 -0
- data/bin/haml +0 -0
- data/bin/html2haml +0 -0
- data/bin/sass +0 -0
- data/init.rb +6 -1
- data/lib/haml.rb +464 -201
- data/lib/haml/buffer.rb +117 -63
- data/lib/haml/engine.rb +63 -44
- data/lib/haml/error.rb +16 -6
- data/lib/haml/exec.rb +37 -7
- data/lib/haml/filters.rb +213 -68
- data/lib/haml/helpers.rb +95 -60
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +54 -6
- data/lib/haml/html.rb +6 -6
- data/lib/haml/precompiler.rb +254 -133
- data/lib/haml/template.rb +3 -6
- data/lib/haml/template/patch.rb +9 -2
- data/lib/haml/template/plugin.rb +52 -23
- data/lib/sass.rb +157 -12
- data/lib/sass/constant.rb +22 -22
- data/lib/sass/constant/color.rb +13 -13
- data/lib/sass/constant/literal.rb +7 -7
- data/lib/sass/constant/number.rb +9 -9
- data/lib/sass/constant/operation.rb +4 -4
- data/lib/sass/constant/string.rb +3 -3
- data/lib/sass/css.rb +104 -31
- data/lib/sass/engine.rb +120 -39
- data/lib/sass/error.rb +1 -1
- data/lib/sass/plugin.rb +14 -3
- data/lib/sass/plugin/merb.rb +6 -2
- 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/test/benchmark.rb +67 -80
- data/test/haml/engine_test.rb +284 -84
- data/test/haml/helper_test.rb +51 -15
- 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 +44 -15
- data/test/haml/results/helpers.xhtml +2 -3
- data/test/haml/results/just_stuff.xhtml +2 -6
- data/test/haml/results/nuke_inner_whitespace.xhtml +34 -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 +8 -15
- data/test/haml/templates/_partial.haml +1 -0
- data/test/haml/templates/filters.haml +48 -7
- data/test/haml/templates/just_stuff.haml +1 -2
- data/test/haml/templates/nuke_inner_whitespace.haml +26 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/tag_parsing.haml +0 -3
- data/test/haml/test_helper.rb +15 -0
- data/test/sass/engine_test.rb +80 -34
- data/test/sass/plugin_test.rb +1 -1
- 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/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
- metadata +65 -51
- data/lib/haml/util.rb +0 -18
- data/test/haml/runner.rb +0 -16
- data/test/profile.rb +0 -65
data/lib/haml/error.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
module Haml
|
2
|
-
#
|
3
|
-
class Error <
|
2
|
+
# An exception raised by Haml code.
|
3
|
+
class Error < Exception
|
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_offset is non-zero, it's added to that line number
|
9
|
+
# to get the line to report for the error.
|
10
|
+
attr_reader :line_offset
|
11
|
+
|
12
|
+
def initialize(message = nil, line_offset = 0)
|
13
|
+
super(message)
|
14
|
+
@line_offset = line_offset
|
15
|
+
end
|
16
|
+
# :startdoc:
|
17
|
+
end
|
4
18
|
|
5
19
|
# SyntaxError is the type of exception raised when Haml encounters an
|
6
20
|
# ill-formatted document.
|
7
21
|
# It's not particularly interesting, except in that it includes Haml::Error.
|
8
22
|
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
23
|
end
|
data/lib/haml/exec.rb
CHANGED
@@ -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
|
|
@@ -145,6 +149,7 @@ END
|
|
145
149
|
end
|
146
150
|
|
147
151
|
opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
|
152
|
+
require 'stringio'
|
148
153
|
@options[:check_syntax] = true
|
149
154
|
@options[:output] = StringIO.new
|
150
155
|
end
|
@@ -170,7 +175,7 @@ END
|
|
170
175
|
super
|
171
176
|
|
172
177
|
opts.on('-t', '--style NAME',
|
173
|
-
'Output style. Can be nested (default), compact, or expanded.') do |name|
|
178
|
+
'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
|
174
179
|
@options[:for_engine][:style] = name.to_sym
|
175
180
|
end
|
176
181
|
end
|
@@ -206,6 +211,25 @@ END
|
|
206
211
|
@name = "Haml"
|
207
212
|
end
|
208
213
|
|
214
|
+
def set_opts(opts)
|
215
|
+
super
|
216
|
+
|
217
|
+
opts.on('-t', '--style NAME',
|
218
|
+
'Output style. Can be indented (default) or ugly.') do |name|
|
219
|
+
@options[:for_engine][:ugly] = true if name.to_sym == :ugly
|
220
|
+
end
|
221
|
+
|
222
|
+
opts.on('-f', '--format NAME',
|
223
|
+
'Output format. Can be xhtml (default), html4, or html5.') do |name|
|
224
|
+
@options[:for_engine][:format] = name.to_sym
|
225
|
+
end
|
226
|
+
|
227
|
+
opts.on('-e', '--escape-html',
|
228
|
+
'Escape HTML characters (like ampersands and angle brackets) by default.') do
|
229
|
+
@options[:for_engine][:escape_html] = true
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
209
233
|
def process_result
|
210
234
|
super
|
211
235
|
input = @options[:input]
|
@@ -226,7 +250,7 @@ END
|
|
226
250
|
|
227
251
|
case e
|
228
252
|
when ::Haml::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}"
|
229
|
-
when ::Haml::
|
253
|
+
when ::Haml::Error; raise "Haml error on line #{get_line e}: #{e.message}"
|
230
254
|
else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace."
|
231
255
|
end
|
232
256
|
end
|
@@ -289,6 +313,8 @@ END
|
|
289
313
|
def initialize(args)
|
290
314
|
super
|
291
315
|
|
316
|
+
@module_opts = {}
|
317
|
+
|
292
318
|
require 'sass/css'
|
293
319
|
end
|
294
320
|
|
@@ -301,6 +327,10 @@ Description: Transforms a CSS file into corresponding Sass code.
|
|
301
327
|
Options:
|
302
328
|
END
|
303
329
|
|
330
|
+
opts.on('-a', '--alternate', 'Output using alternative Sass syntax (margin: 1px)') do
|
331
|
+
@module_opts[:alternate] = true
|
332
|
+
end
|
333
|
+
|
304
334
|
super
|
305
335
|
end
|
306
336
|
|
@@ -310,7 +340,7 @@ END
|
|
310
340
|
input = @options[:input]
|
311
341
|
output = @options[:output]
|
312
342
|
|
313
|
-
output.write(::Sass::CSS.new(input).render)
|
343
|
+
output.write(::Sass::CSS.new(input, @module_opts).render)
|
314
344
|
end
|
315
345
|
end
|
316
346
|
end
|
data/lib/haml/filters.rb
CHANGED
@@ -1,115 +1,260 @@
|
|
1
1
|
# This file contains redefinitions of and wrappers around various text
|
2
2
|
# filters so they can be used as Haml filters.
|
3
3
|
|
4
|
-
# :stopdoc:
|
5
|
-
|
6
|
-
require 'erb'
|
7
|
-
require 'sass/engine'
|
8
|
-
require 'stringio'
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'rubygems'
|
12
|
-
rescue LoadError; end
|
13
|
-
|
14
|
-
class ERB; alias_method :render, :result; end
|
15
|
-
|
16
4
|
module Haml
|
5
|
+
# The module containing the default filters,
|
6
|
+
# as well as the base module,
|
7
|
+
# Haml::Filters::Base.
|
17
8
|
module Filters
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
# Returns a hash of defined filters.
|
10
|
+
def self.defined
|
11
|
+
@defined ||= {}
|
12
|
+
end
|
22
13
|
|
23
|
-
|
24
|
-
|
14
|
+
# The base module for Haml filters.
|
15
|
+
# User-defined filters should be modules including this module.
|
16
|
+
#
|
17
|
+
# A user-defined filter should override either Base#render or Base #compile.
|
18
|
+
# Base#render is the most common.
|
19
|
+
# It takes a string, the filter source,
|
20
|
+
# and returns another string,
|
21
|
+
# the result of the filter.
|
22
|
+
# For example:
|
23
|
+
#
|
24
|
+
# module Haml::Filters::Sass
|
25
|
+
# include Haml::Filters::Base
|
26
|
+
#
|
27
|
+
# def render(text)
|
28
|
+
# ::Sass::Engine.new(text).render
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# For details on overriding #compile, see its documentation.
|
33
|
+
#
|
34
|
+
module Base
|
35
|
+
def self.included(base) # :nodoc:
|
36
|
+
Filters.defined[base.name.split("::").last.downcase] = base
|
37
|
+
base.extend(base)
|
25
38
|
end
|
26
|
-
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
# Takes a string, the source text that should be passed to the filter,
|
41
|
+
# and returns the string resulting from running the filter on <tt>text</tt>.
|
42
|
+
#
|
43
|
+
# This should be overridden in most individual filter modules
|
44
|
+
# to render text with the given filter.
|
45
|
+
# If compile is overridden, however, render doesn't need to be.
|
46
|
+
def render(text)
|
47
|
+
raise Error.new("#{self.inspect}#render not defined!")
|
31
48
|
end
|
32
49
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
Object.new.instance_eval(@text)
|
37
|
-
old_stdout, $stdout = $stdout, old_stdout
|
38
|
-
old_stdout.pos = 0
|
39
|
-
old_stdout.read
|
50
|
+
def internal_compile(*args) # :nodoc:
|
51
|
+
resolve_lazy_requires
|
52
|
+
compile(*args)
|
40
53
|
end
|
41
|
-
end
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
|
55
|
+
# compile should be overridden when a filter needs to have access
|
56
|
+
# to the Haml evaluation context.
|
57
|
+
# Rather than applying a filter to a string at compile-time,
|
58
|
+
# compile uses the Haml::Precompiler instance to compile the string to Ruby code
|
59
|
+
# that will be executed in the context of the active Haml template.
|
60
|
+
#
|
61
|
+
# Warning: the Haml::Precompiler interface is neither well-documented
|
62
|
+
# nor guaranteed to be stable.
|
63
|
+
# If you want to make use of it,
|
64
|
+
# you'll probably need to look at the source code
|
65
|
+
# and should test your filter when upgrading to new Haml versions.
|
66
|
+
def compile(precompiler, text)
|
67
|
+
resolve_lazy_requires
|
68
|
+
filter = self
|
69
|
+
precompiler.instance_eval do
|
70
|
+
if contains_interpolation?(text)
|
71
|
+
return if options[:suppress_eval]
|
72
|
+
|
73
|
+
push_script(<<RUBY, false)
|
74
|
+
find_and_preserve(#{filter.inspect}.render(#{unescape_interpolation(text)}))
|
75
|
+
RUBY
|
76
|
+
return
|
77
|
+
end
|
78
|
+
|
79
|
+
rendered = Haml::Helpers::find_and_preserve(filter.render(text), precompiler.options[:preserve])
|
80
|
+
|
81
|
+
if !options[:ugly]
|
82
|
+
push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
|
83
|
+
else
|
84
|
+
push_text(rendered.rstrip)
|
85
|
+
end
|
86
|
+
end
|
46
87
|
end
|
47
88
|
|
48
|
-
|
49
|
-
|
89
|
+
# This becomes a class method of modules that include Base.
|
90
|
+
# It allows the module to specify one or more Ruby files
|
91
|
+
# that Haml should try to require when compiling the filter.
|
92
|
+
#
|
93
|
+
# The first file specified is tried first,
|
94
|
+
# then the second, etc.
|
95
|
+
# If none are found, the compilation throws an exception.
|
96
|
+
#
|
97
|
+
# For example:
|
98
|
+
#
|
99
|
+
# module Haml::Filters::Markdown
|
100
|
+
# lazy_require 'bluecloth', 'redcloth'
|
101
|
+
#
|
102
|
+
# ...
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
def lazy_require(*reqs)
|
106
|
+
@lazy_requires = reqs
|
50
107
|
end
|
51
|
-
end
|
52
108
|
|
53
|
-
|
54
|
-
|
55
|
-
|
109
|
+
private
|
110
|
+
|
111
|
+
def resolve_lazy_requires
|
112
|
+
return unless @lazy_requires
|
113
|
+
|
114
|
+
@lazy_requires[0...-1].each do |req|
|
56
115
|
begin
|
57
116
|
@required = req
|
58
117
|
require @required
|
59
118
|
return
|
60
119
|
rescue LoadError; end # RCov doesn't see this, but it is run
|
61
120
|
end
|
62
|
-
|
121
|
+
|
63
122
|
begin
|
64
|
-
@required =
|
123
|
+
@required = @lazy_requires[-1]
|
65
124
|
require @required
|
66
125
|
rescue LoadError => e
|
67
126
|
classname = self.class.to_s.gsub(/\w+::/, '')
|
68
127
|
|
69
|
-
if
|
70
|
-
raise
|
128
|
+
if @lazy_requires.size == 1
|
129
|
+
raise Error.new("Can't run #{classname} filter; required file '#{@lazy_requires.first}' not found")
|
71
130
|
else
|
72
|
-
raise
|
131
|
+
raise Error.new("Can't run #{classname} filter; required #{@lazy_requires.map { |r| "'#{r}'" }.join(' or ')}, but none were found")
|
73
132
|
end
|
74
133
|
end
|
75
134
|
end
|
76
135
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# :stopdoc:
|
140
|
+
|
141
|
+
begin
|
142
|
+
require 'rubygems'
|
143
|
+
rescue LoadError; end
|
144
|
+
|
145
|
+
module Haml
|
146
|
+
module Filters
|
147
|
+
module Plain
|
148
|
+
include Base
|
149
|
+
|
150
|
+
def render(text); text; end
|
151
|
+
end
|
152
|
+
|
153
|
+
module Javascript
|
154
|
+
include Base
|
155
|
+
|
156
|
+
def render(text)
|
157
|
+
<<END
|
158
|
+
<script type='text/javascript'>
|
159
|
+
//<![CDATA[
|
160
|
+
#{text.rstrip.gsub("\n", "\n ")}
|
161
|
+
//]]>
|
162
|
+
</script>
|
163
|
+
END
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
module Cdata
|
168
|
+
include Base
|
169
|
+
|
170
|
+
def render(text)
|
171
|
+
"<![CDATA[#{("\n" + text).rstrip.gsub("\n", "\n ")}\n]]>"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
module Escaped
|
176
|
+
include Base
|
177
|
+
|
178
|
+
def render(text)
|
179
|
+
Haml::Helpers.html_escape text
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
module Ruby
|
184
|
+
include Base
|
185
|
+
lazy_require 'stringio'
|
186
|
+
|
187
|
+
def compile(precompiler, text)
|
188
|
+
return if precompiler.options[:suppress_eval]
|
189
|
+
precompiler.instance_eval do
|
190
|
+
push_silent <<-END.gsub("\n", ';')
|
191
|
+
_haml_old_stdout = $stdout
|
192
|
+
$stdout = StringIO.new(_hamlout.buffer, 'a')
|
193
|
+
#{text}
|
194
|
+
_haml_old_stdout, $stdout = $stdout, _haml_old_stdout
|
195
|
+
_haml_old_stdout.close
|
196
|
+
END
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
module Preserve
|
202
|
+
include Base
|
203
|
+
|
204
|
+
def render(text)
|
205
|
+
Haml::Helpers.preserve text
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
module Sass
|
210
|
+
include Base
|
211
|
+
lazy_require 'sass/engine'
|
212
|
+
|
213
|
+
def render(text)
|
214
|
+
::Sass::Engine.new(text).render
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
module ERB
|
219
|
+
include Base
|
220
|
+
lazy_require 'erb'
|
221
|
+
|
222
|
+
def compile(precompiler, text)
|
223
|
+
return if precompiler.options[:suppress_eval]
|
224
|
+
src = ::ERB.new(text).src.sub(/^_erbout = '';/, "").gsub("\n", ';')
|
225
|
+
precompiler.send(:push_silent, src)
|
82
226
|
end
|
227
|
+
end
|
228
|
+
|
229
|
+
module RedCloth
|
230
|
+
include Base
|
231
|
+
lazy_require 'redcloth'
|
83
232
|
|
84
|
-
def render
|
85
|
-
|
233
|
+
def render(text)
|
234
|
+
::RedCloth.new(text).to_html
|
86
235
|
end
|
87
236
|
end
|
88
|
-
|
237
|
+
|
89
238
|
# Uses RedCloth to provide only Textile (not Markdown) parsing
|
90
|
-
|
91
|
-
|
92
|
-
|
239
|
+
module Textile
|
240
|
+
include Base
|
241
|
+
lazy_require 'redcloth'
|
242
|
+
|
243
|
+
def render(text)
|
244
|
+
::RedCloth.new(text).to_html(:textile)
|
93
245
|
end
|
94
246
|
end
|
95
247
|
|
96
248
|
# Uses BlueCloth or RedCloth to provide only Markdown (not Textile) parsing
|
97
|
-
|
98
|
-
|
99
|
-
|
249
|
+
module Markdown
|
250
|
+
include Base
|
251
|
+
lazy_require 'bluecloth', 'redcloth'
|
100
252
|
|
253
|
+
def render(text)
|
101
254
|
if @required == 'bluecloth'
|
102
|
-
|
103
|
-
else
|
104
|
-
@engine = ::RedCloth.new(text)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def render
|
109
|
-
if @engine.is_a?(::BlueCloth)
|
110
|
-
@engine.to_html
|
255
|
+
::BlueCloth.new(text).to_html
|
111
256
|
else
|
112
|
-
|
257
|
+
::RedCloth.new(text).to_html(:markdown)
|
113
258
|
end
|
114
259
|
end
|
115
260
|
end
|