【问题标题】:Get attr_reader, writer, or accessor oustide of the class获取类外的 attr_reader、writer 或 accessor
【发布时间】:2018-03-23 12:35:44
【问题描述】:

我目前正在使用 ruby​​ 进行一些元编程,并且我正在尝试隔离类的方法(该类在另一个文件中,我通过要求获得)。感谢 klass.public_instance_methods(false),我可以获得所有方法,但同时,我给出的数组也具有类的所有属性。我怎么能隔离他们?在关于 SO 的其他相关问题中,他们建议使用 klass.instance_variables 但是当我这样做时,它只返回一个空数组。

我似乎无法理解那个人。我不明白为什么还没有专门针对那个的方法...

例如:

我在一个文件中有这个类:

class T
    attr_reader:a
    def initialize(a)
        @a = a
    end
    def meth
        #code here
    end
end

而且,在另一个文件中,我有

require_relative 'T.rb'
class meta
   def initialize
       methods = T.public_instance_methods(false) #=> here methods = [:a,:meth] but I would want only to have [:meth]
       #rest of code
   end
end

【问题讨论】:

  • 你能举个例子解释一下吗?
  • @VishalTajPM 我添加了一个例子
  • "给定的数组也具有类的所有属性" - 什么属性?访问者? attr_accessor 是一个简单的宏,它定义了两个实例方法。不多也不少。这些方法没有什么特别之处。

标签: ruby methods metaprogramming


【解决方案1】:

对于这样定义的类:

class Klass
    attr_accessor :variable
    def initialize(variable)
        @variable = variable
    end

    def method
    end
end

您可以使用public_instance_methodsinstance_variables 方法找到公共的非属性实例方法。

public_instance_methods  = Klass.public_instance_methods(false)
#  [:method, :variable, :variable=]

instance_variables = Klass.new(nil).instance_variables
# [:@variable]

getters_and_setters = instance_variables
                        .map(&:to_s)
                        .map{|v| v[1..-1] }
                        .flat_map {|v| [v, v + '=']}
                        .map(&:to_sym)
# [:variable, :variable=]

without_attr = public_instance_methods - getters_and_setters
# [:method]

【讨论】:

  • 是的!非常感谢,原来如此!我错过了类的实例化,这就是它没有早点工作的原因。
  • @Lusheez 很高兴能帮上忙。另外,我更新了我的答案,因为原始代码仅适用于吸气剂 - 它没有从 public_instance_methods 数组中减去 <name>= 方法
  • 这仅在initialize 创建所有实例变量时有效。一般来说,实例变量可以随时定义,因此无法区分非属性方法和尚未定义变量的 getter。
【解决方案2】:

这是不可能的。 Ruby 的“属性”是完全正常的方法。没有办法将它们与其他方法区分开来。例如,这两个类是完全无法区分的:

class Foo
   attr_reader :bar
end

class Foo
   def bar
     @bar
   end
end

你可以试着聪明点,根据实例变量过滤掉它们,但这很危险:

class Foo
  # can filter this out using @bar
  attr_writer :bar
  def initialize
    @bar = []
  end
end

class Foo
  def initialize
    @bar = []
  end

  # this looks the same as above, but isn't a normal attribute!
  def bar= x
    @bar = x.to_a
  end
end

【讨论】:

  • 感谢您提供的信息,尽管出于我的确切目的,Maciej 提出的解决方案非常适合!
猜你喜欢
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多