Class: PatienceDiff::Differ

Inherits:
Object
  • Object
show all
Defined in:
lib/patience_diff/differ.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Differ

Options:

* :all_context: Output the entirety of each file. This overrides the sequence matcher's context setting.
* :line_ending: Delimiter to use when joining diff output. Defaults to $RS.
* :ignore_whitespace: Before comparing lines, strip trailing whitespace, and treat leading whitespace 
  as either present or not. Does not affect output.

Any additional options (e.g. :context) are passed on to the sequence matcher.



16
17
18
19
20
21
# File 'lib/patience_diff/differ.rb', line 16

def initialize(opts = {})
  @all_context = opts.delete(:all_context)
  @line_ending = opts.delete(:line_ending) || $RS
  @ignore_whitespace = opts.delete(:ignore_whitespace)
  @matcher = SequenceMatcher.new(opts)
end

Instance Attribute Details

#all_contextObject

Returns the value of attribute all_context.



8
9
10
# File 'lib/patience_diff/differ.rb', line 8

def all_context
  @all_context
end

#ignore_whitespaceObject

Returns the value of attribute ignore_whitespace.



8
9
10
# File 'lib/patience_diff/differ.rb', line 8

def ignore_whitespace
  @ignore_whitespace
end

#line_endingObject

Returns the value of attribute line_ending.



8
9
10
# File 'lib/patience_diff/differ.rb', line 8

def line_ending
  @line_ending
end

#matcherObject (readonly)

Returns the value of attribute matcher.



7
8
9
# File 'lib/patience_diff/differ.rb', line 7

def matcher
  @matcher
end

Instance Method Details

#diff_files(left_file, right_file, formatter = Formatter.new) ⇒ Object

Generates a unified diff from the contents of the files at the paths specified.



24
25
26
27
28
29
30
31
32
# File 'lib/patience_diff/differ.rb', line 24

def diff_files(left_file, right_file, formatter=Formatter.new)
  (left_data, left_timestamp), (right_data, right_timestamp) = [left_file, right_file].map do |filename|
    # Read in binary encoding, so that we can diff any encoding and split() won't complain
    File.open(filename, :external_encoding => Encoding::BINARY) do |file|
      [file.read.split($RS), file.mtime]
    end
  end
  diff_sequences(left_data, right_data, left_file, right_file, left_timestamp, right_timestamp, formatter)
end

#diff_sequences(left, right, left_name = nil, right_name = nil, left_timestamp = nil, right_timestamp = nil, formatter = Formatter.new) ⇒ Object

Generate a unified diff of the data specified. The left and right values should be strings, or any other indexable, sortable data. File names and timestamps do not affect the diff algorithm, but are used in the header text.



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
# File 'lib/patience_diff/differ.rb', line 36

def diff_sequences(left, right, left_name=nil, right_name=nil, left_timestamp=nil, right_timestamp=nil, formatter=Formatter.new)
  if @ignore_whitespace
    a = left.map  { |line| line.rstrip.gsub(/^\s+/, ' ') }
    b = right.map { |line| line.rstrip.gsub(/^\s+/, ' ') }
  else
    a = left
    b = right
  end
  
  if @all_context
    hunks = [@matcher.diff_opcodes(a, b)]
  else
    hunks = @matcher.grouped_opcodes(a, b)
  end
  
  return nil unless hunks.any?
  
  lines = []
  lines << formatter.render_header(left_name, right_name, left_timestamp, right_timestamp)
  last_hunk_end = -1
  hunks.each do |opcodes|
    lines << formatter.render_hunk(a, b, opcodes, last_hunk_end)
    last_hunk_end = opcodes.last[4]
  end
  lines.flatten.compact.join(@line_ending) + @line_ending
end