overloading sort_by (blocks question)

D

Dan Zwell

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
 
M

Mark Day

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
 
D

Dan Zwell

Thanks, that worked immediately.

Dan

Mark said:
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
 
R

Rick DeNatale

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

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
 
D

Dan Zwell

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

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top