Hi --

On Mon, 8 Aug 2005, Trans wrote:

> In Facets I offer:
>
>  class String
>    def to_ary
>      self.split(//)
>    end
>  end
>
> This proves useful in adding other methods to Enumerable that can act
> to all enumerables and on strings as character arrays. For instance:
>
>  # Generates a hash mapping each unique element to the frequency it
> appears.
>  #--
>  # Credit goes to Derek.
>  #++
>  def freq
>    arr = respond_to?(:to_ary) ? self.to_ary : self.to_a
>    probHash = Hash.new
>    size = arr.size.to_f
>    arr.uniq.each do |i|
>      ct = arr.inject(0) do |mem,obj|
>        obj.eql?(i) ? (mem+1) : mem
>      end
>      probHash[i] = ct.to_f/size
>    end
>    probHash
>  end

This is just a sidenote, but here's a fun way to do that:

   module Enumerable
     def freq
       arr = to_ary rescue to_a
       probs = Hash.new {|h,k| h[k] = arr.find_all {|e| e == k }.size }
       arr.uniq.each {|k| probs[k] /= arr.size.to_f }
       probs
     end
   end

:-)

Anyway...

> I had hopped by using Sting#to_ary I would avoid any problems b/c it is
> not defined by default. Alas I don't seem so fortunate. Test::Unit
> chokes on it:

It's not test/unit related, except that line 105 of testrunner.rb
happens to call puts.  Here's what I think is happening.

When you call puts x, there's a test somewhere to see if it's
an array (including via to_ary).  If it is, then puts x turns into
puts x.to_ary.

In the case of a string (assuming your String#to_ary), that means
that:

   puts "abc"

becomes

   puts ["a","b","c"]

which starts with

   puts "a"

but that triggers puts "a".to_ary, which becomes puts ["a"], which
starts with puts "a", which triggers puts "a".to_ary, which becomes
puts ["a"], etc., in an infinite loop.

(I haven't tracked this down in the source; it's inference from the
Ruby side.)

To see this in action:

   class String
     def to_ary
       split(/#{p self}/)
     end
   end

   puts "abc"

and get ready to hit ctrl-c :-)


David

-- 
David A. Black
dblack / wobblini.net