Facets defines metaclass like this:
def meta_class(&block)
if block_given?
(class << self; self; end).class_eval(&block)
else
(class << self; self; end)
end
end
alias_method :metaclass, :meta_class
RSpec defines it this way:
def metaclass class << self; self; end end
I just spent an hour figuring out why some carefully-tested code went no-op after adding RSpec to a project. As a community we need to commit to a standard definition here. What should it be?
I agree, metaclass should be part of Ruby and given those two options, I can’t see why anyone would prefer the RSpec way over the Facets way.
Agreed there should be a standard definition. And it should really live in the language, not in assorted libraries. I think you’ll find it in a few others besides Facets and RSpec.
I’m going to move RSpec’s into a module that gets included where RSpec uses it so this won’t get in your (or anybody’s) way.
Clearly the one in Facets is more general purpose, so of these two I’d vote for that (for inclusion in a general purpose library).
I’ll disagree with Paul and David. metaclass should be an accessor only, and be paired with metaclass_eval (to mirror class and class_eval).
Why’s metaid gem almost gets this right:
To be clear – the metaclass method in RSpec is not intended for general consumption. It was a simple refactoring away of duplication within RSpec’s code and does exactly what is needed internally within RSpec. It was a mistake to put it in Object, and I’m moving it from there. But please don’t refer to it as “the RSpec Way.” Pretty please?
Terminology Objection: A “Metaclass” is an object that defines the behavior of a class. What the “metaclass” method above returns is the singleton class of an object (also sometimes called the “eigenclass”).
In as far as Ruby has metaclasses, you could possibly refer to the eigenclass of a Class object as a metaclass.
In summary, even though all metaclasses are eigenclasses, not all eigenclasses are metaclasses.
This is probably a hopeless attempt to keep some terminology straight, but at least I tried, right?
@Jim – I’m all for getting the words right. I just wish there were sexier words than “singleton class,” which makes me think of that awful pattern, and “eigenclass,” which makes me feel like I need another degree.
@Glenn – having two methods does make things more clear and honors command/query separation, so +1. I’m curious as to why you say why’s gem almost gets it right? Is it just the name? Of course, Jim would say he got both names wrong :)
Jim, part of me agrees with the terminology correction, and I’ve always liked the term ‘eigenclass’—but I suspect we’ve lost the battle at this point. (Note that even Why, who coined the term ‘eigenclass’, calls the method ‘metaclass’.)
David, the only thing I think Why got wrong is the name ‘meta_eval’ as opposed to ‘metaclass_eval’ (again, looking for name parallelism with ‘class’ and ‘class_eval’).
+1 on Glenn’s suggestion. Ruby has enough unnecessary variation in the api…consistency is a good thing, and Ruby is flexible enough where you can define your own aliases if it makes you happy.