class Murdoc::Scanner

Attributes

language[R]

Public Class Methods

new(language) click to toggle source
# File lib/murdoc/scanner.rb, line 7
def initialize(language)
  @language = language
end

Public Instance Methods

call(source, do_not_count_comment_lines = false) click to toggle source
# File lib/murdoc/scanner.rb, line 11
def call(source, do_not_count_comment_lines = false)
  paragraphs = []
  ss = StringScanner.new(source)
  line = i = src_line = 0

  loop do
    comment_lines = []
    code_lines = []

    # Multi line comments
    if has_mlc?
      while (ss.scan(mlcb_regex))
        comment = ''

        while (!ss.eos? && !ss.match?(/.*#{mlce_regex}/))
          i += 1
          comment << ss.scan(/.*?$/)
          comment << ss.getch.to_s
        end

        if (fragment = ss.scan(/.*#{mlce_regex}/))
          comment << fragment.sub(mlce_regex, '')
        end

        ss.scan(/[ \t]*\n/) # skip trailing whitespace and a newline
        comment_lines << remove_common_space_prefix(comment)
      end
    end

    # Single line comments
    if has_slc?
      while (ss.scan(slc_regex))
        comment = ''
        comment << ss.scan(/.*?$/)
        comment << ss.getch.to_s
        comment_lines << comment
        i += 1
      end
    end


    # Code
    empty_leading_lines_count = skip_empty_lines(ss)
    i += empty_leading_lines_count
    src_line += empty_leading_lines_count

    line = do_not_count_comment_lines ? src_line : i
    while (!comment_start?(ss) && !ss.eos?)
      code = ss.scan(/^.*?$/)
      code << ss.getch.to_s
      code_lines << code
      i += 1
      src_line += 1
    end

    code = post_process_code(code_lines.join(''))
    comments = post_process_comments(comment_lines.join(''))

    paragraphs << Paragraph.new(code,
                                comments,
                                line,
                                language.name)

    break if ss.eos?
  end

  paragraphs
end

Protected Instance Methods

comment_start?(ss) click to toggle source
# File lib/murdoc/scanner.rb, line 90
def comment_start?(ss)
  (has_slc? && ss.match?(slc_regex)) ||
      (has_mlc? && ss.match?(mlcb_regex))
end
has_mlc?() click to toggle source
# File lib/murdoc/scanner.rb, line 124
def has_mlc?
  language.comment_symbols[:multiline] &&
      language.comment_symbols[:multiline][:begin] &&
      language.comment_symbols[:multiline][:end]
end
has_slc?() click to toggle source
# File lib/murdoc/scanner.rb, line 115
def has_slc?
  !!language.comment_symbols[:single_line]
end
mlcb_regex() click to toggle source
# File lib/murdoc/scanner.rb, line 130
def mlcb_regex
  has_mlc? && /^[ \t]*#{Regexp.escape(language.comment_symbols[:multiline][:begin])}/
end
mlce_regex() click to toggle source
# File lib/murdoc/scanner.rb, line 134
def mlce_regex
  has_mlc? && /#{Regexp.escape(language.comment_symbols[:multiline][:end])}/
end
post_process_code(code) click to toggle source
# File lib/murdoc/scanner.rb, line 82
def post_process_code(code)
  code.rstrip
end
post_process_comments(comments) click to toggle source
# File lib/murdoc/scanner.rb, line 86
def post_process_comments(comments)
  comments.strip.gsub(/^\s(\S)/, '\\1')
end
remove_common_space_prefix(str) click to toggle source
# File lib/murdoc/scanner.rb, line 104
def remove_common_space_prefix(str)
  lines = str.split("\n")
  # delete empty leading and trailing lines
  lines.delete_at(0) while lines[0] && lines[0].empty?
  lines.delete_at(-1) while lines[-1] && lines[-1].empty?

  prefix_lengths =  lines.map {|l| l.match(/^( *)/)[1].length }.reject(&:zero?)
  prefix = ' ' * (prefix_lengths.min || 0)
  lines.map {|line| line.sub(/^#{prefix}/, '') }.join("\n")
end
skip_empty_lines(ss) click to toggle source
# File lib/murdoc/scanner.rb, line 95
def skip_empty_lines(ss)
  i = 0
  while (ss.scan(/\s*?$/) && !ss.eos?)
    i += 1
    ss.getch
  end
  i
end
slc_regex() click to toggle source
# File lib/murdoc/scanner.rb, line 119
def slc_regex
  return @slc_regex unless @slc_regex.nil?
  @slc_regex = has_slc? && /^[ \t]*#{Regexp.escape(language.comment_symbols[:single_line])}/
end