haml 2.2.24 → 3.0.0.beta.1
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 +0 -1
- data/README.md +91 -151
- data/REMEMBER +11 -1
- data/Rakefile +73 -55
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/css2sass +7 -1
- data/bin/sass-convert +7 -0
- data/extra/haml-mode.el +2 -1
- data/lib/haml/buffer.rb +22 -4
- data/lib/haml/engine.rb +5 -1
- data/lib/haml/exec.rb +231 -46
- data/lib/haml/filters.rb +19 -8
- data/lib/haml/helpers.rb +47 -20
- data/lib/haml/helpers/action_view_extensions.rb +2 -4
- data/lib/haml/helpers/action_view_mods.rb +11 -8
- data/lib/haml/helpers/xss_mods.rb +13 -2
- data/lib/haml/html.rb +179 -48
- data/lib/haml/html/erb.rb +141 -0
- data/lib/haml/precompiler.rb +40 -15
- data/lib/haml/railtie.rb +1 -5
- data/lib/haml/root.rb +3 -0
- data/lib/haml/template.rb +4 -14
- data/lib/haml/util.rb +120 -30
- data/lib/haml/version.rb +25 -2
- data/lib/sass.rb +5 -1
- data/lib/sass/callbacks.rb +50 -0
- data/lib/sass/css.rb +40 -191
- data/lib/sass/engine.rb +170 -74
- data/lib/sass/environment.rb +8 -2
- data/lib/sass/error.rb +163 -25
- data/lib/sass/files.rb +31 -28
- data/lib/sass/plugin.rb +268 -87
- data/lib/sass/plugin/rails.rb +9 -4
- data/lib/sass/repl.rb +1 -1
- data/lib/sass/script.rb +31 -29
- data/lib/sass/script/bool.rb +1 -0
- data/lib/sass/script/color.rb +290 -23
- data/lib/sass/script/css_lexer.rb +22 -0
- data/lib/sass/script/css_parser.rb +28 -0
- data/lib/sass/script/funcall.rb +22 -3
- data/lib/sass/script/functions.rb +523 -33
- data/lib/sass/script/interpolation.rb +42 -0
- data/lib/sass/script/lexer.rb +169 -52
- data/lib/sass/script/literal.rb +58 -9
- data/lib/sass/script/node.rb +79 -1
- data/lib/sass/script/number.rb +20 -5
- data/lib/sass/script/operation.rb +49 -3
- data/lib/sass/script/parser.rb +162 -28
- data/lib/sass/script/string.rb +50 -2
- data/lib/sass/script/unary_operation.rb +25 -2
- data/lib/sass/script/variable.rb +21 -4
- data/lib/sass/scss.rb +14 -0
- data/lib/sass/scss/css_parser.rb +39 -0
- data/lib/sass/scss/parser.rb +683 -0
- data/lib/sass/scss/rx.rb +112 -0
- data/lib/sass/scss/script_lexer.rb +13 -0
- data/lib/sass/scss/script_parser.rb +25 -0
- data/lib/sass/tree/comment_node.rb +69 -27
- data/lib/sass/tree/debug_node.rb +7 -2
- data/lib/sass/tree/directive_node.rb +41 -35
- data/lib/sass/tree/for_node.rb +6 -0
- data/lib/sass/tree/if_node.rb +13 -1
- data/lib/sass/tree/import_node.rb +52 -27
- data/lib/sass/tree/mixin_def_node.rb +18 -0
- data/lib/sass/tree/mixin_node.rb +41 -6
- data/lib/sass/tree/node.rb +197 -70
- data/lib/sass/tree/prop_node.rb +152 -57
- data/lib/sass/tree/root_node.rb +118 -0
- data/lib/sass/tree/rule_node.rb +193 -96
- data/lib/sass/tree/variable_node.rb +9 -5
- data/lib/sass/tree/while_node.rb +4 -0
- data/test/benchmark.rb +5 -5
- data/test/haml/engine_test.rb +147 -10
- data/test/haml/{rhtml/_av_partial_1.rhtml → erb/_av_partial_1.erb} +1 -1
- data/test/haml/{rhtml/_av_partial_2.rhtml → erb/_av_partial_2.erb} +1 -1
- data/test/haml/{rhtml/action_view.rhtml → erb/action_view.erb} +1 -1
- data/test/haml/{rhtml/standard.rhtml → erb/standard.erb} +0 -0
- data/test/haml/helper_test.rb +91 -24
- data/test/haml/html2haml/erb_tests.rb +410 -0
- data/test/haml/html2haml_test.rb +210 -66
- data/test/haml/results/filters.xhtml +1 -1
- data/test/haml/results/just_stuff.xhtml +2 -0
- data/test/haml/spec_test.rb +44 -0
- data/test/haml/template_test.rb +22 -2
- data/test/haml/templates/helpers.haml +0 -13
- data/test/haml/templates/just_stuff.haml +2 -0
- data/test/haml/util_test.rb +48 -0
- data/test/sass/callbacks_test.rb +61 -0
- data/test/sass/conversion_test.rb +884 -0
- data/test/sass/css2sass_test.rb +99 -18
- data/test/sass/data/hsl-rgb.txt +319 -0
- data/test/sass/engine_test.rb +1049 -131
- data/test/sass/functions_test.rb +398 -47
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more_import.sass +3 -3
- data/test/sass/plugin_test.rb +184 -10
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +5 -5
- data/test/sass/results/compressed.css +1 -1
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +3 -1
- data/test/sass/results/mixins.css +12 -12
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/options.css +1 -0
- data/test/sass/results/parent_ref.css +4 -4
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +15 -0
- data/test/sass/results/scss_importee.css +2 -0
- data/test/sass/script_conversion_test.rb +153 -0
- data/test/sass/script_test.rb +137 -70
- data/test/sass/scss/css_test.rb +811 -0
- data/test/sass/scss/rx_test.rb +156 -0
- data/test/sass/scss/scss_test.rb +871 -0
- data/test/sass/scss/test_helper.rb +37 -0
- data/test/sass/templates/alt.sass +2 -2
- data/test/sass/templates/bork1.sass +2 -0
- data/test/sass/templates/bork3.sass +2 -0
- data/test/sass/templates/bork4.sass +2 -0
- data/test/sass/templates/import.sass +4 -4
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/line_numbers.sass +1 -1
- data/test/sass/templates/mixin_bork.sass +5 -0
- data/test/sass/templates/mixins.sass +2 -2
- data/test/sass/templates/nested_bork1.sass +2 -0
- data/test/sass/templates/nested_bork2.sass +2 -0
- data/test/sass/templates/nested_bork3.sass +2 -0
- data/test/sass/templates/nested_bork4.sass +2 -0
- data/test/sass/templates/nested_mixin_bork.sass +6 -0
- data/test/sass/templates/options.sass +2 -0
- data/test/sass/templates/parent_ref.sass +2 -2
- data/test/sass/templates/script.sass +69 -69
- data/test/sass/templates/scss_import.scss +10 -0
- data/test/sass/templates/scss_importee.scss +1 -0
- data/test/sass/templates/units.sass +10 -10
- data/test/test_helper.rb +20 -8
- data/vendor/fssm/LICENSE +20 -0
- data/vendor/fssm/README.markdown +55 -0
- data/vendor/fssm/Rakefile +59 -0
- data/vendor/fssm/VERSION.yml +5 -0
- data/vendor/fssm/example.rb +9 -0
- data/vendor/fssm/fssm.gemspec +77 -0
- data/vendor/fssm/lib/fssm.rb +33 -0
- data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
- data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
- data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
- data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
- data/vendor/fssm/lib/fssm/monitor.rb +26 -0
- data/vendor/fssm/lib/fssm/path.rb +91 -0
- data/vendor/fssm/lib/fssm/pathname.rb +502 -0
- data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
- data/vendor/fssm/lib/fssm/state/file.rb +24 -0
- data/vendor/fssm/lib/fssm/support.rb +63 -0
- data/vendor/fssm/lib/fssm/tree.rb +176 -0
- data/vendor/fssm/profile/prof-cache.rb +40 -0
- data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
- data/vendor/fssm/profile/prof-pathname.rb +68 -0
- data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
- data/vendor/fssm/profile/prof.html +2379 -0
- data/vendor/fssm/spec/path_spec.rb +75 -0
- data/vendor/fssm/spec/root/duck/quack.txt +0 -0
- data/vendor/fssm/spec/root/file.css +0 -0
- data/vendor/fssm/spec/root/file.rb +0 -0
- data/vendor/fssm/spec/root/file.yml +0 -0
- data/vendor/fssm/spec/root/moo/cow.txt +0 -0
- data/vendor/fssm/spec/spec_helper.rb +14 -0
- metadata +94 -14
- data/test/sass/templates/bork.sass +0 -2
data/lib/haml/filters.rb
CHANGED
@@ -100,11 +100,7 @@ module Haml
|
|
100
100
|
if contains_interpolation?(text)
|
101
101
|
return if options[:suppress_eval]
|
102
102
|
|
103
|
-
text = unescape_interpolation(text).gsub(
|
104
|
-
escapes = $1.size
|
105
|
-
next s if escapes % 2 == 0
|
106
|
-
("\\" * (escapes - 1)) + "\n"
|
107
|
-
end
|
103
|
+
text = unescape_interpolation(text).gsub("\\n", "\n")
|
108
104
|
newline if text.gsub!(/\n"\Z/, "\\n\"")
|
109
105
|
push_script <<RUBY.strip, :escape_html => false
|
110
106
|
find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options))
|
@@ -210,6 +206,23 @@ END
|
|
210
206
|
end
|
211
207
|
end
|
212
208
|
|
209
|
+
# Surrounds the filtered text with `<style>` and CDATA tags.
|
210
|
+
# Useful for including inline CSS.
|
211
|
+
module Css
|
212
|
+
include Base
|
213
|
+
|
214
|
+
# @see Base#render_with_options
|
215
|
+
def render_with_options(text, options)
|
216
|
+
<<END
|
217
|
+
<style type=#{options[:attr_wrapper]}text/css#{options[:attr_wrapper]}>
|
218
|
+
/*<![CDATA[*/
|
219
|
+
#{text.rstrip.gsub("\n", "\n ")}
|
220
|
+
/*]]>*/
|
221
|
+
</style>
|
222
|
+
END
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
213
226
|
# Surrounds the filtered text with CDATA tags.
|
214
227
|
module Cdata
|
215
228
|
include Base
|
@@ -281,7 +294,7 @@ END
|
|
281
294
|
end
|
282
295
|
end
|
283
296
|
|
284
|
-
# Parses the filtered text with ERB
|
297
|
+
# Parses the filtered text with ERB.
|
285
298
|
# Not available if the {file:HAML_REFERENCE.md#suppress_eval-option `:suppress_eval`} option is set to true.
|
286
299
|
# Embedded Ruby code is evaluated in the same context as the Haml template.
|
287
300
|
module ERB
|
@@ -308,8 +321,6 @@ END
|
|
308
321
|
::RedCloth.new(text).to_html(:textile)
|
309
322
|
end
|
310
323
|
end
|
311
|
-
# An alias for the Textile filter,
|
312
|
-
# since the only available Textile parser is RedCloth.
|
313
324
|
RedCloth = Textile
|
314
325
|
Filters.defined['redcloth'] = RedCloth
|
315
326
|
|
data/lib/haml/helpers.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
if defined?(ActionView)
|
2
|
+
require 'haml/helpers/action_view_mods'
|
3
|
+
require 'haml/helpers/action_view_extensions'
|
4
|
+
end
|
5
|
+
|
1
6
|
module Haml
|
2
7
|
# This module contains various helpful methods to make it easier to do various tasks.
|
3
8
|
# {Haml::Helpers} is automatically included in the context
|
@@ -47,7 +52,8 @@ MESSAGE
|
|
47
52
|
|
48
53
|
self.extend self
|
49
54
|
|
50
|
-
@@action_view_defined =
|
55
|
+
@@action_view_defined = defined?(ActionView)
|
56
|
+
@@force_no_action_view = false
|
51
57
|
|
52
58
|
# @return [Boolean] Whether or not ActionView is loaded
|
53
59
|
def self.action_view?
|
@@ -359,22 +365,16 @@ MESSAGE
|
|
359
365
|
haml_buffer.capture_position = nil
|
360
366
|
end
|
361
367
|
|
362
|
-
# @deprecated This will be removed in version 3.0.
|
363
|
-
# @see #haml_concat
|
364
|
-
def puts(*args)
|
365
|
-
warn <<END
|
366
|
-
DEPRECATION WARNING:
|
367
|
-
The Haml #puts helper is deprecated and will be removed in version 3.0.
|
368
|
-
Use the #haml_concat helper instead.
|
369
|
-
END
|
370
|
-
haml_concat(*args)
|
371
|
-
end
|
372
|
-
|
373
368
|
# Outputs text directly to the Haml buffer, with the proper indentation.
|
374
369
|
#
|
375
370
|
# @param text [#to_s] The text to output
|
376
371
|
def haml_concat(text = "")
|
377
|
-
haml_buffer.
|
372
|
+
unless haml_buffer.options[:ugly] || haml_indent == 0
|
373
|
+
haml_buffer.buffer << haml_indent <<
|
374
|
+
text.to_s.gsub("\n", "\n" + haml_indent) << "\n"
|
375
|
+
else
|
376
|
+
haml_buffer.buffer << text.to_s << "\n"
|
377
|
+
end
|
378
378
|
ErrorReturn.new("haml_concat")
|
379
379
|
end
|
380
380
|
|
@@ -388,6 +388,11 @@ END
|
|
388
388
|
# If the block is a Haml block or outputs text using \{#haml\_concat},
|
389
389
|
# the text will be properly indented.
|
390
390
|
#
|
391
|
+
# `name` can be a string using the standard Haml class/id shorthand
|
392
|
+
# (e.g. "span#foo.bar", "#foo").
|
393
|
+
# Just like standard Haml tags, these class and id values
|
394
|
+
# will be merged with manually-specified attributes.
|
395
|
+
#
|
391
396
|
# `flags` is a list of symbol flags
|
392
397
|
# like those that can be put at the end of a Haml tag
|
393
398
|
# (`:/`, `:<`, and `:>`).
|
@@ -402,7 +407,7 @@ END
|
|
402
407
|
#
|
403
408
|
# haml_tag :table do
|
404
409
|
# haml_tag :tr do
|
405
|
-
# haml_tag
|
410
|
+
# haml_tag 'td.cell' do
|
406
411
|
# haml_tag :strong, "strong!"
|
407
412
|
# haml_concat "data"
|
408
413
|
# end
|
@@ -438,13 +443,14 @@ END
|
|
438
443
|
def haml_tag(name, *rest, &block)
|
439
444
|
ret = ErrorReturn.new("haml_tag")
|
440
445
|
|
441
|
-
name = name.to_s
|
442
446
|
text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
|
443
447
|
flags = []
|
444
448
|
flags << rest.shift while rest.first.is_a? Symbol
|
449
|
+
name, attrs = merge_name_and_attributes(name.to_s, rest.shift || {})
|
450
|
+
|
445
451
|
attributes = Haml::Precompiler.build_attributes(haml_buffer.html?,
|
446
452
|
haml_buffer.options[:attr_wrapper],
|
447
|
-
|
453
|
+
attrs)
|
448
454
|
|
449
455
|
if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
|
450
456
|
haml_concat "<#{name}#{attributes} />"
|
@@ -458,8 +464,17 @@ END
|
|
458
464
|
|
459
465
|
tag = "<#{name}#{attributes}>"
|
460
466
|
if block.nil?
|
461
|
-
|
462
|
-
|
467
|
+
text = text.to_s
|
468
|
+
if text.include?("\n")
|
469
|
+
haml_concat tag
|
470
|
+
tab_up
|
471
|
+
haml_concat text
|
472
|
+
tab_down
|
473
|
+
haml_concat "</#{name}>"
|
474
|
+
else
|
475
|
+
tag << text << "</#{name}>"
|
476
|
+
haml_concat tag
|
477
|
+
end
|
463
478
|
return ret
|
464
479
|
end
|
465
480
|
|
@@ -496,7 +511,7 @@ END
|
|
496
511
|
# @param text [String] The string to sanitize
|
497
512
|
# @return [String] The sanitized string
|
498
513
|
def html_escape(text)
|
499
|
-
|
514
|
+
text.to_s.gsub(/[\"><&]/n) {|s| HTML_ESCAPE[s]}
|
500
515
|
end
|
501
516
|
|
502
517
|
# Escapes HTML entities in `text`, but without escaping an ampersand
|
@@ -534,6 +549,17 @@ END
|
|
534
549
|
|
535
550
|
private
|
536
551
|
|
552
|
+
# Parses the tag name used for \{#haml\_tag}
|
553
|
+
# and merges it with the Ruby attributes hash.
|
554
|
+
def merge_name_and_attributes(name, attributes_hash = {})
|
555
|
+
# skip merging if no ids or classes found in name
|
556
|
+
return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
|
557
|
+
|
558
|
+
return $1 || "div", Buffer.merge_attrs(
|
559
|
+
Precompiler.parse_class_and_id($2),
|
560
|
+
Haml::Util.map_keys(attributes_hash) {|key| key.to_s})
|
561
|
+
end
|
562
|
+
|
537
563
|
# Runs a block of code with the given buffer as the currently active buffer.
|
538
564
|
#
|
539
565
|
# @param buffer [Haml::Buffer] The Haml buffer to use temporarily
|
@@ -566,10 +592,11 @@ END
|
|
566
592
|
_erbout = _hamlout.buffer
|
567
593
|
proc { |*args| proc.call(*args) }
|
568
594
|
end
|
595
|
+
|
596
|
+
include ActionViewExtensions if self.const_defined? "ActionViewExtensions"
|
569
597
|
end
|
570
598
|
end
|
571
599
|
|
572
|
-
# @private
|
573
600
|
class Object
|
574
601
|
# Haml overrides various `ActionView` helpers,
|
575
602
|
# which call an \{#is\_haml?} method
|
@@ -1,7 +1,7 @@
|
|
1
|
+
require 'haml/helpers/action_view_mods'
|
2
|
+
|
1
3
|
module Haml
|
2
4
|
module Helpers
|
3
|
-
@@action_view_defined = true
|
4
|
-
|
5
5
|
# This module contains various useful helper methods
|
6
6
|
# that either tie into ActionView or the rest of the ActionPack stack,
|
7
7
|
# or are only useful in that context.
|
@@ -51,7 +51,5 @@ module Haml
|
|
51
51
|
@_haml_concat_raw = old
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
55
|
-
include ActionViewExtensions
|
56
54
|
end
|
57
55
|
end
|
@@ -125,12 +125,9 @@ module ActionView
|
|
125
125
|
@template_object.send :is_haml?
|
126
126
|
end
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
return error_wrapping(html_tag) if method(:error_wrapping).arity == 1
|
132
|
-
return html_tag unless object.respond_to?(:errors) && object.errors.respond_to?(:on)
|
133
|
-
return error_wrapping(html_tag, object.errors.on(@method_name))
|
128
|
+
unless defined?(ActionView::Helpers) && defined?(ActionView::Helpers::ActiveRecordInstanceTag)
|
129
|
+
alias_method :content_tag_without_haml, :content_tag
|
130
|
+
alias_method :content_tag, :content_tag_with_haml
|
134
131
|
end
|
135
132
|
end
|
136
133
|
|
@@ -160,7 +157,9 @@ module ActionView
|
|
160
157
|
def form_for_with_haml(object_name, *args, &proc)
|
161
158
|
if block_given? && is_haml?
|
162
159
|
oldproc = proc
|
163
|
-
proc =
|
160
|
+
proc = haml_bind_proc do |*args|
|
161
|
+
with_tabs(1) {oldproc.call(*args)}
|
162
|
+
end
|
164
163
|
end
|
165
164
|
res = form_for_without_haml(object_name, *args, &proc)
|
166
165
|
res << "\n" if block_given? && is_haml?
|
@@ -185,7 +184,10 @@ module ActionView
|
|
185
184
|
concat haml_indent
|
186
185
|
end
|
187
186
|
res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) + "\n"
|
188
|
-
|
187
|
+
if block_given?
|
188
|
+
concat "\n"
|
189
|
+
return Haml::Helpers::ErrorReturn.new("form_tag")
|
190
|
+
end
|
189
191
|
res
|
190
192
|
else
|
191
193
|
form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc)
|
@@ -209,6 +211,7 @@ module ActionView
|
|
209
211
|
end
|
210
212
|
form_for_without_haml(object_name, *args, &proc)
|
211
213
|
concat "\n" if block_given? && is_haml?
|
214
|
+
Haml::Helpers::ErrorReturn.new("form_for") if is_haml?
|
212
215
|
end
|
213
216
|
alias_method :form_for_without_haml, :form_for
|
214
217
|
alias_method :form_for, :form_for_with_haml
|
@@ -92,6 +92,13 @@ module Haml
|
|
92
92
|
html_escape(text)
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
class ErrorReturn
|
97
|
+
# Any attempt to treat ErrorReturn as a string should cause it to blow up.
|
98
|
+
alias_method :html_safe, :to_s
|
99
|
+
alias_method :html_safe?, :to_s
|
100
|
+
alias_method :html_safe!, :to_s
|
101
|
+
end
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
@@ -112,7 +119,9 @@ module ActionView
|
|
112
119
|
|
113
120
|
module FormTagHelper
|
114
121
|
def form_tag_with_haml_xss(*args, &block)
|
115
|
-
|
122
|
+
res = form_tag_without_haml_xss(*args, &block)
|
123
|
+
res = Haml::Util.html_safe(res) unless block_given?
|
124
|
+
res
|
116
125
|
end
|
117
126
|
alias_method :form_tag_without_haml_xss, :form_tag
|
118
127
|
alias_method :form_tag, :form_tag_with_haml_xss
|
@@ -120,7 +129,9 @@ module ActionView
|
|
120
129
|
|
121
130
|
module FormHelper
|
122
131
|
def form_for_with_haml_xss(*args, &block)
|
123
|
-
|
132
|
+
res = form_for_without_haml_xss(*args, &block)
|
133
|
+
return Haml::Util.html_safe(res) if res.is_a?(String)
|
134
|
+
return res
|
124
135
|
end
|
125
136
|
alias_method :form_for_without_haml_xss, :form_for
|
126
137
|
alias_method :form_for, :form_for_with_haml_xss
|
data/lib/haml/html.rb
CHANGED
@@ -9,37 +9,75 @@ module Haml
|
|
9
9
|
# A module containing utility methods that every Hpricot node
|
10
10
|
# should have.
|
11
11
|
module Node
|
12
|
+
# Whether this node has already been converted to Haml.
|
13
|
+
# Only used for text nodes and elements.
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
attr_accessor :converted_to_haml
|
17
|
+
|
12
18
|
# Returns the Haml representation of the given node.
|
13
19
|
#
|
14
20
|
# @param tabs [Fixnum] The indentation level of the resulting Haml.
|
15
21
|
# @option options (see Haml::HTML#initialize)
|
16
22
|
def to_haml(tabs, options)
|
17
|
-
|
23
|
+
return "" if converted_to_haml || to_s.strip.empty?
|
24
|
+
text = uninterp(self.to_s)
|
25
|
+
node = next_node
|
26
|
+
while node.is_a?(::Hpricot::Elem) && node.name == "haml:loud"
|
27
|
+
node.converted_to_haml = true
|
28
|
+
text << '#{' <<
|
29
|
+
CGI.unescapeHTML(node.inner_text).gsub(/\n\s*/, ' ').strip << '}'
|
30
|
+
|
31
|
+
if node.next_node.is_a?(::Hpricot::Text)
|
32
|
+
node = node.next_node
|
33
|
+
text << uninterp(node.to_s)
|
34
|
+
node.converted_to_haml = true
|
35
|
+
end
|
36
|
+
|
37
|
+
node = node.next_node
|
38
|
+
end
|
39
|
+
return parse_text_with_interpolation(text, tabs)
|
18
40
|
end
|
19
41
|
|
20
42
|
private
|
21
43
|
|
44
|
+
def erb_to_interpolation(text, options)
|
45
|
+
return text unless options[:erb]
|
46
|
+
text = CGI.escapeHTML(uninterp(text))
|
47
|
+
%w[<haml:loud> </haml:loud>].each {|str| text.gsub!(CGI.escapeHTML(str), str)}
|
48
|
+
::Hpricot::XML(text).children.inject("") do |str, elem|
|
49
|
+
if elem.is_a?(::Hpricot::Text)
|
50
|
+
str + CGI.unescapeHTML(elem.to_s)
|
51
|
+
else # <haml:loud> element
|
52
|
+
str + '#{' + CGI.unescapeHTML(elem.innerText.strip) + '}'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
22
57
|
def tabulate(tabs)
|
23
58
|
' ' * tabs
|
24
59
|
end
|
25
60
|
|
61
|
+
def uninterp(text)
|
62
|
+
text.gsub('#{', '\#{') #'
|
63
|
+
end
|
64
|
+
|
26
65
|
def attr_hash
|
27
66
|
attributes.to_hash
|
28
67
|
end
|
29
68
|
|
30
69
|
def parse_text(text, tabs)
|
70
|
+
parse_text_with_interpolation(uninterp(text), tabs)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_text_with_interpolation(text, tabs)
|
31
74
|
text.strip!
|
32
|
-
text.
|
33
|
-
if text.empty?
|
34
|
-
String.new
|
35
|
-
else
|
36
|
-
lines = text.split("\n")
|
75
|
+
return "" if text.empty?
|
37
76
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
77
|
+
text.split("\n").map do |line|
|
78
|
+
line.strip!
|
79
|
+
"#{tabulate(tabs)}#{'\\' if Haml::Engine::SPECIAL_CHARACTERS.include?(line[0])}#{line}\n"
|
80
|
+
end.join
|
43
81
|
end
|
44
82
|
end
|
45
83
|
end
|
@@ -65,6 +103,9 @@ require 'hpricot'
|
|
65
103
|
module Haml
|
66
104
|
# Converts HTML documents into Haml templates.
|
67
105
|
# Depends on [Hpricot](http://github.com/whymirror/hpricot) for HTML parsing.
|
106
|
+
# If ERB conversion is being used, also depends on
|
107
|
+
# [Erubis](http://www.kuwata-lab.com/erubis) to parse the ERB
|
108
|
+
# and [ruby_parser](http://parsetree.rubyforge.org/) to parse the Ruby code.
|
68
109
|
#
|
69
110
|
# Example usage:
|
70
111
|
#
|
@@ -72,7 +113,7 @@ module Haml
|
|
72
113
|
# #=> "%a{:href => 'http://google.com'} Blat"
|
73
114
|
class HTML
|
74
115
|
# @param template [String, Hpricot::Node] The HTML template to convert
|
75
|
-
# @option options :
|
116
|
+
# @option options :erb [Boolean] (false) Whether or not to parse
|
76
117
|
# ERB's `<%= %>` and `<% %>` into Haml's `=` and `-`
|
77
118
|
# @option options :xhtml [Boolean] (false) Whether or not to parse
|
78
119
|
# the HTML strictly as XHTML
|
@@ -86,9 +127,11 @@ module Haml
|
|
86
127
|
template = template.read
|
87
128
|
end
|
88
129
|
|
89
|
-
|
90
|
-
|
91
|
-
|
130
|
+
template = Haml::Util.check_encoding(template) {|msg, line| raise Haml::Error.new(msg, line)}
|
131
|
+
|
132
|
+
if @options[:erb]
|
133
|
+
require 'haml/html/erb'
|
134
|
+
template = ERB.compile(template)
|
92
135
|
end
|
93
136
|
|
94
137
|
method = @options[:xhtml] ? Hpricot.method(:XML) : method(:Hpricot)
|
@@ -129,7 +172,9 @@ module Haml
|
|
129
172
|
class ::Hpricot::CData
|
130
173
|
# @see Haml::HTML::Node#to_haml
|
131
174
|
def to_haml(tabs, options)
|
132
|
-
|
175
|
+
content = parse_text_with_interpolation(
|
176
|
+
erb_to_interpolation(self.content, options), tabs + 1)
|
177
|
+
"#{tabulate(tabs)}:cdata\n#{content}"
|
133
178
|
end
|
134
179
|
end
|
135
180
|
|
@@ -140,9 +185,7 @@ module Haml
|
|
140
185
|
def to_haml(tabs, options)
|
141
186
|
attrs = public_id.nil? ? ["", "", ""] :
|
142
187
|
public_id.scan(/DTD\s+([^\s]+)\s*([^\s]*)\s*([^\s]*)\s*\/\//)[0]
|
143
|
-
if attrs == nil
|
144
|
-
raise Exception.new("Invalid doctype")
|
145
|
-
end
|
188
|
+
raise Haml::SyntaxError.new("Invalid doctype") if attrs == nil
|
146
189
|
|
147
190
|
type, version, strictness = attrs.map { |a| a.downcase }
|
148
191
|
if type == "html"
|
@@ -170,7 +213,17 @@ module Haml
|
|
170
213
|
class ::Hpricot::Comment
|
171
214
|
# @see Haml::HTML::Node#to_haml
|
172
215
|
def to_haml(tabs, options)
|
173
|
-
|
216
|
+
content = self.content
|
217
|
+
if content =~ /\A(\[[^\]]+\])>(.*)<!\[endif\]\z/m
|
218
|
+
condition = $1
|
219
|
+
content = $2
|
220
|
+
end
|
221
|
+
|
222
|
+
if content.include?("\n")
|
223
|
+
"#{tabulate(tabs)}/#{condition}\n#{parse_text(content, tabs + 1)}"
|
224
|
+
else
|
225
|
+
"#{tabulate(tabs)}/#{condition} #{content.strip}"
|
226
|
+
end
|
174
227
|
end
|
175
228
|
end
|
176
229
|
|
@@ -179,32 +232,104 @@ module Haml
|
|
179
232
|
class ::Hpricot::Elem
|
180
233
|
# @see Haml::HTML::Node#to_haml
|
181
234
|
def to_haml(tabs, options)
|
182
|
-
|
183
|
-
if
|
184
|
-
|
235
|
+
return "" if converted_to_haml
|
236
|
+
if name == "script" &&
|
237
|
+
(attr_hash['type'].nil? || attr_hash['type'] == "text/javascript") &&
|
238
|
+
(attr_hash.keys - ['type']).empty?
|
239
|
+
return to_haml_filter(:javascript, tabs, options)
|
240
|
+
elsif name == "style" &&
|
241
|
+
(attr_hash['type'].nil? || attr_hash['type'] == "text/css") &&
|
242
|
+
(attr_hash.keys - ['type']).empty?
|
243
|
+
return to_haml_filter(:css, tabs, options)
|
185
244
|
end
|
186
245
|
|
187
|
-
output
|
188
|
-
|
246
|
+
output = tabulate(tabs)
|
247
|
+
if options[:erb] && name[0...5] == 'haml:'
|
248
|
+
case name[5..-1]
|
249
|
+
when "loud"
|
250
|
+
lines = CGI.unescapeHTML(inner_text).split("\n").
|
251
|
+
map {|s| s.rstrip}.reject {|s| s.strip.empty?}
|
252
|
+
lines.first.gsub!(/^[ \t]*/, "= ")
|
253
|
+
|
254
|
+
if lines.size > 1 # Multiline script block
|
255
|
+
# Normalize the indentation so that the last line is the base
|
256
|
+
indent_str = lines.last[/^[ \t]*/]
|
257
|
+
indent_re = /^[ \t]{0,#{indent_str.count(" ") + 8 * indent_str.count("\t")}}/
|
258
|
+
lines.map! {|s| s.gsub!(indent_re, '')}
|
259
|
+
|
260
|
+
# Add an extra " " to make it indented relative to "= "
|
261
|
+
lines[1..-1].each {|s| s.gsub!(/^/, " ")}
|
262
|
+
|
263
|
+
# Add | at the end, properly aligned
|
264
|
+
length = lines.map {|s| s.size}.max + 1
|
265
|
+
lines.map! {|s| "%#{-length}s|" % s}
|
266
|
+
|
267
|
+
if next_sibling && next_sibling.is_a?(Hpricot::Elem) && next_sibling.name == "haml:loud" &&
|
268
|
+
next_sibling.inner_text.split("\n").reject {|s| s.strip.empty?}.size > 1
|
269
|
+
lines << "-#"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
return lines.map {|s| output + s + "\n"}.join
|
273
|
+
when "silent"
|
274
|
+
return CGI.unescapeHTML(inner_text).split("\n").map do |line|
|
275
|
+
next "" if line.strip.empty?
|
276
|
+
"#{output}- #{line.strip}\n"
|
277
|
+
end.join
|
278
|
+
when "block"
|
279
|
+
return render_children("", tabs, options)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
output << "%#{name}" unless name == 'div' &&
|
284
|
+
(static_id?(options) ||
|
285
|
+
static_classname?(options) &&
|
286
|
+
attr_hash['class'].split(' ').any?(&method(:haml_css_attr?)))
|
189
287
|
|
190
288
|
if attr_hash
|
191
289
|
if static_id?(options)
|
192
|
-
output
|
290
|
+
output << "##{attr_hash['id']}"
|
193
291
|
remove_attribute('id')
|
194
292
|
end
|
195
293
|
if static_classname?(options)
|
196
|
-
attr_hash['class'].split(' ').
|
294
|
+
leftover = attr_hash['class'].split(' ').reject do |c|
|
295
|
+
next unless haml_css_attr?(c)
|
296
|
+
output << ".#{c}"
|
297
|
+
end
|
197
298
|
remove_attribute('class')
|
299
|
+
set_attribute('class', leftover.join(' ')) unless leftover.empty?
|
198
300
|
end
|
199
|
-
output
|
301
|
+
output << haml_attributes(options) if attr_hash.length > 0
|
200
302
|
end
|
201
303
|
|
202
|
-
|
203
|
-
|
304
|
+
output << "/" if empty? && !etag
|
305
|
+
|
306
|
+
if children && children.size == 1
|
307
|
+
child = children.first
|
308
|
+
if child.is_a?(::Hpricot::Text)
|
309
|
+
if !child.to_s.include?("\n")
|
310
|
+
text = child.to_haml(tabs + 1, options)
|
311
|
+
return output + " " + text.lstrip.gsub(/^\\/, '') unless text.chomp.include?("\n")
|
312
|
+
return output + "\n" + text
|
313
|
+
elsif ["pre", "textarea"].include?(name) ||
|
314
|
+
(name == "code" && parent.is_a?(::Hpricot::Elem) && parent.name == "pre")
|
315
|
+
return output + "\n#{tabulate(tabs + 1)}:preserve\n" +
|
316
|
+
innerText.gsub(/^/, tabulate(tabs + 2))
|
317
|
+
end
|
318
|
+
elsif child.is_a?(::Hpricot::Elem) && child.name == "haml:loud"
|
319
|
+
return output + child.to_haml(tabs + 1, options).lstrip
|
320
|
+
end
|
204
321
|
end
|
322
|
+
|
323
|
+
render_children(output + "\n", tabs, options)
|
205
324
|
end
|
206
325
|
|
207
326
|
private
|
327
|
+
|
328
|
+
def render_children(so_far, tabs, options)
|
329
|
+
(self.children || []).inject(so_far) do |output, child|
|
330
|
+
output + child.to_haml(tabs + 1, options)
|
331
|
+
end
|
332
|
+
end
|
208
333
|
|
209
334
|
def dynamic_attributes
|
210
335
|
@dynamic_attributes ||= begin
|
@@ -221,47 +346,53 @@ module Haml
|
|
221
346
|
end
|
222
347
|
end
|
223
348
|
|
224
|
-
def
|
225
|
-
|
226
|
-
|
349
|
+
def to_haml_filter(filter, tabs, options)
|
350
|
+
content =
|
351
|
+
if children.first.is_a?(::Hpricot::CData)
|
352
|
+
children.first.content
|
353
|
+
else
|
354
|
+
CGI.unescapeHTML(self.innerText)
|
355
|
+
end
|
356
|
+
|
357
|
+
content = erb_to_interpolation(content, options)
|
358
|
+
content.gsub!(/\A\s*\n(\s*)/, '\1')
|
359
|
+
original_indent = content[/\A(\s*)/, 1]
|
360
|
+
if content.split("\n").all? {|l| l.strip.empty? || l =~ /^#{original_indent}/}
|
361
|
+
content.gsub!(/^#{original_indent}/, tabulate(tabs + 1))
|
362
|
+
end
|
227
363
|
|
228
|
-
|
229
|
-
text.split("\n").map { |line| "- #{line.strip}\n" }.join
|
364
|
+
"#{tabulate(tabs)}:#{filter}\n#{content}"
|
230
365
|
end
|
231
366
|
|
232
367
|
def static_attribute?(name, options)
|
233
|
-
attr_hash[name]
|
368
|
+
attr_hash[name] && !dynamic_attribute?(name, options)
|
234
369
|
end
|
235
370
|
|
236
371
|
def dynamic_attribute?(name, options)
|
237
|
-
options[:
|
372
|
+
options[:erb] and dynamic_attributes.key?(name)
|
238
373
|
end
|
239
374
|
|
240
375
|
def static_id?(options)
|
241
|
-
static_attribute?('id', options)
|
376
|
+
static_attribute?('id', options) && haml_css_attr?(attr_hash['id'])
|
242
377
|
end
|
243
378
|
|
244
379
|
def static_classname?(options)
|
245
380
|
static_attribute?('class', options)
|
246
381
|
end
|
247
382
|
|
383
|
+
def haml_css_attr?(attr)
|
384
|
+
attr =~ /^[-:\w]+$/
|
385
|
+
end
|
386
|
+
|
248
387
|
# Returns a string representation of an attributes hash
|
249
388
|
# that's prettier than that produced by Hash#inspect
|
250
389
|
def haml_attributes(options)
|
251
|
-
attrs = attr_hash.map do |name, value|
|
390
|
+
attrs = attr_hash.sort.map do |name, value|
|
252
391
|
value = dynamic_attribute?(name, options) ? dynamic_attributes[name] : value.inspect
|
253
392
|
name = name.index(/\W/) ? name.inspect : ":#{name}"
|
254
393
|
"#{name} => #{value}"
|
255
394
|
end
|
256
|
-
"{
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
private
|
261
|
-
|
262
|
-
def match_to_html(string, regex, tag)
|
263
|
-
string.gsub!(regex) do
|
264
|
-
"<haml:#{tag}>#{CGI.escapeHTML($1)}</haml:#{tag}>"
|
395
|
+
"{#{attrs.join(', ')}}"
|
265
396
|
end
|
266
397
|
end
|
267
398
|
end
|