Reputation: 2824
Currently working on a ruby minifier using Ripper's lex()
method. However currently attr_accessor
is defined as an identifier... I assume because it's a method.
Where is attr_accessor
defined? If I know where it's defined I can easily make exceptions for methods like it.
Upvotes: 1
Views: 102
Reputation: 110665
Yes, attr_accessor
is defined in the class Module
(Module#attr_accessor), but how does one go about finding it in the first place? Having to ask someone, or perhaps Googling, is not a very efficient way of going about it.
We can make use of the method Method#owner.1
owner
responds to method objects (instances of the class Method
), not to method names, which are symbols. Why? Because many modules/classes have methods that have the same symbolic name. For example, String
, Array
and Hash
all have an instance method named :[]
. Therefore, we cannot ask Ruby where :[]
is defined. We can ask, however, where the method
m = [1,2,3].method(:[])
#=> #<Method: Array#[]
is defined, namely,
m.owner
#=> Array
The determination of m
makes use of the method Object#method.
Alternatively, we could write
m = Array.instance_method(:[])
#=> #<UnboundMethod: Array#[]>
m.owner
#=> Array
This makes use of the method Module#instance_mathod.
Notice that in the first case the method :[]
is bound to the instance of Array
[1,2,3]
, whereas in the second case :[]
is not bound to any particular instance of Array
, so it is referred to as UnboundMethod
. Either way, we see that Array#[]
is defined in Array
(i.e., it is not inherited from an ancestor).
Let's consider another example.
We know that 3.zero? #=> false
, but do not find an instance method :zero?
in the class Integer. So, where is it? We can write:
m = 3.method(:zero?)
#=> #<Method: Integer(Numeric)#zero?>
or
m = Integer.instance_method(:zero?)
#=> #<UnboundMethod: Integer(Numeric)#zero?>
then
m.owner
#=> Numeric
Aha! It's defined in Numeric
, the superclass of Integer
, Float
, Rationale
and Complex
.
Notice that, in computing m
, the message displayed includes, "Integer(Numeric)"
. Even before computing m.owner
this tells us that the owner is Numeric
. By contrast, in finding the owner of Array#[]
the message was simply "Array"
. Helpful as always, Ruby parenthetically gives the owner when the owner is not the class of the receiver of method
or the class that is the receiver of instance_method
.
So now let us find the owner of the class method :attr_accessor
. We know that this method is available for every class (e.g., Class.new.methods.include?(:attr_accessor) #=> true
), so we could write, say,
m = Class.method(:attr_accessor)
#=> #<Method: Class.attr_accessor>
m.owner
#=> Module
since Class
is itself a class, but we could have instead written, say,
m = Regexp.method(:attr_accessor)
#=> #<Method: Regexp.attr_accessor>
m.owner
#=> Module
or even
m = Class.instance_method(:attr_accessor)
#=> #<UnboundMethod: Class(Module)#attr_accessor>
m.owner
#=> Module
the last because methods of every class (which is an instance of Class
) are instance methods of Class
.
1 If one forgets where the instance method owner
is defined, just remember that it is defined on methods, which are instances of the class Method
.
Upvotes: 0
Reputation: 2496
It is defined in the Module
class. (Documentation Link)
EDIT:
Just to make the answer more complete, it is a private method of the Module
class, which means you cannot call it with a receiver, need to have the class opened to use it (or using some hack like send
or eval
):
class MyClassOrModule
attr_accessor :foobar
end
You cannot invoke it as MyClassOrModule.attr_accessor
. As you already discovered in our comments below, Module.private_instance_methods
will show its presence.
Upvotes: 1