Module: Haml::Util
Overview
A module containing various useful functions.
Class Method Summary collapse
- .escape_html(html) ⇒ Object
-
.escape_html_safe(html) ⇒ Object
TODO: Remove unescape_interpolation’s workaround and get rid of ‘respond_to?`.
Instance Method Summary collapse
-
#balance(scanner, start, finish, count = 0) ⇒ (String, String)
Moves a scanner through a balanced pair of characters.
-
#check_encoding(str) {|msg| ... } ⇒ String
Checks that the encoding of a string is valid and cleans up potential encoding gotchas like the UTF-8 BOM.
-
#check_haml_encoding(str) {|msg| ... } ⇒ String
Like #check_encoding, but also checks for a Ruby-style ‘-# coding:` comment at the beginning of the template and uses that encoding if it exists.
- #contains_interpolation?(str) ⇒ Boolean
-
#handle_interpolation(str) {|scan| ... } ⇒ String
Scans through a string looking for the interoplation-opening ‘#{` and, when it’s found, yields the scanner to the calling code so it can handle it properly.
-
#human_indentation(indentation) ⇒ String
Formats a string for use in error messages about indentation.
-
#inspect_obj(obj) ⇒ String
Like ‘Object#inspect`, but preserves non-ASCII characters rather than escaping them.
-
#rails_xss_safe? ⇒ Boolean
Whether or not ActionView’s XSS protection is available and enabled, as is the default for Rails 3.0+, and optional for version 2.3.5+.
-
#silence_warnings { ... } ⇒ Object
Silence all output to STDERR within a block.
- #unescape_interpolation(str, escape_html = nil) ⇒ Object
Class Method Details
.escape_html(html) ⇒ Object
80 81 82 |
# File 'ext/haml/haml.c', line 80 def self.escape_html(html) CGI.escapeHTML(html.to_s) end |
.escape_html_safe(html) ⇒ Object
TODO: Remove unescape_interpolation’s workaround and get rid of ‘respond_to?`.
30 31 32 |
# File 'lib/haml/util.rb', line 30 def self.escape_html_safe(html) (html.respond_to?(:html_safe?) && html.html_safe?) ? html : escape_html(html) end |
Instance Method Details
#balance(scanner, start, finish, count = 0) ⇒ (String, String)
Moves a scanner through a balanced pair of characters. For example:
Foo (Bar (Baz bang) bop) (Bang (bop bip))
^ ^
from to
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/haml/util.rb', line 171 def balance(scanner, start, finish, count = 0) str = ''.dup scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE) while scanner.scan(regexp) str << scanner.matched count += 1 if scanner.matched[-1] == start count -= 1 if scanner.matched[-1] == finish return [str.strip, scanner.rest] if count == 0 end end |
#check_encoding(str) {|msg| ... } ⇒ String
Checks that the encoding of a string is valid and cleans up potential encoding gotchas like the UTF-8 BOM. If it’s not, yields an error string describing the invalid character and the line on which it occurs.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/haml/util.rb', line 65 def check_encoding(str) if str.valid_encoding? # Get rid of the Unicode BOM if possible # Shortcut for UTF-8 which might be the majority case if str.encoding == Encoding::UTF_8 return str.gsub(/\A\uFEFF/, '') elsif str.encoding.name =~ /^UTF-(16|32)(BE|LE)?$/ return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding)), '') else return str end end encoding = str.encoding newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding(Encoding::ASCII_8BIT)) str.force_encoding(Encoding::ASCII_8BIT).split(newlines).each_with_index do |line, i| begin line.encode(encoding) rescue Encoding::UndefinedConversionError => e yield <<MSG.rstrip, i + 1 Invalid #{encoding.name} character #{e.error_char.dump} MSG end end return str end |
#check_haml_encoding(str) {|msg| ... } ⇒ String
Like #check_encoding, but also checks for a Ruby-style ‘-# coding:` comment at the beginning of the template and uses that encoding if it exists.
The Haml encoding rules are simple. If a ‘-# coding:` comment exists, we assume that that’s the original encoding of the document. Otherwise, we use whatever encoding Ruby has.
Haml uses the same rules for parsing coding comments as Ruby. This means that it can understand Emacs-style comments (e.g. ‘-*- encoding: “utf-8” -*-`), and also that it cannot understand non-ASCII-compatible encodings such as `UTF-16` and `UTF-32`.
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/haml/util.rb', line 112 def check_haml_encoding(str, &block) str = str.dup if str.frozen? bom, encoding = parse_haml_magic_comment(str) if encoding; str.force_encoding(encoding) elsif bom; str.force_encoding(Encoding::UTF_8) end return check_encoding(str, &block) end |
#contains_interpolation?(str) ⇒ Boolean
200 201 202 |
# File 'lib/haml/util.rb', line 200 def contains_interpolation?(str) /#[\{$@]/ === str end |
#handle_interpolation(str) {|scan| ... } ⇒ String
Scans through a string looking for the interoplation-opening ‘#{` and, when it’s found, yields the scanner to the calling code so it can handle it properly.
The scanner will have any backslashes immediately in front of the ‘#{` as the second capture group (`scan`), and the text prior to that as the first (`scan`).
150 151 152 153 154 |
# File 'lib/haml/util.rb', line 150 def handle_interpolation(str) scan = StringScanner.new(str) yield scan while scan.scan(/(.*?)(\\*)#([\{@$])/) scan.rest end |
#human_indentation(indentation) ⇒ String
Formats a string for use in error messages about indentation.
187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/haml/util.rb', line 187 def human_indentation(indentation) if !indentation.include?(?\t) noun = 'space' elsif !indentation.include?(?\s) noun = 'tab' else return indentation.inspect end singular = indentation.length == 1 "#{indentation.length} #{noun}#{'s' unless singular}" end |
#inspect_obj(obj) ⇒ String
Like ‘Object#inspect`, but preserves non-ASCII characters rather than escaping them. This is necessary so that the precompiled Haml template can be `#encode`d into `@options` before being evaluated.
129 130 131 132 133 134 135 136 137 138 |
# File 'lib/haml/util.rb', line 129 def inspect_obj(obj) case obj when String %Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.dump[1...-1]}}"! when Symbol ":#{inspect_obj(obj.to_s)}" else obj.inspect end end |
#rails_xss_safe? ⇒ Boolean
Whether or not ActionView’s XSS protection is available and enabled, as is the default for Rails 3.0+, and optional for version 2.3.5+. Overridden in haml/template.rb if this is the case.
51 52 53 |
# File 'lib/haml/util.rb', line 51 def rails_xss_safe? false end |
#silence_warnings { ... } ⇒ Object
Silence all output to STDERR within a block.
37 38 39 40 41 42 |
# File 'lib/haml/util.rb', line 37 def silence_warnings the_real_stderr, $stderr = $stderr, StringIO.new yield ensure $stderr = the_real_stderr end |
#unescape_interpolation(str, escape_html = nil) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/haml/util.rb', line 204 def unescape_interpolation(str, escape_html = nil) res = ''.dup rest = Haml::Util.handle_interpolation str.dump do |scan| escapes = (scan[2].size - 1) / 2 char = scan[3] # '{', '@' or '$' res << scan.matched[0...-3 - escapes] if escapes % 2 == 1 res << "\##{char}" else interpolated = if char == '{' balance(scan, ?{, ?}, 1)[0][0...-1] else scan.scan(/\w+/) end content = eval("\"#{interpolated}\"") content = "#{char}#{content}" if char == '@' || char == '$' content = "Haml::Util.escape_html_safe((#{content}).to_s)" if escape_html res << "\#{#{content}}" end end res + rest end |