attr_accessor
で定義されたすべてのメソッドを一覧表示する最短のワンライナーの方法は何ですか?そのようにしたいと思います。クラスMyBaseClass
があれば、それを拡張するものであれば、サブクラスで定義されたattr_accessor
を取得できます。このようなもの:
class MyBaseClass < Hash
def attributes
# ??
end
end
class SubClass < MyBaseClass
attr_accessor :id, :title, :body
end
puts SubClass.new.attributes.inspect #=> [id, title, body]
attr_reader
とattr_writer
の定義だけを表示するのはどうですか?
独自のattr_accessorを定義せずに、attr_accessorによって定義されたすべてのメソッドをリストし、attr_accessorによって定義されたメソッドのみをリストする方法(ワンライナーまたはその他)はありません。
MyBaseClassのattr_accessorをオーバーライドして、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]
継承ではなくミックスインを使用する別の方法を次に示します。
module TrackAttributes
def attr_readers
self.class.instance_variable_get('@attr_readers')
end
def attr_writers
self.class.instance_variable_get('@attr_writers')
end
def attr_accessors
self.class.instance_variable_get('@attr_accessors')
end
def self.included(klass)
klass.send :define_singleton_method, :attr_reader, ->(*params) do
@attr_readers ||= []
@attr_readers.concat params
super(*params)
end
klass.send :define_singleton_method, :attr_writer, ->(*params) do
@attr_writers ||= []
@attr_writers.concat params
super(*params)
end
klass.send :define_singleton_method, :attr_accessor, ->(*params) do
@attr_accessors ||= []
@attr_accessors.concat params
super(*params)
end
end
end
class MyClass
include TrackAttributes
attr_accessor :id, :title, :body
end
MyClass.new.attr_accessors #=> [:id, :title, :body]
class MyBaseClass
attr_writer :an_attr_writer
attr_reader :an_attr_reader
def instance_m
end
def self.class_m
end
end
class SubClass < MyBaseClass
attr_accessor :id
def sub_instance_m
end
def self.class_sub_m
end
end
p SubClass.instance_methods - Object.methods
p MyBaseClass.instance_methods - Object.methods
a = SubClass.new
b = MyBaseClass.new
p a.methods - Object.methods
p b.methods - Object.methods
#=> [:id, :sub_instance_m, :id=, :an_attr_reader, :instance_m, :an_attr_writer=]
#=> [:an_attr_reader, :instance_m, :an_attr_writer=]
attr_accessorはattr_writerとattr_readerの両方です
attr_readerはメソッド名の後にno =を出力します
attr_writerは、メソッド名の後に=を出力します
正規表現を使用して、その出力をフィルタリングできます。
クリスチャンの応答をフォローアップしますが、ActiveSupport :: Concern ..を使用するように変更します。
module TrackAttributes
extend ActiveSupport::Concern
included do
define_singleton_method(:attr_reader) do |*params|
@attr_readers ||= []
@attr_readers.concat params
super(*params)
end
define_singleton_method(:attr_writer) do |*params|
@attr_writers ||= []
@attr_writers.concat params
super(*params)
end
define_singleton_method(:attr_accessor) do |*params|
@attr_accessors ||= []
@attr_accessors.concat params
super(*params)
end
end
def attr_readers
self.class.instance_variable_get('@attr_readers')
end
def attr_writers
self.class.instance_variable_get('@attr_writers')
end
def attr_accessors
self.class.instance_variable_get('@attr_accessors')
end
end
等号マッチングロジックでフィルタリングできます。
methods = (SubClass.instance_methods - SubClass.superclass.instance_methods).map(&:to_s)
methods.select { |method| !method.end_with?('=') && methods.include?(method + '=') }
#> ["id", "title", "body"]