views:

202

answers:

1

What's the shortest, one-liner way to list all methods defined with attr_accessor? I would like to make it so, if I have a class MyBaseClass, anything that extends that, I can get the attr_accessor's defined in the subclasses. Something like this:

class MyBaseClass < Hash
  def attributes
    # ??
  end
end

class SubClass < MyBaseClass
  attr_accessor :id, :title, :body
end

puts SubClass.new.attributes.inspect #=> [id, title, body]

What about to display just the attr_reader and attr_writer definitions?

+2  A: 

There is no way (one-liner or otherwise) to list all methods defined by attr_accessor and only methods defined by attr_accessor without defining your own attr_accessor.

Here's a solution that overrides attr_accessor in MyBaseClass to remember which methods have been created using attr_accessor:

class MyBaseClass
  def self.attr_accessor(*vars)
    @attributes ||= []
    @attributes.concat vars
    super(*vars)
  end

  def self.attributes
    @attributes
  end

  def attributes
    self.class.attributes
  end
end

class SubClass < MyBaseClass
  attr_accessor :id, :title, :body
end

SubClass.new.attributes.inspect #=> [:id, :title, :body]
sepp2k
Minor nitpick, but on line 5, you don't need to call `super(*vars)` since you're passing it the same arguments that the method received; you can just call `super` without any arguments or parentheses, which will automatically pass `*vars`.
Mark Rushakoff
@MarkRushakoff: I figured this way it is more obvious what's going on. Many people assume `super` is the same thing as `super()` (and to be honest I'm not sure that I wouldn't like it better if it was).
sepp2k
The rationale behind super passing the arguments (and block if any) by default is that usually the interface from doesn't change and it's thus what you want.I'd say embrace Ruby and let others embrace it too, even if that means they have to learn that super is not the same as super()...
Marc-André Lafortune