attr_writer variation

R

Ryan Hinton

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
 
R

Ross Bamford

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 :eek:ne, :two, :three, :modified
attr_writer :eek:ne, :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.
 
V

Vladimir Agafonkin

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?
 
R

Ross Bamford

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.
 
R

Ryan Hinton

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.
 
R

Ryan Hinton

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top