tags # As a result the diff tags should be the "most inside" possible. def insert_tag(tagname, cssclass, words) unless words.any? { |word| tag?(word) } @content << wrap_text(words.join, tagname, cssclass) else loop do break if words.empty? @content << words and break if words.all? { |word| tag?(word) } # We are outside of a diff tag @content << words.shift while not words.empty? and tag?(words.first) @content << %(<#{tagname} class="#{cssclass}">) # We are inside a diff tag @content << words.shift until words.empty? or tag?(words.first) @content << %(#{tagname}>) end end end def wrap_text(text, tagname, cssclass) %(<#{tagname} class="#{cssclass}">#{text}#{tagname}>) end def explode(sequence) sequence.is_a?(String) ? sequence.split(//) : sequence end def end_of_tag?(char) char == '>' end def start_of_tag?(char) char == '<' end def whitespace?(char) char =~ /\s/ end def convert_html_to_list_of_words(x, use_brackets = false) mode = :char current_word = '' words = [] explode(x).each do |char| case mode when :tag if end_of_tag? char current_word << (use_brackets ? ']' : '>') words << current_word current_word = '' if whitespace?(char) mode = :whitespace else mode = :char end else current_word << char end when :char if start_of_tag? char words << current_word unless current_word.empty? current_word = (use_brackets ? '[' : '<') mode = :tag elsif /\s/.match char words << current_word unless current_word.empty? current_word = char mode = :whitespace else current_word << char end when :whitespace if start_of_tag? char words << current_word unless current_word.empty? current_word = (use_brackets ? '[' : '<') mode = :tag elsif /\s/.match char current_word << char else words << current_word unless current_word.empty? current_word = char mode = :char end else raise "Unknown mode #{mode.inspect}" end end words << current_word unless current_word.empty? words end end # of class Diff Builder def diff(a, b) DiffBuilder.new(a, b).build end end