I changed the code a little, to make it more illustrative. The revised code
is in the end of the file. Please, forgive me changing the strings a little.

> root.each { |a|  a = "try " }            #  ``data''  is not changed
> root.each { |a|  a.replace "succ " } # ``data'' is changed

The difference between these two snippets is just what you commented.

When the associated block gets called 

>         def each
>               yield data

what exactly block variable 'a' starts to refer at. Well, in the first call
to the block your datastructure is like this:

#<Bt:0x40178894 
  @right=nil,
  @left=#<Bt:0x401788a8 
    @right=nil,
    @left=#<Bt:0x401788bc 
      @right=nil,
      @left=nil,
      @data="fail 2">, 
    @data="fail 1">, 
  @data="root data">

'a' starts to refer the same string as Bt:0x40178894's @data, that is the
bottommost "root data ". Then, in the block we assign

   a = "try "

happens the same thing as:

  b = "gets"
  c = b
  c = "fooled"
  puts b, c

outputting

  gets
  fooled

So in this example c starts to point to same string as b, that is object of
class String containing a string "gets". When c is assigned to refer object
"fooled" b continues to refer to "gets". At any point c is not "pointing" to
variable b itself, and can't alter where b refers to.

Then the second case. When this block is called for the same data

> root.each { |a|  a.replace "succ " } # ``data'' is changed

block variable 'a' starts to refer the same string "root data". But instead
of reassign 'a' to point some other string, we invoke the object's method
replace and pass the string "succ " to it. So the very same object that
@data was pointing replaces it's contents with different string, so there's
effectively a change in the data structure.

Hopefully this cleared things a bit. Attached is a slightly modified code,
with convenient dumper method.

BTW. I'm sure you noticed there's a big difference between these two
constructs:

 Bt.new ( "fail root", Bt.new "fail 1",  Bt.new "fail 2")
 Bt.new ( "fail root", Bt.new("fail 1"), Bt.new("fail 2"))

In the resulting data structures the first one doesn't have right branch at
all

  #<Bt:0x40178894 
    @right=nil,
    @left=#<Bt:0x401788a8 
      @right=nil,
      @left=#<Bt:0x401788bc 
        @right=nil,
        @left=nil,
        @data="fail 2">, 
      @data="fail 1">, 
    @data="root data">

  like    root
          /  \
      fail 1  nil
      /   \
   fail2  nil
   /  \
 nil  nil

and the second one is well balanced case :).

  #<Bt:0x401785d8 
    @right=#<Bt:0x401785ec 
      @right=nil,
      @left=nil,
      @data="fail 2">, 
    @left=#<Bt:0x40178614 
      @right=nil,
      @left=nil,
      @data="fail 1">, 
    @data="root data">

  like    root
         /    \
     fail 1   fail 2
    /  \       /   \
  nil  nil   nil  nil


	- Aleksi



#***********************
# A binary tree class
class Bt
        def  initialize( cont, l = nil, r = nil )
                @data=cont
                @left=l
                @right=r
        end
        def each
              yield data
              left.each   { |l| yield l } 
              right.each { |r| yield r }  
        end
        attr_accessor( :left,  :right, :data)
end

module Each
        def each
        end
end

nil.extend(Each)

def dumper(obj)
  indent = 0
  str = obj.inspect
  while str.length > 0
    if m = /(#<.+? )|(, (?=@))|(>, )/.match(str)
      if m[1]
	indent += 1
	print $` + $& + "\n" + "  " * indent
	str = $'
      elsif m[2]
	print $` + ",\n" + "  " * indent
	str = $'
      elsif m[3]
	indent -= 1
	print $` + $& + "\n" + "  " * indent
	str = $'
      end
    else
      indent -= 1
      puts "  " * indent + str
      str = ""
    end
  end
end

[Bt.new ( "fail root", Bt.new "fail 1", Bt.new "fail 2"),
 Bt.new ( "fail root", Bt.new("fail 1"), Bt.new("fail 2"))
].each do |root|
  # ``data'' is changed
  root.data="root data"
  #  ``data''  is not changed
  root.each { |a|  dumper(root); a = "try"; dumper(root); puts; }
  root.each { |a|  print a, " "  }
  puts
  dumper(root)

  puts "Then the real change"

  # ``data'' is changed
  root.each { |a|  dumper(root); a.replace "succ"; dumper(root); puts; } 
  root.each { |a|  print a, " "  }
  puts
  dumper(root)

  puts "\n" * 3
end