Reputation: 69747
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.
Upvotes: 3
Views: 1537
Reputation: 7856
The class<< foo
syntax stands for "in the definition of the class of foo". So if you do this:
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
Upvotes: 10
Reputation: 12202
When it comes to caching data in view helpers you could use memoization.
Upvotes: 2
Reputation: 370102
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.
Upvotes: 6