Forum: Ruby Subclassing Array

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
6ea82eb4189671b3686ff8a81e6ec199?d=identicon&s=25 El Gato (el-gato)
on 2007-02-26 16:42
I'm sure I'm just being an idiot here... my mind is a little foggy this
morning, but I'm having a hard time understanding how to accomplish
this.  I've written a class (I'll just put some snippets in for
understanding) in which I'd like to be able to use the following
behavior:

irb> columns = [[1, "Hostname"], [2, "Model"], [5, "OS Version"]]
irb> report = InventoryReport.new("HARDWARE_QUERY", columns)
irb> report.query.map {|a| a.first.downcase!; a}.save "/tmp/test.xls"

Where query() returns an array like [["host1", "Dell", "Windows"],
["host2", "Hitachi", "Windows"], ...]

However, throwing a map (or select or whatever) in there (obviously)
ends up returning an Array.  How would I handle this so that it works as
I would like?  Do I need to move my save(), to_csv(), and to_xls() stuff
into the Array class?

Sorry if this is a dumb question.

class InventoryReport < Array
    def initialize(query_name, fields)
        @query_name = query_name
        @fields = fields
        super()
    end

    def query
        cols = @fields.map {|a| a.first - 1}
        %x{runquery #{@query_name}}.each_line do |l|
           t = l.chomp.split
           tmp = []
           cols.each do |a|
               tmp << t[a].strip
           end
           self << tmp
        end
        self
    end

    def save(filename)
        case filename
            when /.*\.csv/ then to_csv(filename)
            when /.*\.xls/ then
                to_csv(filename.gsub(/xls$/, "csv"))
                to_xls(filename, filename.gsub(/xls$/, "csv")
         end
    end

    def to_csv(...)
    end

    def to_xls(...)
    end
end
391f9b787cdc12aa2c179713f5103e3a?d=identicon&s=25 Ilan Berci (iberci)
on 2007-02-26 16:58
El Gato wrote:
> I'm sure I'm just being an idiot here... my mind is a little foggy this
> morning, but I'm having a hard time understanding how to accomplish
> this.  I've written a class (I'll just put some snippets in for
> understanding) in which I'd like to be able to use the following
> behavior:
>

El Gato,

My suggestion is to take a good look at Ruby's incredibly powerfull use
of delegates
http://www.ruby-doc.org/stdlib/libdoc/delegate/rdo...
(documentation provided by James Earl Gray II)

Secondly, there is a great book entitled "Ruby Recipes", which discusses
your question in great detail and I higly recommend that you pick it
up..

Hope this helps and this is only a suggestion as there exists 100 ways
to do what you are asking.. :)

ilan
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-02-26 17:05
(Received via mailing list)
On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:

> (documentation provided by James Earl Gray II)

I have become a tea.

James *Edward* Gray II
391f9b787cdc12aa2c179713f5103e3a?d=identicon&s=25 Ilan Berci (iberci)
on 2007-02-26 17:07
James Gray wrote:
> On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:
>
>> (documentation provided by James Earl Gray II)
>
> I have become a tea.
>
> James *Edward* Gray II

Ouch!!! Apologies.. Not enough coffee this morning and guess what my
wife's favourite is..  Also forgot to mention Gavin as well.. :(

I will keep quiet for the remainder of the day.. :)

ilan
0c00d644de3b8bb2f655908c79af25a5?d=identicon&s=25 Matt Lawrence (Guest)
on 2007-02-26 17:07
(Received via mailing list)
On Tue, 27 Feb 2007, James Edward Gray II wrote:

> On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:
>
>> (documentation provided by James Earl Gray II)
>
> I have become a tea.

So what did you do to get yourself in such hot water?

-- Matt
It's not what I know that counts.
It's what I can remember in time to use.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-02-26 17:11
(Received via mailing list)
On Feb 26, 2007, at 10:07 AM, Ilan Berci wrote:

> wife's favourite is..
No worries.  Hal listed me as James Edward Gray III in the second
edition of The Ruby Way.  Good to know he gives me the +1 I guess...  ;)

James Edward Gray II
6ea82eb4189671b3686ff8a81e6ec199?d=identicon&s=25 El Gato (el-gato)
on 2007-02-26 17:43
Ilan Berci wrote:
> El Gato wrote:
>> I'm sure I'm just being an idiot here... my mind is a little foggy this
>> morning, but I'm having a hard time understanding how to accomplish
>> this.  I've written a class (I'll just put some snippets in for
>> understanding) in which I'd like to be able to use the following
>> behavior:
>>
>
> El Gato,
>
> My suggestion is to take a good look at Ruby's incredibly powerfull use
> of delegates
> http://www.ruby-doc.org/stdlib/libdoc/delegate/rdo...
> (documentation provided by James Earl Gray II)
>
> Secondly, there is a great book entitled "Ruby Recipes", which discusses
> your question in great detail and I higly recommend that you pick it
> up..
>
> Hope this helps and this is only a suggestion as there exists 100 ways
> to do what you are asking.. :)
>
> ilan


I'm not sure if I'm missing something, but it appears that calling map()
on a DelegateClass still returns an Array object.  I guess I would need
map() and friends to return an InventoryReport class (i.e., Array
doesn't have a save method, whereas InventoryReport does, so calling
report.query.map {...}.save "/tmp/filename.xls" fails)
19fdf8bd123216b5056fb856cf1a5771?d=identicon&s=25 _why (Guest)
on 2007-02-26 17:47
(Received via mailing list)
On Tue, Feb 27, 2007 at 01:04:39AM +0900, James Edward Gray II wrote:
> On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:
>
> >(documentation provided by James Earl Gray II)
>
> I have become a tea.

Not just any tea.  A tea that speaks in the voice of Darth Vader.

_why
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-26 17:48
(Received via mailing list)
On Tue, 27 Feb 2007, El Gato wrote:

> Ilan Berci wrote:
>> El Gato wrote:
>>> I'm sure I'm just being an idiot here... my mind is a little foggy this
>>> morning, but I'm having a hard time understanding how to accomplish
>>> this.  I've written a class (I'll just put some snippets in for
>>> understanding) in which I'd like to be able to use the following
>>> behavior:
>>>
>>

check out arrayfields - on rubyforge or

   http://codeforpeople.com/lib/ruby/arrayfields/

by using it you can name your fields for the result set only

-a
391f9b787cdc12aa2c179713f5103e3a?d=identicon&s=25 Ilan Berci (iberci)
on 2007-02-26 17:54
El Gato wrote:

> I'm not sure if I'm missing something, but it appears that calling map()
> on a DelegateClass still returns an Array object.  I guess I would need
> map() and friends to return an InventoryReport class (i.e., Array
> doesn't have a save method, whereas InventoryReport does, so calling
> report.query.map {...}.save "/tmp/filename.xls" fails)

El Gato,

No, you didn't miss anything, your delegate class would return and
InventoryReport on map() (on a side note, I dislike the re-usage of the
"map" name for alternate functionality but that's another discussion)
which would have the save() method.  The delegate pattern allows you to
"intercept" selectively in order to accomplish the task at hand.


ilan
Fd22ee3cfc7dac283ce8e451af324f7d?d=identicon&s=25 Chad Perrin (Guest)
on 2007-02-26 18:27
(Received via mailing list)
On Tue, Feb 27, 2007 at 01:10:46AM +0900, James Edward Gray II wrote:
> >Ouch!!! Apologies.. Not enough coffee this morning and guess what my
> >wife's favourite is..
>
> No worries.  Hal listed me as James Edward Gray III in the second
> edition of The Ruby Way.  Good to know he gives me the +1 I guess...  ;)
>
> James Edward Gray II

James Edward Gray II ++
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-02-26 21:50
(Received via mailing list)
On Tue, Feb 27, 2007 at 12:42:15AM +0900, El Gato wrote:
> Where query() returns an array like [["host1", "Dell", "Windows"],
> ["host2", "Hitachi", "Windows"], ...]
>
> However, throwing a map (or select or whatever) in there (obviously)
> ends up returning an Array.  How would I handle this so that it works as
> I would like?  Do I need to move my save(), to_csv(), and to_xls() stuff
> into the Array class?

It was a Moment of Enlightenment for me when I realised that all this
stuff
they teach you about OO, class hierarchies and inheritance is actually
irrelevant. It's mainly there just to keep C++ and Java compilers happy.

A more flexible approach is composition and delegation. (Object A *has
a* B,
not Object A *is a* B)

In this model, what you'd get is something like this:

class InventoryReport
    def initialize(query_name, fields, data = [])
        @query_name = query_name
        @fields = fields
        @data = data
    end

    def query
      ans = ...do database query...
      self.class.new(@query_name, @fields, ans)
    end

    def map(&blk)
      self.class.new(@query_name, @fields, @data.map(&blk))
    end

    ... etc
end

But in that case, InventoryReport#query could modify its own @data
instance
in-place, in which case you'd have

    def query
      @data = ...do database query...
    end

    def map(&blk)
      @data = @data.map(&blk)
    end

(Then you can argue about whether the methods should be called 'query!'
and
'map!' but I won't go there)

Anyway, I find this approach is much more powerful. For example, your
object
A can contain instances of B, C and D. When an incoming method call
arrives,
it can forward to one of these, or use them in sequence to perform
whatever
task is required.

If you find you are writing lots of explicit delegation, then use one of
the
delegation patterns to help you - or just write a method_missing()
function.
And if you're using inheritance as a form of implementation code sharing
between your own objects, then just use mixins for the common code.

Going down this route, a lot of the OO conundrums simply disappear -
such as
"is a circle an oval, or is an oval a circle?"

I notice that your InventoryReport is already composed of three
elements: a
query name, a field array, and a data array. If you use inheritance, you
have to worry about which of these elements is the "primary" one which
inherits from some other class, and deal with all the nits of inherited
methods (such as Array#map always returning an Array, as you
discovered).
However if you use composition, all the elements are equal, and you can
pick
whatever behaviour you want from all three.

Regards,

Brian.
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-02-26 21:56
(Received via mailing list)
On Feb 26, 9:46 am, _why <w...@ruby-lang.org> wrote:
> On Tue, Feb 27, 2007 at 01:04:39AM +0900, James Edward Gray II wrote:
>
> > On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:
>
> > >(documentation provided by James Earl Gray II)
>
> > I have become a tea.
>
> Not just any tea.  A tea that speaks in the voice of Darth Vader.

LOL

Awesome :)
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-02-26 21:56
(Received via mailing list)
On 2/26/07, James Edward Gray II <james@grayproductions.net> wrote:
> On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:
>
> > (documentation provided by James Earl Gray II)
>
> I have become a tea.
>
> James *Edward* Gray II
>
>
Tea for II, very nice, watch out for Jean-Luc ;)
Ce8b03e5750097942c58e12b46724312?d=identicon&s=25 Giles Bowkett (Guest)
on 2007-02-27 01:02
(Received via mailing list)
> > > >(documentation provided by James Earl Gray II)
> >
> > > I have become a tea.
> >
> > Not just any tea.  A tea that speaks in the voice of Darth Vader.
>
> LOL
>
> Awesome :)

I love it. I get these images of the Lord of the Sith relaxing with a
nice McVittie's digestive biscuit. "The Force is strong in this cup."
6087a044557d6b59ab52e7dd20f94da8?d=identicon&s=25 Peña, Botp (Guest)
on 2007-02-27 01:54
(Received via mailing list)
From: _why [mailto:why@ruby-lang.org] :
# fr: James Edward Gray II wrote:
# > >(documentation provided by James Earl Gray II)
# > I have become a tea.
#
# Not just any tea.  A tea that speaks in the voice of Darth Vader.

can't resist my stomach, sorry list, but i really love this list! rotfl
:)))
This topic is locked and can not be replied to.