web-dev-qa-db-ja.com

Rubyでattr_accessorsを一覧表示する最速/ワンライナーの方法は?

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_readerattr_writerの定義だけを表示するのはどうですか?

31
Lance Pollard

独自の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]
39
sepp2k

属性を配列に抽出し、それらを constant に割り当て、次に splatattr_accessorに割り当てます。

class SubClass < MyBaseClass
  ATTRS = [:id, :title, :body]
  attr_accessor(*ATTRS)
end

これで、定数を介してそれらにアクセスできます。

puts SubClass.ATTRS #=> [:id, :title, :body]
43
dukedave

継承ではなくミックスインを使用する別の方法を次に示します。

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]
6

クラス定義

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は、メソッド名の後に=を出力します

正規表現を使用して、その出力をフィルタリングできます。

2
jasonleonhard

クリスチャンの応答をフォローアップしますが、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
2
smooshy

等号マッチングロジックでフィルタリングできます。

methods = (SubClass.instance_methods - SubClass.superclass.instance_methods).map(&:to_s)
methods.select { |method| !method.end_with?('=') && methods.include?(method + '=') }
#> ["id", "title", "body"]
0
pocheptsov