Question

I want to implement a (class) method attr_accessor_with_client_reset, which does the same thing as attr_accessor, but on every writer it additionally executes

@client = nil

So, for example,

attr_accessor_with_client_reset :foo

should produce the same result as

attr_reader :foo

def foo=(value)
  @foo = value
  @client = nil
end

How do I achieve this?

Was it helpful?

Solution

Sergio's solution is good, but needlessly complex: there's no need to duplicate the behavior of attr_reader, you can just delegate to it. And there's no need for all this double module include hook hackery. Plus, attr_accessor takes multiple names, so attr_accessor_with_client_reset should, too.

module AttrAccessorWithClientReset
  def attr_accessor_with_client_reset(*names)
    attr_reader *names

    names.each do |name|
      define_method :"#{name}=" do |v|
        instance_variable_set(:"@#{name}", v)
        @client = nil
      end
    end
  end
end

class Foo
  extend AttrAccessorWithClientReset

  attr_reader :client
  def initialize
    @foo = 0
    @client = 'client'
  end

  attr_accessor_with_client_reset :foo
end

f = Foo.new
f.foo    # => 0
f.client # => "client"
f.foo = 1
f.foo    # => 1
f.client # => nil

OTHER TIPS

It's actually pretty straightforward if you have some experience in ruby metaprogramming. Take a look:

module Ext
  def self.included base
    base.extend ClassMethods
  end

  module ClassMethods
    def attr_accessor_with_client_reset name
      define_method name do
        instance_variable_get "@#{name}"
      end

      define_method "#{name}=" do |v|
        instance_variable_set "@#{name}", v
        @client = nil
      end
    end
  end

end

class Foo
  include Ext

  attr_reader :client
  def initialize
    @foo = 0
    @client = 'client'
  end

  attr_accessor_with_client_reset :foo
end

f = Foo.new
f.foo # => 0
f.client # => "client"
f.foo = 1
f.foo # => 1
f.client # => nil

If this code is not completely clear to you, then I strongly recommend this book: Metaprogramming Ruby.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top