Sancarn
Sancarn

Reputation: 2824

Where is attr_accessor defined?

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

Answers (2)

Cary Swoveland
Cary Swoveland

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

ForeverZer0
ForeverZer0

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

Related Questions