OK - here's my solution - without the change I plan to
make after looking at Simons answer...

I find it interesting comparing the times of Simons pgm
vs mine - his is faster about half the time, but in a
one case, his program runs in  .9 Seconds, while mine
takes 85.7 ... a huge difference.

The one that's hardest for mine to solve is:

+-------+-------+-------+
| 3 1 _ | 6 _ _ | _ _ _ |
| _ _ 2 | _ _ _ | _ _ _ |
| _ 5 _ | _ 9 _ | 7 8 _ |
+-------+-------+-------+
| _ _ _ | _ _ 5 | _ _ _ |
| _ 9 _ | _ 1 _ | _ 6 _ |
| _ _ _ | 4 _ _ | _ _ _ |
+-------+-------+-------+
| _ 7 5 | _ 6 _ | _ 3 _ |
| _ _ _ | _ _ _ | 4 _ _ |
| _ _ _ | _ _ 7 | _ 9 2 |
+-------+-------+-------+

although his finds that there's no solution 
for 
+-------+-------+-------+
| _ _ _ | _ _ _ | _ _ _ |
| 7 _ _ | _ 8 _ | 3 _ _ |
| _ _ _ | 7 _ _ | _ _ _ |
+-------+-------+-------+
| _ _ _ | _ _ _ | _ _ _ |
| _ _ 9 | _ 1 _ | _ _ _ |
| _ _ _ | _ _ 7 | _ _ _ |
+-------+-------+-------+
| _ _ 1 | _ _ 8 | _ 2 _ |
| _ _ _ | _ 2 6 | _ _ 1 |
| _ _ _ | 3 _ 5 | _ _ _ |
+-------+-------+-------+

in about 0.2 S.

Here's my (first) solution ...

-----
class Sudoku
  def initialize(dbg = false)
    @dbg = dbg
    @board = []
  end

  def read(fname = STDIN)
    while line = gets
      next unless line =~ /^[\d\|]/
      line.gsub!(/,/, ' ')if line =~ /^\d/   # to keep working w/old
boards
      @board << line.gsub(/\|/,'').split(' ').map{|p| p.to_i}
    end
  end

  def to_s
    tb = "+-------+-------+-------+\n"
    out = ''
    @board.each_with_index{|row,rndx|
      out += tb if rndx % 3 == 0
      row.each_with_index{|cell, cndx|
        out += '| ' if cndx % 3 == 0
        out += cell == 0 ? "_ " : "#{cell} "
      }
      out += "|\n"
    }
    out += tb
  end

  def solve
    begin
      fill_spec  # fill fully specified spaces
    rescue
      return     # if try made illegal partial ...
    end

    if count_zeros > 0  # some empty spaces
      sav = []
      copy_board(sav,@board)  # save last known legal bd
      x,y = first_zero
      choices = find_choices(x,y)
      choices.each{|v|      # try each possible choice for a 0
        copy_board(@board,sav)
        @board[x][y] = v
        puts "Try #{x},#{y} <- #{v}" if @dbg
        self.solve      # recurse...
        break if count_zeros == 0
      }
    end
  end

  # fill fully specified entries
  def fill_spec
    zeros = count_zeros        # how many to fill
    begin
      last_zeros = zeros
      (0..8).each{|i|
        (0..8).each{|j|
          next if @board[i][j] != 0   # skip filled spaces
          choices = find_choices(i, j)
          raise "Illegal Board #{i+1} #{j+1}" if choices.length == 0
          @board[i][j] = choices[0] if choices.length == 1
        }
      }
      zeros = count_zeros
    # if filled some, possibly others are now fully specified
    end while ((zeros > 0) &&  (last_zeros > zeros))
  end

  def find_choices (x, y)  # get all choices for a given location
    choices = Array.new(9) {|i| i+1}
    # remove numbers from same line & row
    (0..8).each{|i|
      choices[@board[x][i] -1] = 0 if (@board[x][i] != 0 )  # rm digits
in row
      choices[@board[i][y] -1] = 0 if (@board[i][y] != 0 )  # rm digits
in col
    }
    # remove numbers from same square ...
    xs = (x/3) * 3
    xe = xs + 2
    ys = (y/3) * 3
    ye = ys + 2
    (xs..xe).each{|i|
      (ys..ye).each{|j|
        choices[(@board[i][j]) - 1] = 0 if (@board[i][j] != 0)
      }
    }
    choices.delete_if {|v| v == 0}
  end

  def count_zeros  # to determine if I'm done ...
    @board.inject(0){|sum, row| sum += row.select{|e| e == 0}.length }
  end

  def copy_board(dst, src)
    (0..8).each{|i| dst[i] = src[i].dup}
  end
  def first_zero
    (0..8).each{|j| (0..8).each{|i| return i,j if @board[i][j] == 0 }}
  end

end

dbg = ARGV[0] =~ /-d/ ? true : false
ARGV.shift if dbg

bd = Sudoku.new(dbg)
bd.read(ARGV[0])
puts "Input\n#{bd}"
bd.solve
puts bd.count_zeros == 0 ?  "Solution\n#{bd}" : "Unsolvable\n#{bd}"

----
Vance