A class that looks like (kind_of?) several classes

> > > Is there a way to make a class that looks like several
> > classes?
> > > For example:
> > >
> > > class IOArray < IO
> > > include Array # doesn't work because Array is not a
> > Module
> > > # use IO methods calls to accomplish the Array
methods
> > > end
> > >
> > > I don't need multiple inheritance. All I want is these
> > > additional classes to appear in the ancestors list. In
the
> > > above example, IOArray could act like an IO or an
Array.
> > It
> > > looks like evil.rb might have a solution, but is there
a
> > > non-evil way?
> >
> > class IOArray < IO
> > def kind_of?(cl)
> > Array == cl || super
> > end
> > end
>
> Yep, that is pretty obvious. I think that is all I need,
but I
> guess overriding ancestors would complete this.
>
> > >> x=IOArray.allocate
> > => #<IOArray:0x10184258>
> > >> x.kind_of? Array
> > => true
> >
> > But seriously, for what do you need that? I can't think
of
> > an application
> > where I would want to make something look like an Array
> > without being one.
> > Maybe it's rather Enumerable that you want?
>
> Enumerable doesn't have random access and can't modify like
> Array (or String). I think it would have been nice to have
a
> module like "Indexable" that would cover common methods in
> Array and String.
>
> The example I have above should probably be combining an IO
and
> a String since an IO accesses characters like a String:
>
> class IOString < IO
> def kind_of?(c); String==c || super; end
> # use IO methods (seek/tell/read/write) to accomplish
> # the String methods
> end

This is generally unneeded in Ruby; If duck typing is used
properly,
the ancestors and kind_of? shouldn't matter. And if it *does*
matter,
then masquerading like this could cause problems:

  if obj.kind_of? String
    var.replace obj
  end

This code would break if obj is an IOString as defined above,
even
though this code has no logic errors.

If you check out the StringIO class (require 'stringio'), you
will
find that it inherits neither from IO nor String. But it
still works
very nicely :slight_smile:

Thanks. I assumed that the StringIO class inherited from the
IO class since it has all of the same methods. So the proper
Ruby style is to use respond_to? instead of kind_of? to see
what "type" your arguments are?

You still should be able to make the above "replace" code work
above. For the IOString class I described, you'd just replace
the contents of the file with the string passed. seek(0);
truncate(write(value)). That would seem to accomplish the
replace function.

···

__________________________________
Do you Yahoo!?
Yahoo! Mail - You care about security. So do we.
http://promotions.yahoo.com/new_mail

> > > > Is there a way to make a class that looks like several
> > > classes?
> > > > For example:
> > > >
> > > > class IOArray < IO
> > > > include Array # doesn't work because Array is not a
> > > Module
> > > > # use IO methods calls to accomplish the Array
> methods
> > > > end
> > > >
> > > > I don't need multiple inheritance. All I want is these
> > > > additional classes to appear in the ancestors list. In
> the
> > > > above example, IOArray could act like an IO or an
> Array.
> > > It
> > > > looks like evil.rb might have a solution, but is there
> a
> > > > non-evil way?
> > >
> > > class IOArray < IO
> > > def kind_of?(cl)
> > > Array == cl || super
> > > end
> > > end
> >
> > Yep, that is pretty obvious. I think that is all I need,
> but I
> > guess overriding ancestors would complete this.
> >
> > > >> x=IOArray.allocate
> > > => #<IOArray:0x10184258>
> > > >> x.kind_of? Array
> > > => true
> > >
> > > But seriously, for what do you need that? I can't think
> of
> > > an application
> > > where I would want to make something look like an Array
> > > without being one.
> > > Maybe it's rather Enumerable that you want?
> >
> > Enumerable doesn't have random access and can't modify like
> > Array (or String). I think it would have been nice to have
> a
> > module like "Indexable" that would cover common methods in
> > Array and String.
> >
> > The example I have above should probably be combining an IO
> and
> > a String since an IO accesses characters like a String:
> >
> > class IOString < IO
> > def kind_of?(c); String==c || super; end
> > # use IO methods (seek/tell/read/write) to accomplish
> > # the String methods
> > end
>
> This is generally unneeded in Ruby; If duck typing is used
> properly,
> the ancestors and kind_of? shouldn't matter. And if it *does*
> matter,
> then masquerading like this could cause problems:
>
> if obj.kind_of? String
> var.replace obj
> end
>
> This code would break if obj is an IOString as defined above,
> even
> though this code has no logic errors.
>
> If you check out the StringIO class (require 'stringio'), you
> will
> find that it inherits neither from IO nor String. But it
> still works
> very nicely :slight_smile:

Thanks. I assumed that the StringIO class inherited from the
IO class since it has all of the same methods. So the proper
Ruby style is to use respond_to? instead of kind_of? to see
what "type" your arguments are?

The usual Ruby way is to use Duck Typing. As I see it:
- If you are accepting different kinds of objects in the same method,
use respond_to? to determine how to use them.
- If you only expect one kind of argument, don't even bother checking.

So:

# takes a file or a filename
def read_data(file)
  if file.respond_to? :read
    file.read
  else
    File.open(file){|f| f.read}
  end
end

# takes an string
def show_in_quotes(str)
  puts '"' + str + '"'
end

You still should be able to make the above "replace" code work
above. For the IOString class I described, you'd just replace
the contents of the file with the string passed. seek(0);
truncate(write(value)). That would seem to accomplish the
replace function.

Add that to a to_str method, and you'll have it. My example was
flawed; the Ruby interpreter won't decide that it's a String anyway.
But I still think that it could cause problems...
cheers,
Mark

···

On 5/10/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

Eric Mahurin said:

Thanks. I assumed that the StringIO class inherited from the
IO class since it has all of the same methods. So the proper
Ruby style is to use respond_to? instead of kind_of? to see
what "type" your arguments are?

The common Ruby style is to not check at all, but just send the messages
needed to get the job done. If the object is inappropriate, Ruby will
catch it and let you know what it didn't like.

···

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)