Overloading sort_by (blocks question)

Hi, all,

I have subclassed Array to add some features. I am redefining sort_by so
that it does not return an Array but a Pairs (my subclass), but I cannot
get the syntax for passing the blocks right.

Here’s my code:

class Pairs < Array
def initialize(ary)
self.replace(ary)
end

 alias_method :sort_by_old, :sort_by
 # PROBLEM here:
 def sort_by(&block)
   ary = self.sort_by_old {yield(block)}
   Pairs.new(ary)
 end

end

I just want Pairs#sort_by to return a Pairs object every time it is
called. Could anybody help me?

Thanks,
Dan

On May 16, 2007, at 1:49 PM, Dan Z. wrote:

I have subclassed Array to add some features. I am redefining
sort_by so that it does not return an Array but a Pairs (my
subclass), but I cannot get the syntax for passing the blocks right.

Here’s my code:

alias_method :sort_by_old, :sort_by

PROBLEM here:

def sort_by(&block)
ary = self.sort_by_old {yield(block)}
Pairs.new(ary)
end

Use this instead:
ary = self.sort_by_old(&block)

p=Pairs[“abcd”, “efg”, “hi”, “j”]
=> [“abcd”, “efg”, “hi”, “j”]

p.class
=> Pairs

q=p.sort_by{|x| x.length}
=> [“j”, “hi”, “efg”, “abcd”]

q.class
=> Pairs

-Mark

Thanks, that worked immediately.

Dan

      @array = array
 end

 def to_pairs

Thanks for the code examples–I previously didn’t understand exactly how
delegation worked. This looks neat. I’ll be playing with this and will
most likely use it.

Thanks again,
Dan

On 5/16/07, Dan Z. [email protected] wrote:

   self.replace(ary)

I just want Pairs#sort_by to return a Pairs object every time it is
called. Could anybody help me?

Thanks,
Dan

def sort_by(&block)
Pairs.new(self.sort_by_old(&block))
end

This should solve your block passing problem.

However, I’d strongly suggets rethinking making a subclass of array
In most cases its better to use delegation to an array instance
variable.

Something like:

require ‘forwardable’

class Pairs
extend Forwardable

  # For methods which you would not have overriden in the subclass
  # simply delegate to the instance variable @array
  # this is just an example, the division between methods which are
  # simply delegated, which are replaced and which are wrapped is up
  # to you.
  def_delegators(:@array, :[], :[]=,  :+ #...

  # I notice that your initialize method doesn't seem to take the 

same
# argument as Array so …
def initialize(array)
@array = array
end
=begin
# If you wanted to have the same protocol for creating your class
# as Array then you’d need something like this.
def initialize(*args, &block)
@array = Array.new(*args, &block)
end

  def self.[](*objs)
       new().replace(Array[*objs])
  end

=end

  def replace(other_array)
       self.array = other_array.to_ary  # use to_ary instead of to_a
  end

  # to_ary is used for internal conversions of objects
  def to_ary
       array
  end

  # For a method which was replaced in your subclass just replace
  # explicit (or implicit) self with @array
  def concat(other_arr)
        array.concat(other_arr.to_pairs)
  end

  def sort_by(&b)
        Pairs.new(@array.sort_by(&b))
  end

  def to_pairs
      self
  end

end

class Array
def to_pairs
Pairs.new(self)
end
end


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/