Module: ERB::Linter::Converter
Constant Summary collapse
- ATTR_NAME =
%r{[^\r\n\t\f\v= '"<>]*[^\r\n\t\f\v= '"<>/]}
- UNQUOTED_VALUE =
ATTR_NAME
- UNQUOTED_ATTR =
%r{#{ATTR_NAME}=#{UNQUOTED_VALUE}}
- SINGLE_QUOTE_ATTR =
%r{(?:#{ATTR_NAME}='[^']*')}
- DOUBLE_QUOTE_ATTR =
%r{(?:#{ATTR_NAME}="[^"]*")}
- ERB_TAG =
%r{<%.*?%>}
- HTML_ATTR =
%r{\s+#{SINGLE_QUOTE_ATTR}|\s+#{DOUBLE_QUOTE_ATTR}|\s+#{UNQUOTED_ATTR}|\s+#{ATTR_NAME}}
- HTML_TAG =
%r{(<\w+)((?:#{HTML_ATTR})*)(\s*)(/>|>)}m
Instance Method Summary collapse
-
#erb2html(source) ⇒ Object
(credit goes to the Deface gem for the original implementation).
Instance Method Details
#erb2html(source) ⇒ Object
(credit goes to the Deface gem for the original implementation)
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/erb/linter/converter.rb', line 23 def erb2html(source) source = +source # encode all erb tags so that the HTML looks valid = {} source.gsub!(ERB_TAG) do |tag| uid = ["ERB_", SecureRandom.uuid].join.delete('-') [uid] = tag uid end = Regexp.union(.keys) # transform/escape all the erb-attributes first source.gsub!(HTML_TAG).each do |match| line = Regexp.last_match.to_a[1..-1] tag = [line[0], line[2]+line[3]] # scan each attribute into an array attr_scanner = StringScanner.new(line[1]) attributes = [] attributes << (attr_scanner.scan(HTML_ATTR) or raise "Can't scan: #{attr_scanner.string}") until attr_scanner.eos? # attributes.compact! i = -1 attributes.map! do |attribute| if attribute.match?() space, attribute = attribute.scan(/\A(\s+)(.*)\z/m).flatten attribute.gsub!(, ) attribute = case attribute when /\A#{ERB_TAG}\z/ %{data-erb-#{i += 1}="#{CGI.escapeHTML(attribute)}"} when /\A#{ATTR_NAME}=/ name, value = attribute.split("=", 2) quote = '"' if value.match(/\A['"]/) quote = value[0] value = value[1...-1] end %{data-erb-#{name}=#{quote}#{CGI.escapeHTML(value)}#{quote}} else raise "Don't know how to process attribute: #{attribute.inspect}" end "#{space}#{attribute}" else attribute end end [tag[0], *attributes, tag[1]].join end # restore the encoded erb tags source.gsub!(, ) # replaces all <% %> not inside opening html tags replacements = [ { %r{<%\s*end\s*-?%>} => "</erb>" }, { %r{(^\s*)<%(\s*(?:else|elsif\b.*)\s*)-?%>} => "\\1</erb>\n\\1<erb silent erb-code-start\\2erb-code-end>" }, { "<%=" => "<erb loud erb-code-start" }, { "<%" => "<erb silent erb-code-start" }, { "-%>" => "erb-code-end>" }, { "%>" => "erb-code-end>" }, ] replacements.each{ |h| h.each { |replace, with| source.gsub! replace, with } } source.scan(/(erb-code-start)((?:(?!erb-code-end)[\s\S])*)(erb-code-end)/).each do |match| source.sub!("#{match[0]}#{match[1]}#{match[2]}") do |_m| code = match[1] # is nil when the parsing is broken, meaning it's an open expression if Ripper.sexp(code).nil? "erb-code=\"#{CGI.escapeHTML(code.gsub("\n", " "))}\"" else "erb-code=\"#{CGI.escapeHTML(code.gsub("\n", " "))}\"></erb" end end end source end |