[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

attr_writer variation

Ryan Hinton

1/26/2006 10:16:00 PM

I am working on a nice little document-based app where I would like to
take selective action based on whether data have been modified (e.g.
prompt to save before exit). When I imagine writing a bunch of
"memberVariable=(newVar)" methods, all with the same pattern for the
guts, I think there must be a better way.

How does attr_writer do this? I tried to figure out how to do
something similar in vanilla Ruby, but I don't see a way to
programmatically define a new method. Would I have to write a C
extension for this?

Here is roughly what I want.

module AttrWriterTrackModified
def attr_writer(*syms)
syms.each do |sym|
eval("def #{sym}=(val)
if @#{sym} != val
@#{sym} = val
@modified = true
end
end;")
end
end
end

5 Answers

Ross Bamford

1/26/2006 11:47:00 PM

0

On Thu, 26 Jan 2006 22:15:50 -0000, Ryan Hinton <iobass@email.com> wrote:

> Here is roughly what I want.
>
> module AttrWriterTrackModified
> def attr_writer(*syms)
> syms.each do |sym|
> eval("def #{sym}=(val)
> if @#{sym} != val
> @#{sym} = val
> @modified = true
> end
> end;")
> end
> end
> end
>

Maybe I'm missing something, but you're almost there. You could try this:

class Module
def attr_writer(*syms)
syms.each do |sym|
module_eval <<-EOC
def #{sym}=(val)
if @#{sym} != val
@#{sym} = val
@modified = true
end
end
EOC
end
end
end

Just use it as normal:

class TryIt
attr_reader :one, :two, :three, :modified
attr_writer :one, :two, :three
def initialize(one, two, three)
@one, @two, @three = one, two, three
@modified = false
end
end

p t = TryIt.new(1,2,3)
p t.one
p t.two
p t.three
p t.modified

p t.two = 4
p t.one
p t.two
p t.three
p t.modified

Output:

#<TryIt:0xb7facae4 @modified=false, @three=3, @two=2, @one=1>
1
2
3
false
1
4
3
true

(Hmm, I bet you could make an attr_initializer or something to cover that
initialize method too ... ;))

Hope that helps.

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Vladimir Agafonkin

1/27/2006 12:13:00 AM

0

By the way, here's a simple newbie question: what is the difference
between defining some method with class_eval in Class class and with
module_eval in Module class?

Ross Bamford

1/27/2006 12:34:00 AM

0

On Fri, 27 Jan 2006 00:12:56 -0000, Vladimir Agafonkin
<agafonkin@gmail.com> wrote:

> By the way, here's a simple newbie question: what is the difference
> between defining some method with class_eval in Class class and with
> module_eval in Module class?
>

Aside from the usual difference between class instance and module instance
methods, I don't think there is a difference. Module.class_eval is an
alias for Module.module_eval.

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Ryan Hinton

1/27/2006 5:30:00 PM

0

That works! But I don't want the tracking all the time. Can I put it
in a module to mix-in? I've been fiddling trying different variations,
but apparently I am missing the reason why your example works.

Ryan Hinton

1/27/2006 7:14:00 PM

0

I think I figured it out, but I'm still a little hazy so any
clarification is great. "include" merges the definition of the module
and the class, so instances of the class effectively have two
superclasses. "extend" adds the instance methods from a module to the
current object. When I call attr_writer, I am effectively calling a
method in the context of the current class being defined (self ==
MyClass). Its methods are defined in Class and/or Method, so I can
redefine attr_writer there. If I don't want to do that, I can "extend"
a class being defined with a module I write that defines and
attr_writer method. Then using attr_writer will do what I want.
However, I will need to do this in each class I want this behavior.

I am still confused by module_function. Normally the instance methods
of a module are passed on in an "include", but module_function makes a
method a module method (Mod.meth) _and_ passes it on as a private
instance method in an "include". This seems really quirky.