This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.

Making Sure a Sorted Array Stays Sorted
CodeExpectedActual
class SortedArray < Array
  def initialize(*args, &sort_by)
    @sort_by = sort_by || Proc.new { |x,y| x <=> y }	
    super(*args)
    sort! &sort_by
  end
  def insert(i, v)
    # The next line could be further optimized to perform a
    # binary search.
    insert_before = index(find { |x| @sort_by.call(x, v) == 1 })
    super(insert_before ? insert_before : -1, v)
  end
  def <<(v)
    insert(0, v)
  end
  alias push <<
  alias unshift <<
  ["collect!", "flatten!", "[]="].each do |method_name|
    module_eval %{
      def #{method_name}(*args)
        super
        sort! &@sort_by
      end
    }
  end
  def reverse!
    #Do nothing; reversing the array would disorder it.
  end
end
a = SortedArray.new([3,2,1])
[1, 2, 3] [1, 2, 3]
unsorted= ["b", "aa", "a", "cccc", "1", "zzzzz", "k", "z"]
strings_by_alpha = SortedArray.new(unsorted)
["1", "a", "aa", "b", "cccc", "k", "z", "zzzzz"] ["1", "a", "aa", "b", "cccc", "k", "z", "zzzzz"]
strings_by_length = SortedArray.new(unsorted) do |x,y| 
  x.length <=> y.length
end
["b", "z", "a", "k", "1", "aa", "cccc", "zzzzz"] ["b", "z", "a", "k", "1", "aa", "cccc", "zzzzz"]
a << -1
[-1, 1, 2, 3] [-1, 1, 2, 3]
a << 1.5
[-1, 1, 1.5, 2, 3] [-1, 1, 1.5, 2, 3]
a.push(2.5)
[-1, 1, 1.5, 2, 2.5, 3] [-1, 1, 1.5, 2, 2.5, 3]
a.unshift(1.6)
[-1, 1, 1.5, 1.6, 2, 2.5, 3] [-1, 1, 1.5, 1.6, 2, 2.5, 3]
a = SortedArray.new([10, 6, 4, -4, 200, 100])  
[-4, 4, 6, 10, 100, 200] [-4, 4, 6, 10, 100, 200]
a.collect! { |x| x * -1 }
[-200, -100, -10, -6, -4, 4] [-200, -100, -10, -6, -4, 4]
a[3] = 25
a
[-200, -100, -10, -4, 4, 25] [-200, -100, -10, -4, 4, 25]
a[1..2] = [6000, 10, 600, 6]
a
[-200, -4, 4, 6, 10, 25, 600, 6000] [-200, -4, 4, 6, 10, 25, 600, 6000]
class SortedArray
  def []=(*args)    
    if args.size == 3     
      #e.g. "a[6,3] = [1,2,3]"
      start, length, value = args
      slice! Range.new(start, start+length, true)
      (value.respond_to? :each) ? value.each { |x| self << x } : self << value
    elsif args.size == 2
      index, value = args  
      if index.is_a? Numeric
        #e.g. "a[0] = 10" (the most common form of array assignment)
        delete_at(index)
        self << value
      elsif index.is_a? Range
        #e.g. "a[0..3] = [1,2,3]"
        slice! index
        (value.respond_to? :each) ? value.each { |x| self << x } : self << value
      else
        #Not supported. Delegate to superclass; will probably give an error.
        super
        sort!(&sort_by)
      end
    else
      #Not supported. Delegate to superclass; will probably give an error.
      super
      sort!(&sort_by)
    end
  end
end
a = SortedArray.new([1,2,3,4,5,6])
a[0] = 10
a
[2, 3, 4, 5, 6, 10] [2, 3, 4, 5, 6, 10]
a[0, 2] = [100, 200]
a
[4, 5, 6, 10, 100, 200] [4, 5, 6, 10, 100, 200]
a[1..2] = [-4, 6]
a
[-4, 4, 6, 10, 100, 200] [-4, 4, 6, 10, 100, 200]
stripes = SortedArray.new(["aardwolf", "zebrafish"])
stripes[1].upcase!
stripes
["aardwolf", "ZEBRAFISH"] ["aardwolf", "ZEBRAFISH"]
stripes.sort!
["ZEBRAFISH", "aardwolf"] ["ZEBRAFISH", "aardwolf"]
class Object
  def to_frozen
    f = self
    unless frozen?       
      begin
        f = dup.freeze
      rescue TypeError 
        #This object can't be duped (e.g. Fixnum); fortunately,
        #it usually can't be modified either
      end
    end
    return f
  end
end
class FrozenCopySortedArray < SortedArray
  def insert(i, v)    
    insert_before = index(find { |x| x > v })
    super(insert_before ? insert_before : -1, v.to_frozen)
  end
  ["initialize", "collect!", "flatten!"].each do |method_name|
    define_method(method_name) do
      super
      each_with_index { |x, i| self[i] = x.to_frozen }
      # No need to sort; by doing an assignment to every element
      # in the array, we've made #insert keep the array sorted.
    end
  end
end
stripes = SortedArray.new(["aardwolf", "zebrafish"])
stripes[1].upcase!
TypeError: can't modify frozen string
[1, "string"].sort 
ArgumentError: comparison of Fixnum with String failed
...
ArgumentError: comparison of Fixnum with String failed
	from (irb):116:in `sort'
	from (irb):116
	from :0
a = SortedArray.new([1])
a << "string"
ArgumentError: comparison of Fixnum with String failed
a = SortedArray.new([3, 2, 1])
[1, 2, 3] [1, 2, 3]
a += [1, -10]
[1, 2, 3, 1, -10] [1, 2, 3, 1, -10]
a.class
Array Array
class SortedArray
  def + (other_array)
    SortedArray.new(super)
  end
end
nil