Attr / attr_accessor

Hi Ruby Folk,

I'm quite a newbie in programming. Last year I came to perl and now I'm
testing ruby.

I like the methods attr, attr_*. But there is one drawback. You can't tell the
methode that there should be a standard code that will be executed on every
access. IMHO The best would be a pre and a posthook.

I use the module Class::Methodmaker in perl, were this is possible. Surely I
can write (If I would know how) a own Class to handle this needs. But since
attr_ is so a nice standandard feature I'm the opionion that the feature I
ask for, would be a good enhancement.

Happy New Year

Markus

Markus Werner wrote:

access. IMHO The best would be a pre and a posthook.

You can already have that kind of thing.
attr_ are actually simply another way to write the following methods:

def variable
   @variable
end

def variable=(value)
   @variable=value
end

If you write these methods yourself instead of using the attr_-construct, you can do whatever you want in the methods and it still looks the same to everyone who uses your class.

Greetings,
Henrik

Perhaps:

class Module
  def attr_writer_proc(*args, &block)
    names = args.map{|s| s.to_sym}
    names.each do |name|
      define_method "#{name}=" do |val|
        instance_variable_set "@#{name}", block.call(val)
      end
    end
  end
  def attr_reader_proc(*args, &block)
    names = args.map{|s| s.to_sym}
    names.each do |name|
      define_method name do
        block.call instance_variable_get("@#{name}")
      end
    end
  end
end

This would act as a combo pre-hook and data filter:

class Foo
  # make sure the values are strings
  attr_writer_proc :foo, :bar do |val|
    val.to_str
  end

  # we only want to store copies the objects passed
  attr_writer_proc(:baz){|val| val.dup }
  
  # log changes to quux
  attr_writer_proc(:quux){|val| log("setting quux to %p"%[val]); val }
end

this could conceivably be wrapped up into the attr_writer/attr_reader
methods, since they currently don't take blocks... Also, it might be
handy to check the arity of the block and pass the variable name as an
optional second argument.

hth,
Mark

···

On Thu, 30 Dec 2004 22:34:40 +0900, Markus Werner <markus.werner@wobcom.de> wrote:

Hi Ruby Folk,

I'm quite a newbie in programming. Last year I came to perl and now I'm
testing ruby.

I like the methods attr, attr_*. But there is one drawback. You can't tell the
methode that there should be a standard code that will be executed on every
access. IMHO The best would be a pre and a posthook.

Henrik Ronellenfitsch ha scritto:

If you write these methods yourself instead of using the attr_-construct, you can do whatever you want in the methods and it still looks the same to everyone who uses your class.

I /think/ he knew this and was looking for a way to define a bunch of attributes with a common behaviour, say,

class Foo
  attr_with_logging :foo
end
Foo.new.foo=10 #Foo::Logger.log "changed foo in instance 123456"

This is not hard to do, and has imvho, little usage so I don't think it would be needed in core ruby. But this may be an example of "I Don't Have It So I Don't Need It".

Anyway, you could take a look at how mauricio fernandez implemented simple AOP in ~20 lines of ruby here:
http://www.thekode.net/ruby/techniques/CapturingMethods.html

or just use something like:

##warning dumb implementation ahead

class Module
     def attr_with_pre_hook(sym,&blk) #just handles accessors
         define_method(sym) do
           tmp=instance_variable_get "@"+sym.to_s
           blk.call(tmp)
           tmp
         end
     end
end

class Foo
  attr_writer :bar
  attr_with_pre_hook(:bar) {|b| puts b }
end

f=Foo.new
f.bar=20
p f.bar

Hi,

Henrik Ronellenfitsch ha scritto:
> If you write these methods yourself instead of using the
> attr_-construct, you can do whatever you want in the methods and it
> still looks the same to everyone who uses your class.

Hmmm...

don't got your mail yet.

I /think/ he knew this and was looking for a way to define a bunch of
attributes with a common behaviour, say,

You right.

class Foo
  attr_with_logging :foo
end
Foo.new.foo=10 #Foo::Logger.log "changed foo in instance 123456"

For example I playing around with vapor.rubyforge.org and you need to call the
methode object.mark_dirty everytime you write to the attribute.

But I see it's not to hard to implement althoug I'm not able to understand
your code, for now.
But I will...

regards

Markus

···

On Thursday 30 December 2004 15:41, gabriele renzi wrote:

Markus Werner wrote:

I /think/ he knew this and was looking for a way to define a bunch of
attributes with a common behaviour, say,

You right.

OK, I misunderstood you :slight_smile: