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)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/walrus/diff.rb', line 23

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)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/walrus/diff.rb', line 70

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



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

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

#compare_pathname_with_string(left, right) ⇒ Object



54
55
56
57
# File 'lib/walrus/diff.rb', line 54

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



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

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.



60
61
62
63
64
65
66
67
# File 'lib/walrus/diff.rb', line 60

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



91
92
93
# File 'lib/walrus/diff.rb', line 91

def to_s
  @output
end