once modifier (pickaxe book page 391)

C

ChrisKaelin

The following code is from the pickaxe book page 391 (slightly
modified in order to have it available in all classes, that are
defined). It implements a once modifier, that ensures a method's body
is only called, if it's return value (an instance variable) is not
already set.

# Extending Module with the amazing once modifier
class Module
def once(*ids) # :nodoc:
for id in ids
module_eval <<-"EOF"
alias_method :__#{id.to_i}__, :#{id.to_s}
private_methods :__#{id.to_i}__
def #{id.to_s}(*args, &block)
(@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
end
EOF
end
end
end

It really works very well and is a wonderful example of ruby's power.

But I got some noob questions now:
- Why isn't this cool method available in ruby directly?
- Why can't I use "ids.each" instead of "for id in ids"? Ok, this
question has nothing to do with the code itself ;-)
- I know what "||=" does (evaluate assignment only, if the left part
is false), but what do you call this?

Sorry for my lack of these basics and thanks in advance for any
answers.

Chris
 
A

ara.t.howard

The following code is from the pickaxe book page 391 (slightly
modified in order to have it available in all classes, that are
defined). It implements a once modifier, that ensures a method's body
is only called, if it's return value (an instance variable) is not
already set.

# Extending Module with the amazing once modifier
class Module
def once(*ids) # :nodoc:
for id in ids
module_eval <<-"EOF"
alias_method :__#{id.to_i}__, :#{id.to_s}
private_methods :__#{id.to_i}__
def #{id.to_s}(*args, &block)
(@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
end
EOF
end
end
end

It really works very well and is a wonderful example of ruby's power.

But I got some noob questions now:
- Why isn't this cool method available in ruby directly?

one possible reason


harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
once :foo
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
42



harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
2.times{ once :foo }
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
Segmentation fault (core dumped)


harp:~ > ruby --version
ruby 1.8.4 (2005-12-01) [i686-linux]

regards.

-a
 
C

ChrisKaelin

one possible reason


harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
once :foo
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
42



harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
2.times{ once :foo }
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
Segmentation fault (core dumped)


harp:~ > ruby --version
ruby 1.8.4 (2005-12-01) [i686-linux]

regards.

-a
whoops, o.k. I see...
but... why should I do this: 2.times { once :foo } ? o.k. I can
imagine, ruby should allow everything without coredumping ;-)
 
A

ara.t.howard

one possible reason


harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
once :foo
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
42



harp:~ > cat a.rb
require 'once'
class NotRobust
def foo() p 42 end
2.times{ once :foo }
end

nr = NotRobust.new
2.times{ nr.foo }


harp:~ > ruby a.rb
Segmentation fault (core dumped)


harp:~ > ruby --version
ruby 1.8.4 (2005-12-01) [i686-linux]

regards.

-a
whoops, o.k. I see...
but... why should I do this: 2.times { once :foo } ? o.k. I can
imagine, ruby should allow everything without coredumping ;-)

-a
 
B

Brian Candler

- Why can't I use "ids.each" instead of "for id in ids"? Ok, this
question has nothing to do with the code itself ;-)

ids.each do |id|
...
end
- I know what "||=" does (evaluate assignment only, if the left part
is false), but what do you call this?

Note that

a ||= b

is syntactic sugar for

a = a || b

My K&R C book just calls them "assignment operators", although C doesn't
have ||= (but it has *=, /=, %=, +=, -=, <<=. >>=, &=, ^=, |=)
 
C

ChrisKaelin

ids.each do |id|
...
end
nope, that gives me:
SyntaxError: compile error
(irb):3: syntax error, unexpected kDO
(irb):13: can't find string "EOF" anywhere before EOF
(irb):4: syntax error, unexpected $end, expecting tSTRING_CONTENT or
tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
from (irb):4
from :0

while " for id in ids" works well (that's why the official code uses
it, I guess. Normally "each" is preferred over that, afaik.

Note that

a ||= b

is syntactic sugar for

a = a || b

My K&R C book just calls them "assignment operators", although C doesn't
have ||= (but it has *=, /=, %=, +=, -=, <<=. >>=, &=, ^=, |=)
my fault, I should've known that, I just only knew ||= from Array
stuff, so I could not get the link to a = a || b. Thanks a lot!
 
S

Sebastian Hungerecker

ChrisKaelin said:
SyntaxError: compile error
(irb):3: syntax error, unexpected kDO
(irb):13: can't find string "EOF" anywhere before EOF

That would be caused by leaving out the "EOF" not by replacing
the for-loop with each.


HTH,
Sebastian Hungerecker
 
C

ChrisKaelin

That would be caused by leaving out the "EOF" not by replacing
the for-loop with each.
Even more shame for me:
it was, because I used
ids.each |id| do
instead of
ids.each do |id|

ouch!
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top