Ruby 私有方法、继承和元编程?

Ruby 私有方法、继承和元编程?,ruby,metaprogramming,Ruby,Metaprogramming,我有以下定义: #!/usr/bin/env ruby class Something def self._attr_accessor key, value, type (class << self; self; end).send( :attr_accessor, key.to_sym) instance_variable_set "@#{key}", value end end class Client < Something _attr_a

我有以下定义:

#!/usr/bin/env ruby

class Something
  def self._attr_accessor key, value, type
    (class << self; self; end).send( :attr_accessor, key.to_sym)
    instance_variable_set "@#{key}", value
  end
end

class Client < Something
  _attr_accessor 'foo_bar', 'json', String
end

my_something = Client.new
puts my_something.foo_bar
#/usr/bin/env ruby
分类
定义自身属性访问器键、值、类型

(class尝试将您的方法替换为:

class Something

  def self._attr_accessor key, value, type
    method_sym      = key.to_sym
    insance_variable = "@#{key}"

    (class << self; self; end).send( :attr_accessor, method_sym)
    instance_variable_set insance_variable, value

    attr_accessor method_sym

    define_method(method_sym) do 
        self.instance_variable_get(insance_variable) or self.class.send(method_sym) 
    end

  end

 end
在上面的代码中,define_method是为某些内容定义一个实例方法,方法名称是键,例如

 attr_accessor "foo_bar", "json", String
然后,定义\u方法生成的代码是:

 def foo_bar
    if @foo_bar
       @foo_bar
    else
      self.class.foo_bar
    end        
 end
除此之外,ActiveSupport还有attr\u accessor\u和\u default方法,似乎也是这个函数。 请参阅其代码:

class Module
# Declare an attribute accessor with an initial default return value.t>:
#
#   class Person
#     attr_accessor_with_default :age, 25
#   end
#
#   person = Person.new
#   person.age # => 25
#
# To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
# in scope of self:
#
#   attr_accessor_with_default(:element_name) { name.underscore }
#
def attr_accessor_with_default(sym, default = Proc.new)
  define_method(sym, block_given? ? default : Proc.new { default })
  module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
    def #{sym}=(value)
      class << self; attr_accessor :#{sym} end
      @#{sym} = value
    end
  EVAL
end
end
类模块
#使用初始默认返回值声明属性访问器。t>:
#
#班主任
#属性访问器,默认值:年龄,25岁
#结束
#
#person=person.new
#person.age#=>25
#
#为attribute:element\u name指定一个动态默认值,并进行计算
#在自我范围内:
#
#attr_访问器_,默认值为(:element_name){name.下划线}
#
def attr_访问器_和_默认值(sym,default=Proc.new)
define_方法(sym,block_给定??默认值:Proc.new{default})

模块评估(对于其中一个,我认为您被以下事实绊倒了:
格式
上的保留方法,它与您的
属性访问器
尝试相冲突

其次,还有一个更好的方法可以做到这一点。我为正在处理的项目创建了一个相当健壮的“访问器”实用程序类。它允许您定义类级别的默认值,并且仍然覆盖实例定义

实现如下所示:

module OptionAccessor
  # Given a list of names, this declares an option accessor which works like
  # a combination of cattr_accessor and attr_accessor, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Optional hash at end of list can be used to set:
  #  * :default => Assigns a default value which is otherwise nil
  #  * :boolean => If true, creates an additional name? method and will
  #                convert all assigned values to a boolean true/false.
  def option_accessor(*args)
    option_reader(*args)
    option_writer(*args)
  end

  # Given a list of names, this declares an option reader which works like
  # a combination of cattr_reader and attr_reader, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Optional hash at end of list can be used to set:
  #  * :default => Assigns a default value which is otherwise nil
  #  * :boolean => If true, creates an additional name? method and will
  #                convert all assigned values to a boolean true/false.
  def option_reader(*names)
    names = [ names ].flatten.compact
    options = names.last.is_a?(Hash) ? names.pop : { }

    names.each do |name|
      iv = :"@#{name}"

      (class << self; self; end).class_eval do
        if (options[:boolean])
          define_method(:"#{name}?") do
            iv_value = instance_variable_get(iv)

            !!(iv_value.nil? ? (self.superclass.respond_to?(name) ? self.superclass.send(name) : nil) : iv_value)
          end
        end

        define_method(name) do
          iv_value = instance_variable_get(iv)

          iv_value.nil? ? (self.superclass.respond_to?(name) ? self.superclass.send(name) : nil) : iv_value
        end
      end

      define_method(name) do
        iv_value = instance_variable_get(iv)

        iv_value.nil? ? self.class.send(name) : iv_value
      end

      if (options[:boolean])
        define_method(:"#{name}?") do
          iv_value = instance_variable_get(iv)

          !!(iv_value.nil? ? self.class.send(name) : iv_value)
        end
      end

      instance_variable_set(iv, options[:default])
    end
  end

  # Given a list of names, this declares an option writer which works like
  # a combination of cattr_writer and attr_writer, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Options can be specified:
  #  * :boolean => If true, converts all supplied values to true or false
  #                unless nil, in which case nil is preserved.
  def option_writer(*names)
    names = [ names ].flatten.compact
    options = names.last.is_a?(Hash) ? names.pop : { }

    names.each do |name|
      iv = :"@#{name}"

      (class << self; self; end).class_eval do
        if (options[:boolean])
          define_method(:"#{name}=") do |value|
            instance_variable_set(iv, value.nil? ? nil : !!value)
          end
        else
          define_method(:"#{name}=") do |value|
            instance_variable_set(iv, value)
          end
        end
      end

      if (options[:boolean])
        define_method(:"#{name}=") do |value|
          instance_variable_set(iv, value.nil? ? nil : !!value)
        end
      else
        define_method(:"#{name}=") do |value|
          instance_variable_set(iv, value)
        end
      end
    end
  end
end
模块选件附件
#给定一个名称列表,这将声明一个选项访问器,其工作方式如下
#cattr_访问器和attr_访问器的组合,默认情况除外
#为类定义的将向下传播到实例和子类,
#但这些默认值在子类和实例中可能会被忽略
#无干扰。列表末尾的可选哈希可用于设置:
#*:default=>指定一个默认值,否则为零
#*:boolean=>如果为true,则创建一个额外的name?方法并将
#将所有指定的值转换为布尔值true/false。
def选项\存取器(*args)
选项_读取器(*args)
选项_writer(*args)
结束
#给定一个名称列表,这声明了一个选项读取器,其工作方式如下
#cattr_读取器和attr_读取器的组合,默认情况除外
#为类定义的将向下传播到实例和子类,
#但这些默认值在子类和实例中可能会被忽略
#无干扰。列表末尾的可选哈希可用于设置:
#*:default=>指定一个默认值,否则为零
#*:boolean=>如果为true,则创建一个额外的name?方法并将
#将所有指定的值转换为布尔值true/false。
def选项_读卡器(*名称)
名称=[names].flatte.compact
options=names.last.is_a?(散列)?names.pop:{}
名字。每个人都有名字|
iv=:“@#{name}”
(类)如果为true,则将所有提供的值转换为true或false
#除非为零,否则在这种情况下,保留为零。
def选项_写入程序(*名称)
名称=[names].flatte.compact
options=names.last.is_a?(散列)?names.pop:{}
名字。每个人都有名字|
iv=:“@#{name}”

(类这就是我要寻找的,你有任何用例示例吗?另外,将metod从
format
更改为
foobar
在类外调用时,我会遇到和未声明的问题,类似于我最初描述的在类内调用表示私有方法声明时工作正常。如果可以的话向我解释为什么该方法被声明为私有,我也将非常感激!一个例子是只将
option\u accessor:foo
放在一个类中。然后你可以调用
MyClass.foo
MyClass.new.foo
等等,即使通过
MyClass.foo='foo'
赋值。该方法没有被声明,但是re是一个预先存在的方法,名称相同,已经是私有的。这可能就是问题所在。manor定义了一些东西,只允许访问它自己在类内声明的方法(即
self.foo
在类内有效,但在类外无效)。你的回答没有回答我的问题,但我还是投票支持你,因为你的回答很好。谢谢!这消除了我的错误,但我仍然无法访问方法,就好像是使用attr_访问器定义的一样。我的全部目标是使用一个我能够为其定义默认值的方法来引导先前存在的方法h、 另外,我真的不确定
defin\u方法
块中发生了什么,你能给我解释一下吗?
 def foo_bar
    if @foo_bar
       @foo_bar
    else
      self.class.foo_bar
    end        
 end
class Module
# Declare an attribute accessor with an initial default return value.t>:
#
#   class Person
#     attr_accessor_with_default :age, 25
#   end
#
#   person = Person.new
#   person.age # => 25
#
# To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
# in scope of self:
#
#   attr_accessor_with_default(:element_name) { name.underscore }
#
def attr_accessor_with_default(sym, default = Proc.new)
  define_method(sym, block_given? ? default : Proc.new { default })
  module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
    def #{sym}=(value)
      class << self; attr_accessor :#{sym} end
      @#{sym} = value
    end
  EVAL
end
end
module OptionAccessor
  # Given a list of names, this declares an option accessor which works like
  # a combination of cattr_accessor and attr_accessor, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Optional hash at end of list can be used to set:
  #  * :default => Assigns a default value which is otherwise nil
  #  * :boolean => If true, creates an additional name? method and will
  #                convert all assigned values to a boolean true/false.
  def option_accessor(*args)
    option_reader(*args)
    option_writer(*args)
  end

  # Given a list of names, this declares an option reader which works like
  # a combination of cattr_reader and attr_reader, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Optional hash at end of list can be used to set:
  #  * :default => Assigns a default value which is otherwise nil
  #  * :boolean => If true, creates an additional name? method and will
  #                convert all assigned values to a boolean true/false.
  def option_reader(*names)
    names = [ names ].flatten.compact
    options = names.last.is_a?(Hash) ? names.pop : { }

    names.each do |name|
      iv = :"@#{name}"

      (class << self; self; end).class_eval do
        if (options[:boolean])
          define_method(:"#{name}?") do
            iv_value = instance_variable_get(iv)

            !!(iv_value.nil? ? (self.superclass.respond_to?(name) ? self.superclass.send(name) : nil) : iv_value)
          end
        end

        define_method(name) do
          iv_value = instance_variable_get(iv)

          iv_value.nil? ? (self.superclass.respond_to?(name) ? self.superclass.send(name) : nil) : iv_value
        end
      end

      define_method(name) do
        iv_value = instance_variable_get(iv)

        iv_value.nil? ? self.class.send(name) : iv_value
      end

      if (options[:boolean])
        define_method(:"#{name}?") do
          iv_value = instance_variable_get(iv)

          !!(iv_value.nil? ? self.class.send(name) : iv_value)
        end
      end

      instance_variable_set(iv, options[:default])
    end
  end

  # Given a list of names, this declares an option writer which works like
  # a combination of cattr_writer and attr_writer, except that defaults
  # defined for a class will propagate down to the instances and subclasses,
  # but these defaults can be over-ridden in subclasses and instances
  # without interference. Options can be specified:
  #  * :boolean => If true, converts all supplied values to true or false
  #                unless nil, in which case nil is preserved.
  def option_writer(*names)
    names = [ names ].flatten.compact
    options = names.last.is_a?(Hash) ? names.pop : { }

    names.each do |name|
      iv = :"@#{name}"

      (class << self; self; end).class_eval do
        if (options[:boolean])
          define_method(:"#{name}=") do |value|
            instance_variable_set(iv, value.nil? ? nil : !!value)
          end
        else
          define_method(:"#{name}=") do |value|
            instance_variable_set(iv, value)
          end
        end
      end

      if (options[:boolean])
        define_method(:"#{name}=") do |value|
          instance_variable_set(iv, value.nil? ? nil : !!value)
        end
      else
        define_method(:"#{name}=") do |value|
          instance_variable_set(iv, value)
        end
      end
    end
  end
end