Forum: Ruby class C < B < A

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.
Iñaki Baz C. (Guest)
on 2009-04-07 02:14
(Received via mailing list)
Hi, I have this case:

  class A     ; end
  class B < A ; end
  class C < B ; end

  a = A.new
  b = B.new
  c = C.new


I look for a way (***) to get the following results:

a)
  a *** A => true
  a *** B => false
  a *** C => false

b)
  b *** A => false  (*1)
  b *** B => true
  b *** C => false

c)
  c *** A => false  (*2)
  c *** B => true
  c *** C => true


Note that I could use ===, so:
  A === a => true
  A === b => false

but in cases *1 and *2 the result is not what I want:

  A === b => true (I want false)
  A === c => true (I want false)


I could play with a.class.ancestors, but isn't another way?

Thanks a lot.
Joel VanderWerf (Guest)
on 2009-04-07 02:36
(Received via mailing list)
Iñaki Baz C. wrote:
>
> I look for a way (***) to get the following results:
...

#instance_of? works for all cases except:

>   c *** B => true

Are you sure you need this to be true?
Iñaki Baz C. (Guest)
on 2009-04-07 02:43
(Received via mailing list)
El Martes 07 Abril 2009, Joel VanderWerf escribió:
> >
> >
> > I look for a way (***) to get the following results:
>
> ...
>
> #instance_of? works for all cases except:
> >   c *** B => true
>
> Are you sure you need this to be true?

Yes. Basically A is String and B is a child of String with various
methods,
and C is a more specific class.

But I didn't realize of #instance_of?, I will try with it.

Thanks.
Siep K. (Guest)
on 2009-04-07 02:48
Iñaki Baz C. wrote:
> Hi, I have this case:
>
>   class A     ; end
>   class B < A ; end
>   class C < B ; end
>
>   a = A.new
>   b = B.new
>   c = C.new
>
>
> I look for a way (***) to get the following results:
>
> a)
>   a *** A => true
>   a *** B => false
>   a *** C => false
>
> b)
>   b *** A => false  (*1)
>   b *** B => true
>   b *** C => false
>
> c)
>   c *** A => false  (*2)
>   c *** B => true
>   c *** C => true
>
(...)
> Thanks a lot.

The method #kind_of? gives the results you want.

regards,

Siep
Iñaki Baz C. (Guest)
on 2009-04-07 02:55
(Received via mailing list)
El Martes 07 Abril 2009, Siep K. escribió:
> Iñaki Baz C. wrote:

> > a)
> >   a *** A => true
> >   a *** B => false
> >   a *** C => false
> >
> > b)
> >   b *** A => false  (*1)

b.kind_of? A
=> true


> >   b *** B => true
> >   b *** C => false
> >
> > c)
> >   c *** A => false  (*2)

c.kind_of? A
=> true

> >   c *** B => true
> >   c *** C => true
>
> (...)
>
> > Thanks a lot.
>
> The method #kind_of? gives the results you want.

Not in the above cases. It's the same as using ===  :(
Tim P. (Guest)
on 2009-04-07 03:10
(Received via mailing list)
On Apr 6, 2009, at 4:12 PM, Iñaki Baz C. wrote:

>
>  b *** C => false
>
> but in cases *1 and *2 the result is not what I want:
>
>  A === b => true (I want false)
>  A === c => true (I want false)
>

Well, it's kinda hackish but it does give the correct output. Tailor
to suit your needs:


class A
   alias :like? :instance_of?
end

class B < A; end

class C < B
   def like?( clazz )
     return true if clazz == B
     super
   end
end

a = A.new
b = B.new
c = C.new

[A, B, C].each do |clazz|
   puts "a.like? #{clazz.name}  => #{a.like? clazz}"
end
puts

[A, B, C].each do |clazz|
   puts "b.like? #{clazz.name}  => #{b.like? clazz}"
end
puts

[A, B, C].each do |clazz|
   puts "c.like? #{clazz.name}  => #{c.like? clazz}"
end


==== OUTPUT ====
a.like? A  => true
a.like? B  => false
a.like? C  => false

b.like? A  => false
b.like? B  => true
b.like? C  => false

c.like? A  => false
c.like? B  => true
c.like? C  => true


Again, I'm not proud of this code -- it works, though, without being
too tricky.

Blessings,
TwP
Iñaki Baz C. (Guest)
on 2009-04-07 03:11
(Received via mailing list)
El Martes 07 Abril 2009, Tim P.
escribió:> c.like? B  => true
> c.like? C  => true
>
>
> Again, I'm not proud of this code -- it works, though, without being
> too tricky.

So freak! :)

Thanks a lot.
Sean O. (Guest)
on 2009-04-07 04:39
(Received via mailing list)
On Mon, Apr 6, 2009 at 11:12 PM, Iñaki Baz C. 
<removed_email_address@domain.invalid> wrote:
>
>  b *** C => false
>
> but in cases *1 and *2 the result is not what I want:
>
>  A === b => true (I want false)
>  A === c => true (I want false)
>
>
> I could play with a.class.ancestors, but isn't another way?
>
> Thanks a lot.
>

You need to specify somewhere the root of the inheritance hierarchy
you're interested in. Something like this:

class A
  def like?(klass)
    if klass == A
      self.class == A
    else
      self.class <= klass
    end
  end
end

More generally, this will do what you want (at least, what I think you
want ;)

module RootedClassComparison
  def self.included(other)
    module_eval {
      define_method :like? do |klass|
        if klass == other
          self.class == other
        else
          self.class <= klass
        end
      end
    }
  end
end

class A
  include RootedClassComparison
end
class B < A
end
class C < B
end
class D < C
end


a = A.new
b = B.new
c = C.new
d = D.new

klasses = [A, B, C, D]

# test pinched from Tim's example :)
klasses.each do |clazz|
  puts "a.like? #{clazz.name}  => #{a.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "b.like? #{clazz.name}  => #{b.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "c.like? #{clazz.name}  => #{c.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "d.like? #{clazz.name}  => #{d.like? clazz}"
end

Output:

a.like? A  => true
a.like? B  => false
a.like? C  => false
a.like? D  => false

b.like? A  => false
b.like? B  => true
b.like? C  => false
b.like? D  => false

c.like? A  => false
c.like? B  => true
c.like? C  => true
c.like? D  => false

d.like? A  => false
d.like? B  => true
d.like? C  => true
d.like? D  => true

Regards,
Sean
Robert K. (Guest)
on 2009-04-07 11:50
(Received via mailing list)
On 07.04.2009 00:41, Iñaki Baz C. wrote:
>>>
>>>
>>> I look for a way (***) to get the following results:
>> ...
>>
>> #instance_of? works for all cases except:
>>>   c *** B => true
>> Are you sure you need this to be true?
>
> Yes. Basically A is String and B is a child of String with various methods,
> and C is a more specific class.

Frankly, I find this a bit spooky for several reasons: first, you
inherit String which IMHO is almost always a bad idea(tm).  You should
consider using delegation, so you have

class B
   attr_reader :str
end

class C < B; end

Then, you introduce inconsistencies in inheritance checking.  That might
yield all sorts of surprises.

If you want to do it nevertheless, I'd probably go for a special method
which you override appropriately:

class Module
   def class_of?(obj)
     if self == String
       self == obj.class
     else
       self === obj
     end
   end
end

class B < String
end

class C < B
end

classes = [String,B,C]
classes.each do |cl|
   puts cl
   o = cl.new

   classes.each do |cl2|
     print cl2, " ", cl2.class_of?(o), "\n"
   end

   puts "--"
end


Something along these lines.

Kind regards

  robert
Iñaki Baz C. (Guest)
on 2009-04-07 22:27
(Received via mailing list)
El Martes 07 Abril 2009, Robert K.
escribió:> Frankly, I find this a bit spooky for several reasons: first, you
> inherit String which IMHO is almost always a bad idea(tm).  You should
> consider using delegation, so you have

Thanks a lot. However I've already solved it by changing my classes
definitions so I don't have that painful requeriment anymore :)
This topic is locked and can not be replied to.