class Ruumba::Parser
Responsible for extracting interpolated Ruby.
Constants
- ERB_REGEX
The regular expression to capture interpolated Ruby.
Attributes
region_start_marker[R]
Public Class Methods
new(region_start_marker = nil)
click to toggle source
# File lib/ruumba/parser.rb, line 11 def initialize(region_start_marker = nil) @region_start_marker = region_start_marker end
Public Instance Methods
extract(contents)
click to toggle source
Extracts Ruby code from an ERB template. @return [String] The extracted ruby code
# File lib/ruumba/parser.rb, line 17 def extract(contents) file_text, matches = parse(contents) extracted_ruby = +'' last_match = [0, 0] matches.each_with_index do |(start_index, end_index), index| handle_region_before(start_index, last_match.last, file_text, extracted_ruby) match_marker = "#{region_start_marker}_#{format('%010d', index + 1)}" if region_start_marker extracted_ruby << extract_match(file_text, start_index, end_index, match_marker) last_match = [start_index, end_index] end extracted_ruby << file_text[last_match.last..-1].gsub(/./, ' ') # if we replaced <%== with <%= raw, try to shift the columns back to the # left so they match the original again extracted_ruby.gsub!(/ raw/, 'raw') extracted_ruby end
replace(old_contents, new_contents)
click to toggle source
# File lib/ruumba/parser.rb, line 41 def replace(old_contents, new_contents) file_text, matches = parse(old_contents) auto_corrected_erb = +'' last_match = [0, 0] matches.each_with_index do |(start_index, end_index), index| match_start = start_index prev_end_index = last_match.last if start_index > prev_end_index region_before = file_text[prev_end_index..match_start - 1] auto_corrected_erb << region_before end suffix = format('%010d', index + 1) match_marker = "#{region_start_marker}_#{suffix}" match_without_markers = new_contents[/\n#{match_marker}$\n(.*)\n#{match_marker}\n/m, 1] # auto-correct is still experimental and can cause invalid ruby to be generated when extracting ruby from ERBs return nil unless match_without_markers auto_corrected_erb << match_without_markers last_match = [start_index, end_index] end auto_corrected_erb << file_text[last_match.last..-1] auto_corrected_erb end
Private Instance Methods
extract_match(file_text, start_index, end_index, match_marker)
click to toggle source
# File lib/ruumba/parser.rb, line 110 def extract_match(file_text, start_index, end_index, match_marker) file_text[start_index...end_index].tap do |region| # if there is a ruby comment inside, replace the beginning of each line # with the '#' so we end up with valid ruby if region[0] == '#' region.gsub!(/^ /, '#') region.gsub!(/^(?!#)/, '#') end if match_marker region.prepend("\n", match_marker, "\n") region.concat("\n", match_marker, "\n") end end end
handle_region_before(match_start, prev_end_index, file_text, extracted_ruby)
click to toggle source
# File lib/ruumba/parser.rb, line 90 def handle_region_before(match_start, prev_end_index, file_text, extracted_ruby) return unless match_start > prev_end_index last_position = extracted_ruby.length region_before = file_text[prev_end_index..match_start - 1] region_before.gsub!(/./, ' ') # if the last match was on the same line, we need to use a semicolon to # separate statements extracted_ruby[last_position] = ';' if needs_stmt_delimiter?(prev_end_index, region_before) extracted_ruby << region_before end
needs_stmt_delimiter?(last_match, region_before)
click to toggle source
# File lib/ruumba/parser.rb, line 106 def needs_stmt_delimiter?(last_match, region_before) last_match.positive? && region_before.index("\n").nil? end
parse(contents)
click to toggle source
# File lib/ruumba/parser.rb, line 79 def parse(contents) # http://edgeguides.rubyonrails.org/active_support_core_extensions.html#output-safety # replace '<%==' with '<%= raw' to avoid generating invalid ruby code file_text = contents.gsub(/<%==/, '<%= raw') matching_regions = file_text.enum_for(:scan, ERB_REGEX) .map { Regexp.last_match.offset(1) } [file_text, matching_regions] end