Fixes for previously posted solution:
 - empty node guard in slice
 - normalize returning self for Eric's test

>------------------------------------------------------------------------------

class NilClass
  def length; 0; end
end

class String
  def shift
    return nil if empty?
    res=self[0]
    self[0]=""
    res
  end
end

class Rope
  attr_reader :length, :left, :right

  def initialize(left=nil,right=nil)
    @left=left if left
    @right=right if right
    @length=left.length+right.length
  end

  def append(what)
    len=what.length
    if (len>0)
      @left=self.dup if @right.length>0
      @right=what
      @length+=len
    end
    self
  end

  alias << append

  def prepend(what)
    len=what.length
    if (len>0)
      @right=self.dup if @left.length>0
      @left=what
      @length+=len
    end
    self
  end

  def to_s
    @left.to_s + @right.to_s
  end

  def [](i)
    return i.match(self.to_s)[0] if i.kind_of? Regexp
    if i.kind_of? Range
      pos,last=i.first,i.last
      pos = @length+pos if pos<0
      last = @length+last if last<0
      return nil if pos<0 || last<0
      return slice(pos,last-pos+1)
    end
    i = @length+i if i<0
    return nil if i<0 || i>@length-1
    llen = @left.length
    i<llen ? @left[i] : @right[i-llen]
  end

  def []=(i,val)
    #fixnum only
    i = @length+i if i<0
    ""[i]=0 if i<0 || i> @length-1
    @length+=val.length-1
    llen = @left.length
    i<llen ? @left[i]=val : @right[i-llen]=val
  end

  def slice(pos,len)
    return pos.match(self.to_s)[len] if pos.kind_of? Regexp
    pos = @length+pos if pos<0
    return nil if pos<0 || len<0 || pos>@length-1
    llen = @left.length
    return @left.slice(pos,len) if pos+len<=llen || ! @right
    return @right.slice(pos-llen, len) if pos>=llen
    Rope.new(@left.slice(pos,llen-pos),@right.slice(0,len+pos-llen))
  end

  def shift
    return nil if @length==0
    @length-=1
    res = @left.length>0 ? @left.shift : @right.shift
    @left=nil if @left.length==0
    @right=nil if @right.length==0
    res
  end

  def normalize
    r=Rebalancer.new(@length)
    self.traverse { |str| r.append(str) }
    @left, @right=r.get_ropes
    self
  end

  def traverse(&blck)
    @left.kind_of?(String) ? yield( @left) : @left.traverse(&blck) if @left
    @right.kind_of?(String) ? yield( @right) : @right.traverse(&blck) if 
@right
  end

end

class Rebalancer
  def initialize len
    @limits=[1,2]
    @slots=[]
    n=2
    @limits<< n = @limits[-2] + @limits[-1] while n<len
  end

  def append str
    @slots[0] = @slots[0] ? Rope.new( @slots[0],str) : str
    i=0
    while @slots[i].length>@limits[i]
      @slots[i+1] = @slots[i+1] ? Rope.new( @slots[i+1],@slots[i]) : 
@slots[i]
      @slots[i] = nil
      i+=1
    end
  end

  def get_ropes
    @slots.compact!
    (@slots.length-1).times { |i|
      @slots[i+1]=@slots[i+1] ? Rope.new(@slots[i+1],@slots[i]) : @slots[i]
      @slots[i]=nil
      i+=1
    }
    [@slots[-1].left,@slots[-1].right]
  end
end