开发者

Is there a way to make attr_reader create methods with a different name than the instance variable?

In Ruby, is there a way to do something l开发者_Python百科ike

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

In other words, is there a standard way to make an accessor method for a variable that uses a different name than the variable. (Besides hand-coding it, of course.)


You could use alias_method:

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

The var_name method built by attr_reader would still be available though. You could use remove_method to get rid of the var_name method if you really wanted to (but make sure you get everything in the right order):

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

If you really wanted to, you could monkey patch an attr_reader_as method into Module:

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

A better attr_reader_as would take a hash (e.g. { var_name: :reader_name, var_name: :reader_name2}) but I'll leave that as an exercise for the reader.


You can't pass any options to attr_reader

Is this a handcoding?

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


First off, my mantra: A good programmer plays his teammates good. Following conventions is playing others good.

What you want seems unconventional, and as @edgerunner states, bad practice (read: I would've smacked you). All I'm saying, think twice about this, I don't know your use case, it might prove valid... Anyway, a little fun during easter should be allowed, so I practiced some metaprogramming and played with Mixins.

class Foo
  include MyAttrReader
  my_attr_reader :var_name, :reader_name
  def initialize
    @var_name = 0
  end
end

pretty clean. The module does the trick (be sure to load this module before the class)

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

Testing in 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>

I hope you see how unintuitive this will be for others. You could override the to_s method to show how to access @var_name, but I wouldn't go there... or define the var_name method too (two getter-methods). Stick to conventions. Anyhow, I had great fun, good luck!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜