Subclassing Array

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:

columns = [[1, "Hostname"], [2, "Model"], [5, "OS Version"]]
report = InventoryReport.new("HARDWARE_QUERY", columns)
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

···

--
Posted via http://www.ruby-forum.com/\.

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/rdoc/index.html
(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.. :slight_smile:

ilan

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

On Tue, Feb 27, 2007 at 12:42:15AM +0900, 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:

> columns = [[1, "Hostname"], [2, "Model"], [5, "OS Version"]]
> report = InventoryReport.new("HARDWARE_QUERY", columns)
> 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?

I have become a tea.

James *Edward* Gray II

···

On Feb 26, 2007, at 9:58 AM, Ilan Berci wrote:

(documentation provided by James Earl Gray II)

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/rdoc/index.html
(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.. :slight_smile:

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)

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

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.

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.. :frowning:

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

ilan

--
Posted via http://www.ruby-forum.com/\.

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

_why

···

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.

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

···

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:

--
be kind whenever possible... it is always possible.
- the dalai lama

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

···

--
Posted via http://www.ruby-forum.com/\.

Tea for II, very nice, watch out for Jean-Luc :wink:

···

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

--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous

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... :wink:

James Edward Gray II

···

On Feb 26, 2007, at 10:07 AM, Ilan Berci wrote:

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..

LOL

Awesome :slight_smile:

···

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.

# fr: James Edward Gray II wrote:
# > >(documentation provided by James Earl Gray II)
# > I have become a tea.

···

From: _why [mailto:why@ruby-lang.org] :
#
# 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 :)))

James Edward Gray II ++

···

On Tue, Feb 27, 2007 at 01:10:46AM +0900, James Edward Gray II wrote:

On Feb 26, 2007, at 10:07 AM, Ilan Berci wrote:
>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..

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... :wink:

James Edward Gray II

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
"The first rule of magic is simple. Don't waste your time waving your
hands and hopping when a rock or a club will do." - McCloctnick the Lucid

> > >(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 :slight_smile:

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."

···

--
Giles Bowkett
http://www.gilesgoatboy.org

http://gilesgoatboy.blogspot.com