Class: Diff

Inherits:
Object
  • Object
show all
Defined in:
lib/walrus/diff.rb

Overview

Simple wrapper for diff(1).

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(left, right) ⇒ Diff

Returns a new instance of Diff.

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/walrus/diff.rb', line 17

def initialize(left, right)
  raise ArgumentError.new('left may not be nil') unless left
  raise ArgumentError.new('right may not be nil') unless right
  
  # keep a copy of the parameters (used by the diff method)
  @left   = left.clone
  @right  = right.clone
  
  if left.kind_of? Pathname and right.kind_of? Pathname
    @output = self.compare_pathname_with_pathname(left, right)
  elsif left.kind_of? String and right.kind_of? Pathname
    @output = self.compare_string_with_pathname(left, right)
  elsif left.kind_of? Pathname and right.kind_of? String
    @output = self.compare_pathname_with_string(left, right)
  elsif left.kind_of? String and right.kind_of? String
    @output = self.compare_string_with_string(left, right)
  else
    raise ArgumentError.new('unsupported argument types (%s, %s)' % [left.class.to_s, right.class.to_s])
  end
  
end

Class Method Details

.diff(left, right) ⇒ Object

Actually runs diff(1) with the supplied arguments (pathnames). One but not both of the arguments may be “-” to indicate the standard input.

Raises:

  • (ArgumentError)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/walrus/diff.rb', line 64

def self.diff(left, right)
  raise ArgumentError.new('left may not be ni') unless left
  raise ArgumentError.new('right may not be nil') unless right
  raise ArgumentError.new('only one parameter may be "-"') if left == '-' and right == '-'
  
  # no shell involved, so no need to escape shell metacharacters
  Open3.popen3('diff', '-u', left, right) do |stdin, stdout, stderr|
    if left == '-'
      stdin.write(@left)
    elsif right == '-'
      stdin.write(@right)
    end
    stdin.close_write
    
    # TODO: decide what to do with stderr output (if any)
    stderr.read
    return stdout.read
  end
  
end

Instance Method Details

#compare_pathname_with_pathname(left, right) ⇒ Object



39
40
41
# File 'lib/walrus/diff.rb', line 39

def compare_pathname_with_pathname(left, right)
  self.diff(left.realpath, right.realpath)
end

#compare_pathname_with_string(left, right) ⇒ Object



48
49
50
51
# File 'lib/walrus/diff.rb', line 48

def compare_pathname_with_string(left, right)
  # will pipe right in over standard input
  self.diff(left.realpath, '-')
end

#compare_string_with_pathname(left, right) ⇒ Object



43
44
45
46
# File 'lib/walrus/diff.rb', line 43

def compare_string_with_pathname(left, right)
  # will pipe left in over standard input
  self.diff('-', right.realpath)
end

#compare_string_with_string(left, right) ⇒ Object

This is the least secure comparison method because it requires the creation of a temporary file and Ruby’s builtin Tempfile class is not secure.



54
55
56
57
58
59
60
61
# File 'lib/walrus/diff.rb', line 54

def compare_string_with_string(left, right)
  # incorporate a psuedo-random component to make race conditions more difficult to exploit
  tempfile = Tempfile.new('walrus-%s' % rand(100000).to_s)
  tempfile.unlink  # shut the race condition vulnerability window as soon as possible
  tempfile.write(left)
  tempfile.close
  self.diff(tempfile.path, "-")
end

#to_sObject



85
86
87
# File 'lib/walrus/diff.rb', line 85

def to_s
  @output
end