tags:

views:

280

answers:

4

I've been looking at some articles that say that class variables are bad in Ruby. They suggest using the meta-class (or singleton class). This is my sample code

class Joe
  class << self # here we're putting methods in Joe's "meta class" 
    attr_accessor :foo
  end
  def self.foo2
  end
  def self.foo2=value
  end
end

puts Joe.singleton_methods

I understand that foo and foo2 are essentially the same, though there's no way to use attr_accesor with foo2.

I don't get what's up with the class << self syntax. Is there some kind of concatenation happening, or... what is it? Is that some kind of extension, inheritance or monkey-patching?

Edit (Bonus): While I'm here, is there any way to cache data on a view helper? I have tried using this class << self thing, but the helper methods do not find the accessor.

+3  A: 

The class << foo opens the singleton class of foo, which is the class that foo is the only instance of (and which implicitly inherits foo's "real" class). So it's a kind of extension (you're adding methods to one specific object that are not defined by that object's class). It's not monkey-patching because you're only affecting that one object and not any other object of that class.

Note that def foo.bar is merely a shortcut for

class <<foo
  def bar

i.e. it does the same thing behind the scenes. The << has nothing to do with the << method. It's just part of the syntax.

sepp2k
Cool, thank you. I've edited the question with a bonus (really to not explain myself again in another question)... how can I use this in a view helper.
Yar
+1  A: 

When it comes to caching data in view helpers you could use memoization.

Adam Byrtek
I get it now. But more importantly, I need to shut off caching in the config.
Yar
+2  A: 

Why the lucky stiff has a good article on Metaclasses where he explains the class << self and more.

http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

David Billskog
excellent, thank you I will check that out
Yar
It appears this article has moved to http://dannytatom.github.com/metaid/
Mike Ashley
+5  A: 

The "class<<" stands for "in the definition of the class of foo". So if you do

class Foo
   class << self
     # class method defined as INSTANCE method
     # the only instance being Foo (the class)
     def boo
       ...
     end
   end
end

this is analogous to

class Foo
  def self.boo #class method
  end
end

In the same vein, you can grab a separate object and extend it with methods

class << some_object
   def something # adds a method to some_object ONLY
   end
end

So when you do "within class of self" within a class definition, you are jumping "one level up" into the definition of your "eigen"-class (or "metaclass") where you can call stuff in the context of your "class as an instance of this thing I am in". So the class methods of your class become instance methods and can be defined and treated as such, and module includes will affect the class methods no the instance methods.

For your case:

class Joe
      # here we're putting methods in the "class of class"
  class << self
        include ClassMethodsForJoe
    attr_accessor :foo
  end
end
Joe.foo # this is the method we made
Julik
WOW. That's the answer I needed.
Yar