Forum: Ruby Class atrr_accessor

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.
Ole O. (Guest)
on 2008-12-02 21:22
Why does this not work?

>> class Foo
>>   self.class.attr_accessor :baz
>>   end
TypeError: Foo is not a class
        from (irb):19


I understand that the class << self idiom can be used to work around
this problem but I would like to understand why the above triggers such
an error and what is meant by it.

Thanks.
Thomas S. (Guest)
on 2008-12-02 22:10
(Received via mailing list)
On Dec 2, 2:16 pm, Oliver S. <removed_email_address@domain.invalid> wrote:
> Why does this not work?

An ideology?

> >> class Foo
> >>   self.class.attr_accessor :baz
> >>   end
>
> TypeError: Foo is not a class
>         from (irb):19

  class Module
    public :attr_accessor
  end

All fixed.

> I understand that the class << self idiom can be used to work around
> this problem but I would like to understand why the above triggers such
> an error and what is meant by it.

Well, I think the idea is that you shouldn't be changing a class'
interface from the "outside" ie. so willy-nilly. So you are required
to go "inside" to get the job done. Sort of a caution barrier. But it
does suck that this requires a second layer, eg. class << self, to get
there. I have tried a private #meta method in the past.

 class Foo
   meta.attr_accessor :baz
 end

which works, though I'm not sure the term "meta" feels quite right.
I've avoided ever using it though because I know others would look at
it and think "what?".

T.
The H. (Guest)
on 2008-12-02 22:18
Oliver S. wrote:
> Why does this not work?
>
>>> class Foo
>>>   self.class.attr_accessor :baz
>>>   end
> TypeError: Foo is not a class
>         from (irb):19

You must have miscopied your error message.  I obtain

  NoMethodError: private method `attr_accessor' called for Class:Class

attr_accessor is a private method of Module, and as such cannot be
called directly with the dot notation.  You can call it with send(), or
like this:

  class Foo
    self.class.instance_eval { attr_accessor :baz }
  end

But nevermind, because this is not what you want!

  Foo.baz = :qux
  p Foo.baz # => :qux

  class Bar
  end

  Bar.baz = 4
  p Bar.baz # => 4

You've just added methods #baz and #baz= to every class.  This is
because

  class Foo
    p(self.class == Class) # => true
  end

You want the self << class construct that you mentioned, which is the
singleton class,

  class Foo
    class << self
      attr_accessor :baz
    end
  end

When you said self.class, you were calling Object#class which tells you
the birth canal of an object.  But many things can happen after birth,
and kids can end up really different from their parents!  This
difference is described in the singleton class.  It's unique to the
object.  Above, we are adding a method to Foo's singleton class.

BTW there's nothing special about "class << self".  You could also say,

class Foo
end
class << Foo
  attr_accessor :baz
end

which is the same thing.  "class << x" grabs the singleton class of x.

Hope this helps.
This topic is locked and can not be replied to.