有没有办法让attr_reader创建方法的名称与实例变量不同?

时间:2011-04-24 18:41:01

标签: ruby attributes conventions standard-library

在Ruby中,有没有办法做类似

的事情
class Foo
    attr_reader :var_name :reader_name #This won't work, of course
    def initialize
        @var_name = 0
    end
end

# stuff here ....

def my_method
    foo = Foo.new
    assert_equal 0,foo.reader_name
end

换句话说,是否有一种标准方法可以为使用与变量不同的名称的变量创建一个访问器方法。 (当然,除了手工编码之外。)

3 个答案:

答案 0 :(得分:4)

您无法将任何选项传递给attr_reader

这是手写吗?

class Foo
  def initialize
      @var_name = 0
  end
  def reader_name; @var_name; end
end

答案 1 :(得分:3)

您可以使用alias_method

class Foo
    attr_reader :var_name
    alias_method :reader_name, :var_name
    def initialize
        @var_name = 0
    end
end

var_name构建的attr_reader方法仍然可用。您可以使用remove_method删除var_name方法,如果您真的想要(但请确保按正确的顺序获得所有内容):

class Foo
    attr_reader :var_name
    alias_method :reader_name, :var_name
    remove_method :var_name
    def initialize
        @var_name = 0
    end
end

如果您真的想要,可以将attr_reader_as方法修改为模块:

class Module
    def attr_reader_as(attr_name, alias_name)
        attr_reader attr_name
        alias_method alias_name, attr_name
        remove_method attr_name
    end
end

class Foo
    attr_reader_as :var_name, :reader_name
    def initialize
        @var_name = 0
    end
end

更好的attr_reader_as会使用哈希值(例如{:var_name => :reader_name, :var_name2 => :reader_name2}),但我会将其作为读者的练习。

答案 2 :(得分:2)

首先,我的口头禅:一个优秀的程序员可以很好地扮演他的队友。以下约定对其他人有益。

你想要什么似乎是非常规的,正如@edgerunner所述,糟糕的做法(读:我会揍你)。我只想三思而后行,我不知道你的用例,它可能证明是有效的...无论如何,复活节期间应该允许一点乐趣,所以我练习了一些元编程并与Mixins一起玩。

class Foo
  include MyAttrReader
  my_attr_reader :var_name, :reader_name
  def initialize
    @var_name = 0
  end
end
很干净。该模块可以解决问题(确保在课程之前加载此模块)

module MyAttrReader
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def my_attr_reader(attribute, read_attribute)
      define_method "#{read_attribute}" do
        instance_variable_get "@#{attribute}"
      end
    end
  end
end

在irb中测试

ruby-1.9.2-p180 :001 > load 'my_attr_reader.rb'
 => true 
ruby-1.9.2-p180 :002 > load 'foo.rb'
 => true 
ruby-1.9.2-p180 :003 > f = Foo.new
 => #<Foo:0x00000100979658 @var_name=0> 
ruby-1.9.2-p180 :004 > f.reader_name
 => 0 
ruby-1.9.2-p180 :005 > f.var_name
NoMethodError: undefined method `var_name' for #<Foo:0x00000100979658 @var_name=0>

我希望你看到这对别人有多么不直观。您可以覆盖to_s方法以显示如何访问@var_name,但我不会去那里...或者也定义var_name方法(两个getter方法)。坚持惯例。无论如何,我玩得很开心,祝你好运!