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
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'erubis'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
5
|
+
module Haml
|
6
|
+
class HTML
|
7
|
+
# A class for converting ERB code into a format that's easier
|
8
|
+
# for the {Haml::HTML} Hpricot-based parser to understand.
|
9
|
+
#
|
10
|
+
# Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers
|
11
|
+
# to parse the ERB in a reliable way,
|
12
|
+
# and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge
|
13
|
+
# to figure out whether a given chunk of Ruby code starts a block or not.
|
14
|
+
#
|
15
|
+
# The ERB tags are converted to HTML tags in the following way.
|
16
|
+
# `<% ... %>` is converted into `<haml:silent> ... </haml:silent>`.
|
17
|
+
# `<%= ... %>` is converted into `<haml:loud> ... </haml:loud>`.
|
18
|
+
# Finally, if either of these opens a Ruby block,
|
19
|
+
# `<haml:block> ... </haml:block>` will wrap the entire contents of the block -
|
20
|
+
# that is, everything that should be indented beneath the previous silent or loud tag.
|
21
|
+
class ERB < Erubis::Basic::Engine
|
22
|
+
# Compiles an ERB template into a HTML document containing `haml:` tags.
|
23
|
+
#
|
24
|
+
# @param template [String] The ERB template
|
25
|
+
# @return [String] The output document
|
26
|
+
# @see Haml::HTML::ERB
|
27
|
+
def self.compile(template)
|
28
|
+
new(template).src
|
29
|
+
end
|
30
|
+
|
31
|
+
# `html2haml` doesn't support HTML-escaped expressions.
|
32
|
+
def escaped_expr(code)
|
33
|
+
raise Haml::Error.new("html2haml doesn't support escaped expressions.")
|
34
|
+
end
|
35
|
+
|
36
|
+
# The ERB-to-Hamlized-HTML conversion has no preamble.
|
37
|
+
def add_preamble(src); end
|
38
|
+
|
39
|
+
# The ERB-to-Hamlized-HTML conversion has no postamble.
|
40
|
+
def add_postamble(src); end
|
41
|
+
|
42
|
+
# Concatenates the text onto the source buffer.
|
43
|
+
#
|
44
|
+
# @param src [String] The source buffer
|
45
|
+
# @param text [String] The raw text to add to the buffer
|
46
|
+
def add_text(src, text)
|
47
|
+
src << text
|
48
|
+
end
|
49
|
+
|
50
|
+
# Concatenates a silent Ruby statement onto the source buffer.
|
51
|
+
# This uses the `<haml:silent>` tag,
|
52
|
+
# and may close and/or open a Ruby block with the `<haml:block>` tag.
|
53
|
+
#
|
54
|
+
# In particular, a block is closed if this statement is some form of `end`,
|
55
|
+
# opened if it's a block opener like `do`, `if`, or `begin`,
|
56
|
+
# and both closed and opened if it's a mid-block keyword
|
57
|
+
# like `else` or `when`.
|
58
|
+
#
|
59
|
+
# @param src [String] The source buffer
|
60
|
+
# @param code [String] The Ruby statement to add to the buffer
|
61
|
+
def add_stmt(src, code)
|
62
|
+
src << '</haml:block>' if block_closer?(code) || mid_block?(code)
|
63
|
+
src << '<haml:silent>' << h(code) << '</haml:silent>' unless code.strip == "end"
|
64
|
+
src << '<haml:block>' if block_opener?(code) || mid_block?(code)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Concatenates a Ruby expression that's printed to the document
|
68
|
+
# onto the source buffer.
|
69
|
+
# This uses the `<haml:silent>` tag,
|
70
|
+
# and may open a Ruby block with the `<haml:block>` tag.
|
71
|
+
# An expression never closes a block.
|
72
|
+
#
|
73
|
+
# @param src [String] The source buffer
|
74
|
+
# @param code [String] The Ruby expression to add to the buffer
|
75
|
+
def add_expr_literal(src, code)
|
76
|
+
src << '<haml:loud>' << h(code) << '</haml:loud>'
|
77
|
+
src << '<haml:block>' if block_opener?(code)
|
78
|
+
end
|
79
|
+
|
80
|
+
# `html2haml` doesn't support debugging expressions.
|
81
|
+
def add_expr_debug(src, code)
|
82
|
+
raise Haml::Error.new("html2haml doesn't support debugging expressions.")
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# HTML-escaped some text (in practice, always Ruby code).
|
88
|
+
# A utility method.
|
89
|
+
#
|
90
|
+
# @param text [String] The text to escape
|
91
|
+
# @return [String] The escaped text
|
92
|
+
def h(text)
|
93
|
+
CGI.escapeHTML(text)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns whether the code is valid Ruby code on its own.
|
97
|
+
#
|
98
|
+
# @param code [String] Ruby code to check
|
99
|
+
# @return [Boolean]
|
100
|
+
def valid_ruby?(code)
|
101
|
+
RubyParser.new.parse(code)
|
102
|
+
rescue Racc::ParseError => e
|
103
|
+
false
|
104
|
+
end
|
105
|
+
|
106
|
+
# Checks if a string of Ruby code opens a block.
|
107
|
+
# This could either be something like `foo do |a|`
|
108
|
+
# or a keyword that requires a matching `end`
|
109
|
+
# like `if`, `begin`, or `case`.
|
110
|
+
#
|
111
|
+
# @param code [String] Ruby code to check
|
112
|
+
# @return [Boolean]
|
113
|
+
def block_opener?(code)
|
114
|
+
valid_ruby?(code + "\nend") ||
|
115
|
+
valid_ruby?(code + "\nwhen foo\nend")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Checks if a string of Ruby code closes a block.
|
119
|
+
# This is always `end` followed optionally by some method calls.
|
120
|
+
#
|
121
|
+
# @param code [String] Ruby code to check
|
122
|
+
# @return [Boolean]
|
123
|
+
def block_closer?(code)
|
124
|
+
valid_ruby?("begin\n" + code)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Checks if a string of Ruby code comes in the middle of a block.
|
128
|
+
# This could be a keyword like `else`, `rescue`, or `when`,
|
129
|
+
# or even `end` with a method call that takes a block.
|
130
|
+
#
|
131
|
+
# @param code [String] Ruby code to check
|
132
|
+
# @return [Boolean]
|
133
|
+
def mid_block?(code)
|
134
|
+
return if valid_ruby?(code)
|
135
|
+
valid_ruby?("if foo\n#{code}\nend") || # else, elsif
|
136
|
+
valid_ruby?("begin\n#{code}\nend") || # rescue, ensure
|
137
|
+
valid_ruby?("case foo\n#{code}\nend") # when
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/haml/precompiler.rb
CHANGED
@@ -146,7 +146,6 @@ END
|
|
146
146
|
class Line < Struct.new(:text, :unstripped, :full, :index, :precompiler, :eod)
|
147
147
|
alias_method :eod?, :eod
|
148
148
|
|
149
|
-
# @private
|
150
149
|
def tabs
|
151
150
|
line = self
|
152
151
|
@tabs ||= precompiler.instance_eval do
|
@@ -332,15 +331,23 @@ END
|
|
332
331
|
def flush_merged_text
|
333
332
|
return if @to_merge.empty?
|
334
333
|
|
335
|
-
|
334
|
+
str = ""
|
335
|
+
mtabs = 0
|
336
|
+
newlines = 0
|
337
|
+
@to_merge.each do |type, val, tabs|
|
336
338
|
case type
|
337
339
|
when :text
|
338
|
-
|
340
|
+
str << val.inspect[1...-1]
|
341
|
+
mtabs += tabs
|
339
342
|
when :script
|
340
343
|
if mtabs != 0 && !@options[:ugly]
|
341
344
|
val = "_hamlout.adjust_tabs(#{mtabs}); " + val
|
342
345
|
end
|
343
|
-
|
346
|
+
str << "\#{#{"\n" * newlines}#{val}}"
|
347
|
+
mtabs = 0
|
348
|
+
newlines = 0
|
349
|
+
when :newlines
|
350
|
+
newlines += val
|
344
351
|
else
|
345
352
|
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Precompiler@to_merge.")
|
346
353
|
end
|
@@ -348,10 +355,11 @@ END
|
|
348
355
|
|
349
356
|
@precompiled <<
|
350
357
|
if @options[:ugly]
|
351
|
-
"_hamlout.buffer << \"#{
|
358
|
+
"_hamlout.buffer << \"#{str}\";"
|
352
359
|
else
|
353
|
-
"_hamlout.push_text(\"#{
|
360
|
+
"_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
|
354
361
|
end
|
362
|
+
@precompiled << "\n" * newlines
|
355
363
|
@to_merge = []
|
356
364
|
@dont_tab_up_next_text = false
|
357
365
|
end
|
@@ -396,14 +404,14 @@ END
|
|
396
404
|
|
397
405
|
no_format = @options[:ugly] &&
|
398
406
|
!(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
|
399
|
-
|
400
|
-
|
407
|
+
output_expr = "(#{text}\n)"
|
408
|
+
static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
|
401
409
|
|
402
410
|
# Prerender tabulation unless we're in a tag
|
403
411
|
push_merged_text '' unless opts[:in_tag]
|
404
412
|
|
405
413
|
unless block_opened?
|
406
|
-
@to_merge << [:script, no_format ? "#{text}\n" : "
|
414
|
+
@to_merge << [:script, no_format ? "#{text}\n" : "#{static_method}(#{output_expr});"]
|
407
415
|
concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
|
408
416
|
@newlines -= 1
|
409
417
|
return
|
@@ -413,7 +421,7 @@ END
|
|
413
421
|
|
414
422
|
push_silent "haml_temp = #{text}"
|
415
423
|
newline_now
|
416
|
-
push_and_tabulate([:loud, "_hamlout.buffer << #{no_format ? "
|
424
|
+
push_and_tabulate([:loud, "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}",
|
417
425
|
!(opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly])])
|
418
426
|
end
|
419
427
|
|
@@ -491,10 +499,12 @@ END
|
|
491
499
|
@template_tabs -= 1
|
492
500
|
end
|
493
501
|
|
502
|
+
# This is a class method so it can be accessed from {Haml::Helpers}.
|
503
|
+
#
|
494
504
|
# Iterates through the classes and ids supplied through `.`
|
495
505
|
# and `#` syntax, and returns a hash with them as attributes,
|
496
506
|
# that can then be merged with another attributes hash.
|
497
|
-
def parse_class_and_id(list)
|
507
|
+
def self.parse_class_and_id(list)
|
498
508
|
attributes = {}
|
499
509
|
list.scan(/([#.])([-_a-zA-Z0-9]+)/) do |type, property|
|
500
510
|
case type
|
@@ -531,9 +541,18 @@ END
|
|
531
541
|
quote_escape = attr_wrapper == '"' ? """ : "'"
|
532
542
|
other_quote_char = attr_wrapper == '"' ? "'" : '"'
|
533
543
|
|
544
|
+
if attributes['data'].is_a?(Hash)
|
545
|
+
attributes = attributes.dup
|
546
|
+
attributes =
|
547
|
+
Haml::Util.map_keys(attributes.delete('data')) {|name| "data-#{name}"}.merge(attributes)
|
548
|
+
end
|
549
|
+
|
534
550
|
result = attributes.collect do |attr, value|
|
535
551
|
next if value.nil?
|
536
552
|
|
553
|
+
value = filter_and_join(value, ' ') if attr == :class
|
554
|
+
value = filter_and_join(value, '_') if attr == :id
|
555
|
+
|
537
556
|
if value == true
|
538
557
|
next " #{attr}" if is_html
|
539
558
|
next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
|
@@ -557,6 +576,11 @@ END
|
|
557
576
|
result.compact.sort.join
|
558
577
|
end
|
559
578
|
|
579
|
+
def self.filter_and_join(value, separator)
|
580
|
+
value = [value] unless value.is_a?(Array)
|
581
|
+
return value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
|
582
|
+
end
|
583
|
+
|
560
584
|
def prerender_tag(name, self_close, attributes)
|
561
585
|
attributes_string = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
|
562
586
|
"<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>"
|
@@ -744,7 +768,7 @@ END
|
|
744
768
|
|
745
769
|
object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
|
746
770
|
|
747
|
-
attributes = parse_class_and_id(attributes)
|
771
|
+
attributes = Precompiler.parse_class_and_id(attributes)
|
748
772
|
attributes_hashes.map! do |syntax, attributes_hash|
|
749
773
|
if syntax == :old
|
750
774
|
static_attributes = parse_static_hash(attributes_hash)
|
@@ -761,7 +785,7 @@ END
|
|
761
785
|
raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.", last_line - 1) if parse && value.empty?
|
762
786
|
raise SyntaxError.new("Self-closing tags can't have content.", last_line - 1) if self_closing && !value.empty?
|
763
787
|
|
764
|
-
self_closing ||= !!(
|
788
|
+
self_closing ||= !!(!block_opened? && value.empty? && @options[:autoclose].any? {|t| t === tag_name})
|
765
789
|
value = nil if value.empty? && (block_opened? || self_closing)
|
766
790
|
|
767
791
|
dont_indent_next_line =
|
@@ -1030,8 +1054,7 @@ END
|
|
1030
1054
|
|
1031
1055
|
def resolve_newlines
|
1032
1056
|
return unless @newlines > 0
|
1033
|
-
|
1034
|
-
@precompiled << "\n" * @newlines
|
1057
|
+
@to_merge << [:newlines, @newlines]
|
1035
1058
|
@newlines = 0
|
1036
1059
|
end
|
1037
1060
|
|
@@ -1055,6 +1078,8 @@ END
|
|
1055
1078
|
when :script
|
1056
1079
|
last[1].gsub!(/\(haml_temp, (.*?)\);$/, '(haml_temp.rstrip, \1);')
|
1057
1080
|
rstrip_buffer! index - 1
|
1081
|
+
when :newlines
|
1082
|
+
rstrip_buffer! index - 1
|
1058
1083
|
else
|
1059
1084
|
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Precompiler@to_merge.")
|
1060
1085
|
end
|
data/lib/haml/railtie.rb
CHANGED
@@ -3,11 +3,7 @@
|
|
3
3
|
# Yehuda promises there will be soon,
|
4
4
|
# and once there is we should switch to that.
|
5
5
|
|
6
|
-
if defined?(
|
7
|
-
# Rails 3.0.0.beta.2+
|
8
|
-
ActiveSupport.on_load(:action_view) {Haml.init_rails(binding)}
|
9
|
-
elsif defined?(Rails::Railtie)
|
10
|
-
# Rails 3.0.0.beta1
|
6
|
+
if defined?(Rails::Railtie)
|
11
7
|
module Haml
|
12
8
|
class Railtie < Rails::Railtie
|
13
9
|
initializer :haml do
|
data/lib/haml/root.rb
ADDED
data/lib/haml/template.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'haml/engine'
|
2
|
-
require 'haml/helpers/action_view_mods'
|
3
|
-
require 'haml/helpers/action_view_extensions'
|
4
2
|
|
5
3
|
module Haml
|
6
4
|
# The class that keeps track of the global options for Haml within Rails.
|
@@ -19,11 +17,7 @@ module Haml
|
|
19
17
|
#
|
20
18
|
# @return [Boolean] Whether the XSS integration was enabled.
|
21
19
|
def try_enabling_xss_integration
|
22
|
-
return false unless
|
23
|
-
# We check for ActiveSupport#on_load here because if we're loading Haml that way, it means:
|
24
|
-
# A) we're in Rails 3 so XSS support is always on, and
|
25
|
-
# B) we might be in Rails 3 beta 3 where the load order is broken and xss_safe? is undefined
|
26
|
-
(defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load))
|
20
|
+
return false unless ActionView::Base.respond_to?(:xss_safe?) && ActionView::Base.xss_safe?
|
27
21
|
|
28
22
|
Haml::Template.options[:escape_html] = true
|
29
23
|
|
@@ -59,14 +53,10 @@ else
|
|
59
53
|
require 'haml/template/patch'
|
60
54
|
end
|
61
55
|
|
62
|
-
# Enable XSS integration. Use Rails' after_initialize method
|
56
|
+
# Enable XSS integration. Use Rails' after_initialize method if possible
|
63
57
|
# so that integration will be checked after the rails_xss plugin is loaded
|
64
58
|
# (for Rails 2.3.* where it's not enabled by default).
|
65
|
-
|
66
|
-
# If we're running under Rails 3, though, we don't want to use after_intialize,
|
67
|
-
# since Haml loading has already been deferred via ActiveSupport.on_load.
|
68
|
-
if defined?(Rails.configuration.after_initialize) &&
|
69
|
-
!(defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load))
|
59
|
+
if defined?(Rails.configuration.after_initialize)
|
70
60
|
Rails.configuration.after_initialize {Haml::Template.try_enabling_xss_integration}
|
71
61
|
else
|
72
62
|
Haml::Template.try_enabling_xss_integration
|
@@ -87,7 +77,7 @@ if Haml::Util.rails_root
|
|
87
77
|
FileUtils.cp(haml_init_file, rails_init_file) unless FileUtils.cmp(rails_init_file, haml_init_file)
|
88
78
|
end
|
89
79
|
rescue SystemCallError
|
90
|
-
|
80
|
+
Haml::Util.haml_warn <<END
|
91
81
|
HAML WARNING:
|
92
82
|
#{rails_init_file} is out of date and couldn't be automatically updated.
|
93
83
|
Please run `haml --rails #{File.expand_path(Haml::Util.rails_root)}' to update it.
|
data/lib/haml/util.rb
CHANGED
@@ -2,6 +2,7 @@ require 'erb'
|
|
2
2
|
require 'set'
|
3
3
|
require 'enumerator'
|
4
4
|
require 'stringio'
|
5
|
+
require 'haml/root'
|
5
6
|
|
6
7
|
module Haml
|
7
8
|
# A module containing various useful functions.
|
@@ -16,7 +17,7 @@ module Haml
|
|
16
17
|
# @param file [String] The filename relative to the Haml root
|
17
18
|
# @return [String] The filename relative to the the working directory
|
18
19
|
def scope(file)
|
19
|
-
File.join(
|
20
|
+
File.join(Haml::ROOT_DIR, file)
|
20
21
|
end
|
21
22
|
|
22
23
|
# Converts an array of `[key, value]` pairs to a hash.
|
@@ -103,6 +104,17 @@ module Haml
|
|
103
104
|
end
|
104
105
|
end
|
105
106
|
|
107
|
+
# Restricts a number to falling within a given range.
|
108
|
+
# Returns the number if it falls within the range,
|
109
|
+
# or the closest value in the range if it doesn't.
|
110
|
+
#
|
111
|
+
# @param value [Numeric]
|
112
|
+
# @param range [Range<Numeric>]
|
113
|
+
# @return [Numeric]
|
114
|
+
def restrict(value, range)
|
115
|
+
[[value, range.first].max, range.last].min
|
116
|
+
end
|
117
|
+
|
106
118
|
# Concatenates all strings that are adjacent in an array,
|
107
119
|
# while leaving other elements as they are.
|
108
120
|
# For example:
|
@@ -123,6 +135,29 @@ module Haml
|
|
123
135
|
end
|
124
136
|
end
|
125
137
|
|
138
|
+
# Destructively strips whitespace from the beginning and end
|
139
|
+
# of the first and last elements, respectively,
|
140
|
+
# in the array (if those elements are strings).
|
141
|
+
#
|
142
|
+
# @param arr [Array]
|
143
|
+
# @return [Array] `arr`
|
144
|
+
def strip_string_array(arr)
|
145
|
+
arr.first.lstrip! if arr.first.is_a?(String)
|
146
|
+
arr.last.rstrip! if arr.last.is_a?(String)
|
147
|
+
arr
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns information about the caller of the previous method.
|
151
|
+
#
|
152
|
+
# @param entry [String] An entry in the `#caller` list, or a similarly formatted string
|
153
|
+
# @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller.
|
154
|
+
# The method name may be nil
|
155
|
+
def caller_info(entry = caller[1])
|
156
|
+
info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first
|
157
|
+
info[1] = info[1].to_i
|
158
|
+
info
|
159
|
+
end
|
160
|
+
|
126
161
|
# Silence all output to STDERR within a block.
|
127
162
|
#
|
128
163
|
# @yield A block in which no output will be printed to STDERR
|
@@ -133,6 +168,26 @@ module Haml
|
|
133
168
|
$stderr = the_real_stderr
|
134
169
|
end
|
135
170
|
|
171
|
+
@@silence_warnings = false
|
172
|
+
# Silences all Haml warnings within a block.
|
173
|
+
#
|
174
|
+
# @yield A block in which no Haml warnings will be printed
|
175
|
+
def silence_haml_warnings
|
176
|
+
old_silence_warnings = @@silence_warnings
|
177
|
+
@@silence_warnings = true
|
178
|
+
yield
|
179
|
+
ensure
|
180
|
+
@@silence_warnings = old_silence_warnings
|
181
|
+
end
|
182
|
+
|
183
|
+
# The same as `Kernel#warn`, but is silenced by \{#silence\_haml\_warnings}.
|
184
|
+
#
|
185
|
+
# @param msg [String]
|
186
|
+
def haml_warn(msg)
|
187
|
+
return if @@silence_warnings
|
188
|
+
warn(msg)
|
189
|
+
end
|
190
|
+
|
136
191
|
## Cross Rails Version Compatibility
|
137
192
|
|
138
193
|
# Returns the root of the Rails application,
|
@@ -182,30 +237,6 @@ module Haml
|
|
182
237
|
ActionPack::VERSION::TINY == "0.beta")
|
183
238
|
end
|
184
239
|
|
185
|
-
# Returns whether this environment is using ActionPack
|
186
|
-
# version 3.0.0.beta.3 or greater.
|
187
|
-
#
|
188
|
-
# @return [Boolean]
|
189
|
-
def ap_geq_3_beta_3?
|
190
|
-
# The ActionPack module is always loaded automatically in Rails >= 3
|
191
|
-
return false unless defined?(ActionPack) && defined?(ActionPack::VERSION)
|
192
|
-
|
193
|
-
version =
|
194
|
-
if defined?(ActionPack::VERSION::MAJOR)
|
195
|
-
ActionPack::VERSION::MAJOR
|
196
|
-
else
|
197
|
-
# Rails 1.2
|
198
|
-
ActionPack::VERSION::Major
|
199
|
-
end
|
200
|
-
version >= 3 &&
|
201
|
-
((defined?(ActionPack::VERSION::TINY) &&
|
202
|
-
ActionPack::VERSION::TINY.is_a?(Fixnum) &&
|
203
|
-
ActionPack::VERSION::TINY >= 1) ||
|
204
|
-
(defined?(ActionPack::VERSION::BUILD) &&
|
205
|
-
ActionPack::VERSION::BUILD =~ /beta(\d+)/ &&
|
206
|
-
$1.to_i >= 3))
|
207
|
-
end
|
208
|
-
|
209
240
|
# Returns an ActionView::Template* class.
|
210
241
|
# In pre-3.0 versions of Rails, most of these classes
|
211
242
|
# were of the form `ActionView::TemplateFoo`,
|
@@ -251,10 +282,6 @@ module Haml
|
|
251
282
|
raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.")
|
252
283
|
end
|
253
284
|
|
254
|
-
# The class for the Rails SafeBuffer XSS protection class.
|
255
|
-
# This varies depending on Rails version.
|
256
|
-
#
|
257
|
-
# @return [Class]
|
258
285
|
def rails_safe_buffer_class
|
259
286
|
return ActionView::SafeBuffer if defined?(ActionView::SafeBuffer)
|
260
287
|
ActiveSupport::SafeBuffer
|
@@ -269,6 +296,42 @@ module Haml
|
|
269
296
|
Haml::Util::RUBY_VERSION[0] == 1 && Haml::Util::RUBY_VERSION[1] < 9
|
270
297
|
end
|
271
298
|
|
299
|
+
# Checks that the encoding of a string is valid in Ruby 1.9
|
300
|
+
# and cleans up potential encoding gotchas like the UTF-8 BOM.
|
301
|
+
# If it's not, yields an error string describing the invalid character
|
302
|
+
# and the line on which it occurrs.
|
303
|
+
#
|
304
|
+
# @param str [String] The string of which to check the encoding
|
305
|
+
# @yield [msg] A block in which an encoding error can be raised.
|
306
|
+
# Only yields if there is an encoding error
|
307
|
+
# @yieldparam msg [String] The error message to be raised
|
308
|
+
# @return [String] `str`, potentially with encoding gotchas like BOMs removed
|
309
|
+
def check_encoding(str)
|
310
|
+
if ruby1_8?
|
311
|
+
return str.gsub(/\A\xEF\xBB\xBF/, '') # Get rid of the UTF-8 BOM
|
312
|
+
elsif str.valid_encoding?
|
313
|
+
# Get rid of the Unicode BOM if possible
|
314
|
+
if str.encoding.name =~ /^UTF-(8|16|32)(BE|LE)?$/
|
315
|
+
return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding.name)), '')
|
316
|
+
else
|
317
|
+
return str
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
encoding = str.encoding
|
322
|
+
newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding("binary"))
|
323
|
+
str.force_encoding("binary").split(newlines).each_with_index do |line, i|
|
324
|
+
begin
|
325
|
+
line.encode(encoding)
|
326
|
+
rescue Encoding::UndefinedConversionError => e
|
327
|
+
yield <<MSG.rstrip, i + 1
|
328
|
+
Invalid #{encoding.name} character #{e.error_char.dump}
|
329
|
+
MSG
|
330
|
+
end
|
331
|
+
end
|
332
|
+
return str
|
333
|
+
end
|
334
|
+
|
272
335
|
# Checks to see if a class has a given method.
|
273
336
|
# For example:
|
274
337
|
#
|
@@ -295,6 +358,32 @@ module Haml
|
|
295
358
|
ruby1_8? ? enum.enum_with_index : enum.each_with_index
|
296
359
|
end
|
297
360
|
|
361
|
+
# A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9.
|
362
|
+
#
|
363
|
+
# @param enum [Enumerable] The enumerable to get the enumerator for
|
364
|
+
# @param n [Fixnum] The size of each cons
|
365
|
+
# @return [Enumerator] The consed enumerator
|
366
|
+
def enum_cons(enum, n)
|
367
|
+
ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n)
|
368
|
+
end
|
369
|
+
|
370
|
+
# A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9.
|
371
|
+
#
|
372
|
+
# @param enum [Enumerable] The enumerable to get the enumerator for
|
373
|
+
# @param n [Fixnum] The size of each slice
|
374
|
+
# @return [Enumerator] The consed enumerator
|
375
|
+
def enum_slice(enum, n)
|
376
|
+
ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
|
377
|
+
end
|
378
|
+
|
379
|
+
# Returns the ASCII code of the given character.
|
380
|
+
#
|
381
|
+
# @param c [String] All characters but the first are ignored.
|
382
|
+
# @return [Fixnum] The ASCII code of `c`.
|
383
|
+
def ord(c)
|
384
|
+
ruby1_8? ? c[0] : c.ord
|
385
|
+
end
|
386
|
+
|
298
387
|
## Static Method Stuff
|
299
388
|
|
300
389
|
# The context in which the ERB for \{#def\_static\_method} will be run.
|
@@ -348,9 +437,10 @@ module Haml
|
|
348
437
|
# @param erb [String] The template for the method code
|
349
438
|
def def_static_method(klass, name, args, *vars)
|
350
439
|
erb = vars.pop
|
440
|
+
info = caller_info
|
351
441
|
powerset(vars).each do |set|
|
352
442
|
context = StaticConditionalContext.new(set).instance_eval {binding}
|
353
|
-
klass.class_eval(<<METHOD)
|
443
|
+
klass.class_eval(<<METHOD, info[0], info[1])
|
354
444
|
def #{static_method_name(name, *vars.map {|v| set.include?(v)})}(#{args.join(', ')})
|
355
445
|
#{ERB.new(erb).result(context)}
|
356
446
|
end
|