Meta-programming and the singleton class
Confusing, confusing, confusing. I finally have the opportunity to play with the has_many_polymorphs plugin. I’m using it to handle tagging. As suggested, I’ve written several tag extensions (tag_with, tag_list, tagged_with?, etc). I’m not having trouble writing methods that work on an instance of a class, it’s when I want to add methods that work directly on a class itself (even though a class is an instance of the class, Class—right?). I’ve read a couple of articles, but man, this stuff is tricky.
What I wanted to do was give each model a class method such as find_tagged_with. I thought it would be cleaner as a class method of the “taggable” class in question (but without me having to explicitly define it in each class, as that would defeat the purpose), rather than always referring back to the Tag class. This is how it works currently:
1 2 3 4 5 6 7 8 | class Dog < ActiveRecord::Base; end; class Cat < ActiveRecord::Base; end; Tag.find_by_name("animals").dogs # => {all dogs tagged with "animals"} Tag.find_by_name("animals").cats # => {all cats tagged with "animals"} |
I could leave it as is, but it’s not as intuitive as I’d like it to be. Since I’m getting objects of the Dog and Cat classes independently, I would like to have the find_tagged_with method become part of those classes. So I could do something like:
1 2 | Dog.find_tagged_with "animals" Cat.find_tagged_with "animals" |
From what I’ve read, class methods are just singleton methods defined on the instance of the class in question. So they wouldn’t apply to all instances of a class, but I wouldn’t need them to. I figured I would need to open up the singleton class, since that would only apply to one object. The “taggable” class would be the object, since they are really just instances of the class, Class (and all objects have singleton methods). But obviously what I was thinking wasn’t right, since all I can come up with is “undefined method ‘find_tagged_with’ for

Chris Tuesday, 24 Apr, 2007 Posted at 12:50PM
Since Dog and Cat are subclasses of
ActiveRecord::Base, there’s an easy way out:class ActiveRecord::Base class << self def find_tagged_with(...) ... end end # -- OR -- def self.find_tagged_with(...) ... end endRyan Tuesday, 24 Apr, 2007 Posted at 06:07PM
Man,
self.find...was the first thing I tried. But maybe I had the wrong combination or something. Thanks, though, that worked.There’s still a lot at the OO level that I don’t completely grasp. It seems that things get a lot more confusing with the way Ruby let’s you basically do whatever you want. But I’m getting there.
I always read complaints about “Ruby not supporting multiple-inheritance,” but now that I’m beginning to really understand mixins and how powerful they are, that seems like it’s just as good if not better than multiple-inheritance. Am I wrong in thinking that?
Chris Tuesday, 24 Apr, 2007 Posted at 06:14PM
I think the mixin concept is better because most traditional subclassing is done in order to provide the capabilities of many classes to a new class. Modules in Ruby solve this problem in a more organized manner in my opinion. Plus, being able to extend existing classes with modules is just fantastic.
The downside is sometimes a lack of clarity – a class may have been dynamically extended elsewhere, and you have to track down just where that method really exists. That stuff can get tricky.