Erb: terminating a script?

L

Lloyd Zusman

In PHP I can do the following:

A<br>
B<br>
<?php exit; ?>
C<br>
D<br>

This results in the following data showing up on the page:

A
B

I want to do something similar in Erb:

A<br>
B<br>
<% WHAT GOES HERE TO END THE SCRIPT? %>
C<br>
D<br>

What do use for "WHAT GOES HERE ..." in order to cause the
processing to end after A and B print out?

Thanks in advance.
 
W

William Ramirez

A<br>
B<br>
<% WHAT GOES HERE TO END THE SCRIPT? %>
C<br>
D<br>

What do use for "WHAT GOES HERE ..." in order to cause the
processing to end after A and B print out?

Just doing some quick reading, you may want to try exit or exit!, if
you haven't already. If you have, what happened? Did it still output C
and D?

Apparently they're very similar, however, exit! ignores exception
handling, at_exit functions, and finalizers.
 
L

Lloyd Zusman

William said:
Just doing some quick reading, you may want to try exit or exit!, if
you haven't already. If you have, what happened? Did it still output C
and D?

Apparently they're very similar, however, exit! ignores exception
handling, at_exit functions, and finalizers.

I did call exit, and it terminated the entire web server. I forgot to
mention that I'm running Erb inside of ErbHandler within a webrick
FileHandler instance, not within a stand-alone CGI. I'm sorry for
having left out that key piece of information in my original query.

The same thing happened with the "exit!" method.

What I'm looking for is something that can be invoked within
Erb#result which will terminate the eval at the point at which it
occurs, but which will allow information up to that point to still
appear in the output.

Does such a thing even exist?

If not, I can hack or subclass ErbHandler to enclose its generated
code within a "catch" block inside Erb#result, and then create a
method that I can call which will do an appropriate "throw" if I
want to terminate the processing. But before I embark on that
journey, I want to see if something that has this effect has
already been invented.
 
J

Jamis Buck

I did call exit, and it terminated the entire web server. I forgot to
mention that I'm running Erb inside of ErbHandler within a webrick
FileHandler instance, not within a stand-alone CGI. I'm sorry for
having left out that key piece of information in my original query.

The same thing happened with the "exit!" method.

Have you tried doing 'return'? Or perhaps 'break'? I haven't tried
these myself, so I don't know if they will work or not. Just throwing
out some ideas.

- Jamis
 
L

Lloyd Zusman

Jamis Buck said:
Have you tried doing 'return'? Or perhaps 'break'? I haven't tried these
myself, so I don't know if they will work or not. Just throwing out some
ideas.

Yes, I have tried them.

Using 'return', I get this error:

ERROR ThreadError: return can't jump across threads

Using 'break', I get this one:

undefined method `result' for #<String:0x850bddc>

However, following up on the idea I mentioned in my previous message, I
did the following ... and it works:

Original line in ErbHandler#do_GET ...

res.body = evaluate(ERB.new(data), req, res)

Replaced with ...

res.body = evaluate(ERB.new('<% catch:)quit) { %>' +
data +
'<% } %>'), req, res)

Then, I can exit by doing a '<% throw :quit %>' from anywhere in the
page. And any text that's specified before the 'throw' appears in the
resulting text.

The following also yields the same results:

res.body = evaluate(ERB.new('<% lambda { %>' + data + '<% }.call %>')
req, res)

In this case, I can exit early by using either '<% break %>' or
'<% return %>'. I like this one better, and this is what I have
just now implemented in my application.

Because of this, it seems to me that it would be beneficial if Erb were
to always put a lambda-call block around the text that gets evaluated.

I'm in favor of this enhancement going into a subsequent release, and
I'll soon submit a patch.

Thoughts or opinions?
 
J

Jamis Buck

Have you tried doing 'return'? Or perhaps 'break'? I haven't tried
these
myself, so I don't know if they will work or not. Just throwing out
some
ideas.

[snip]

Original line in ErbHandler#do_GET ...

res.body = evaluate(ERB.new(data), req, res)

Replaced with ...

res.body = evaluate(ERB.new('<% catch:)quit) { %>' +
data +
'<% } %>'), req, res)

Then, I can exit by doing a '<% throw :quit %>' from anywhere in the
page. And any text that's specified before the 'throw' appears in the
resulting text.

The following also yields the same results:

res.body = evaluate(ERB.new('<% lambda { %>' + data + '<% }.call
%>')
req, res)

In this case, I can exit early by using either '<% break %>' or
'<% return %>'. I like this one better, and this is what I have
just now implemented in my application.

Excellent work, Lloyd. Thanks for sharing!
Because of this, it seems to me that it would be beneficial if Erb were
to always put a lambda-call block around the text that gets evaluated.

I'm in favor of this enhancement going into a subsequent release, and
I'll soon submit a patch.

Thoughts or opinions?

I'd vote for it. :)

- Jamis
 
L

Lloyd Zusman

Jamis Buck said:
[ ... ]
res.body = evaluate(ERB.new('<% lambda { %>' +
data +
'<% }.call %>'),
req, res)

In this case, I can exit early by using either '<% break %>' or
'<% return %>'. I like this one better, and this is what I have
just now implemented in my application.

Excellent work, Lloyd. Thanks for sharing!

Well, I'm just glad to have found a solution, and I hope that it's
helpful to others.

I'd vote for it. :)

OK. Here it is. Unless or until this becomes a bona-fide Erb
enhancement, just put this code snippet in your application, somewhere
after the "require 'erb'" statement:

class ERB
def result(b=TOPLEVEL_BINDING)
# Enclosing the 'eval' in a 'lambda-call' block allows it
# to be cut short by means of a 'break' or 'return'.
if @safe_level
th = Thread.start {
$SAFE = @safe_level
lambda {
eval(@src, b, (@filename || '(erb)'), 1)
}.call
}
return th.value
else
return lambda {
eval(@src, b, (@filename || '(erb)'), 1)
}.call
end
end
end
 
J

Jim Weirich

I want to do something similar in Erb:

A<br>
B<br>
<% WHAT GOES HERE TO END THE SCRIPT? %>
C<br>
D<br>

What do use for "WHAT GOES HERE ..." in order to cause the
processing to end after A and B print out?

Here's a bizzare idea ...

<% callcc do |quit_early| %>
A<br>
B<br>
<% quit_early.call %>
C<br>
D<br>
<% end %>

Does that work?
 
L

Lloyd Zusman

Jim Weirich said:
Here's a bizzare idea ...

<% callcc do |quit_early| %>
A<br>
B<br>
<% quit_early.call %>
C<br>
D<br>
<% end %>

Does that work?

Yes, it does work.

I still like the lambda-call thing I mentioned in my previous message,
because using 'break' and 'return' seem to me to be more natural to use.

But this is a good idea, also. Thanks.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top