class Diffy::Diff

Constants

ORIGINAL_DEFAULT_OPTIONS

Attributes

default_format[W]
default_options[W]

default options passed to new Diff objects

options[R]
string1[R]
string2[R]

Public Class Methods

default_format() click to toggle source
# File lib/diffy/diff.rb, line 14
def default_format
  @default_format ||= :text
end
default_options() click to toggle source
# File lib/diffy/diff.rb, line 20
def default_options
  @default_options ||= ORIGINAL_DEFAULT_OPTIONS.dup
end
new(string1, string2, options = {}) click to toggle source

supported options

:diff

A cli options string passed to diff

:source

Either strings or files. Determines whether string1 and string2 should be interpreted as strings or file paths.

:include_diff_info

Include diff header info

:include_plus_and_minus_in_html

Show the +, -, ' ' at the beginning of lines in html output.

# File lib/diffy/diff.rb, line 35
def initialize(string1, string2, options = {})
  @options = self.class.default_options.merge(options)
  if ! ['strings', 'files'].include?(@options[:source])
    raise ArgumentError, "Invalid :source option #{@options[:source].inspect}. Supported options are 'strings' and 'files'."
  end
  @string1, @string2 = string1, string2
end

Public Instance Methods

diff() click to toggle source
# File lib/diffy/diff.rb, line 43
def diff
  @diff ||= begin
    paths = case options[:source]
      when 'strings'
        [tempfile(string1), tempfile(string2)]
      when 'files'
        [string1, string2]
      end

    if WINDOWS
      # don't use open3 on windows
      cmd = sprintf '"%s" %s %s', diff_bin, diff_options.join(' '), paths.map { |s| %("#{s}") }.join(' ')
      diff = `#{cmd}`
    else
      diff = Open3.popen3(diff_bin, *(diff_options + paths)) { |i, o, e| o.read }
    end
    diff.force_encoding('ASCII-8BIT') if diff.respond_to?(:valid_encoding?) && !diff.valid_encoding?
    if diff =~ /\A\s*\Z/ && !options[:allow_empty_diff]
      diff = case options[:source]
      when 'strings' then string1
      when 'files' then File.read(string1)
      end.gsub(/^/, " ")
    end
    diff
  end
ensure
  # unlink the tempfiles explicitly now that the diff is generated
  if defined? @tempfiles # to avoid Ruby warnings about undefined ins var.
    Array(@tempfiles).each do |t|
      begin
        # check that the path is not nil and file still exists.
        # REE seems to be very agressive with when it magically removes
        # tempfiles
        t.unlink if t.path && File.exist?(t.path)
      rescue => e
        warn "#{e.class}: #{e}"
        warn e.backtrace.join("\n")
      end
    end
  end
end
each() { |line| ... } click to toggle source
# File lib/diffy/diff.rb, line 85
def each
  lines = case @options[:include_diff_info]
  when false then diff.split("\n").reject{|x| x =~ /^(---|\+\+\+|@@|\\\\)/ }.map {|line| line + "\n" }
  when true then diff.split("\n").map {|line| line + "\n" }
  end
  if block_given?
    lines.each{|line| yield line}
  else
    lines.to_enum
  end
end
each_chunk() { |chunk| ... } click to toggle source
# File lib/diffy/diff.rb, line 97
def each_chunk
  old_state = nil
  chunks = inject([]) do |cc, line|
    state = line.each_char.first
    if state == old_state
      cc.last << line
    else
      cc.push line.dup
    end
    old_state = state
    cc
  end

  if block_given?
    chunks.each{|chunk| yield chunk }
  else
    chunks.to_enum
  end
end
tempfile(string) click to toggle source
# File lib/diffy/diff.rb, line 117
def tempfile(string)
  t = Tempfile.new('diffy')
  # ensure tempfiles aren't unlinked when GC runs by maintaining a
  # reference to them.
  @tempfiles ||=[]
  @tempfiles.push(t)
  t.print(string)
  t.flush
  t.close
  t.path
end
to_s(format = nil) click to toggle source
# File lib/diffy/diff.rb, line 129
def to_s(format = nil)
  format ||= self.class.default_format
  formats = Format.instance_methods(false).map{|x| x.to_s}
  if formats.include? format.to_s
    enum = self
    enum.extend Format
    enum.send format
  else
    raise ArgumentError,
      "Format #{format.inspect} not found in #{formats.inspect}"
  end
end

Private Instance Methods

diff_bin() click to toggle source
# File lib/diffy/diff.rb, line 144
def diff_bin
  return @@bin if @@bin

  if @@bin = ENV['DIFFY_DIFF']
    # system() trick from Minitest
    raise "Can't execute diff program '#@@bin'" unless system(@@bin, __FILE__, __FILE__)
    return @@bin
  end

  diffs = ['diff', 'ldiff']
  diffs.first << '.exe' if WINDOWS  # ldiff does not have exe extension
  @@bin = diffs.find { |name| system(name, __FILE__, __FILE__) }

  if @@bin.nil?
    raise "Can't find a diff executable in PATH #{ENV['PATH']}"
  end

  @@bin
end
diff_options() click to toggle source

options pass to diff program

# File lib/diffy/diff.rb, line 165
def diff_options
  Array(options[:context] ? "-U #{options[:context]}" : options[:diff])
end