On Monday, July 05, 2010 03:30:44 pm Fearless Fool wrote:
> Assume I'd like to create a statistics package designed to work on
> Arrays [but see P.S.].  One way to do this would be to create functions
> that take an array as an argument:
> 
>   def mean(array)
>     return NaN unless array && array.size > 0
>     array.reduce(0.0) {|accum, val| accum + val} / array.size
>   end
> 
> ... but that's so old school.  What I'd really like is to *cleanly*
> 
> extend the Array class so you can operate on it directly, as in:
>   >> [1, 2, 3].mean
> 
>   => 2.0
> 
> I'm sure that it's considered bad style to simply open the Array class
> and extend it, since that can lead to unexpected user surprises:
> 
>   class Array
>     def mean
>       return NaN unless self.size > 0
>       self.reduce(0.0) {|accum, val| accum + val} / self.size
>     end
>   end

What kind of surprises?

> My hunch is that the stats functions should be wrapped in a module and
> then included (extended?) when desired.  But despite reading the
> tutorials and docs, I'm not sure what's considered the stylistically
> correct way (and the syntax) to package that up.

Simple enough:

module MyModule
  def mean
    ...
  end
end

Then, you can always do this:

[].extend MyModule

Or this:

class Array
  include MyModule
end

Then, probably, provide a file people can 'require' that'll do the inclusion 
for them, maybe even make that the default.

It might also be nice to provide a way to do this on Enumerables, though that 
would be less efficient if you know you have an array. For example:

def mean
  size = 0
  count = inject(0){|accum, val| size+=1; accum+val}
  count / size.to_f
end