Right up front, let me say that I realize that I can't prevent  
modifications to objects referenced by my array - that's OK.

SUMMARY
My desire is to create an Array which is read-only from the outside,  
but which my class can modify internally. #freeze is not an option,  
nor is #dup.


BACKGROUND
The goal here is to mimic the NodeList class in the W3C DOM model. A  
NodeList is an 'array' of items returned from various methods, which  
is immutable by the external consumer but which is also 'live' -  
references to the returned list of nodes will be updated as the DOM  
tree is modified.


In my implementation, I'm creating an array that provides an ordered  
list of children for each Node. Each Node also has #previous_sibling,  
#next_sibling, #first_child, #last_child, and #parent_node  
attributes, which must be properly kept in-sync.

A really nice implementation would cause direct manipulation of the  
Array to update all associated attributes. In the end I may do that.  
However, for now, what I want is to return an array which will not  
let the user modify the array itself, but which my own class can  
modify when necessary.


The code I have currently follows (minus comments and some edge  
checking, for terseness). What I have works, but I'm wondering if  
there is a better way than just aliasing the methods. (I know that  
#instance_eval and the like means that I cannot truly lock down a  
class, but security-through-obscurity seems less than ideal.)


class ReadOnlyArray < Array
     alias_method :'__ro_<<', :'<<' #:nodoc:
     alias_method :__ro_insert, :insert #:nodoc:
     alias_method :__ro_delete_at, :delete_at #:nodoc:
     affectors = %w| << []= clear concat delete delete_at delete_if  
fill flatten! insert map! pack pop push reject! replace reverse!  
shift slice! sort! uniq! unshift |
     affectors.each{ |name| undef_method name }
end

module OrderedTreeNode
   attr_reader :next_sibling, :previous_sibling, :parent_node
   attr_reader :first_child, :last_child, :child_nodes

   def insert_before( new_child, ref_child=nil )
     kids = child_nodes

     #Find the index of the ref_child, if given, or use the end
     dest_slot = ref_child ? kids.index( ref_child ) : kids.length

     #Shove the child into the array and update its pointers
     kids.__ro_insert( dest_slot, new_child )
     new_child.previous_sibling = kids[ dest_slot - 1 ]
     new_child.next_sibling = kids[ dest_slot + 1 ]
     new_child.parent_node = self

     new_child.previous_sibling.next_sibling = new_child if  
new_child.previous_sibling
     new_child.next_sibling.previous_sibling = new_child if  
new_child.next_sibling

     new_child
   end

   def child_nodes #:nodoc:
     @__phrogzdomorderedtreenode_childnodes ||= ReadOnlyArray.new
   end

   #:stopdoc:
   protected
     attr_writer :parent_node, :next_sibling, :previous_sibling
     attr_writer :first_child, :last_child
   #:startdoc:

end