# Proposal: Exception handling in container classes

**URL:** <https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552>\
**Category:** Radiant CMS\
**Created:** [July 30, 2006, 3:51am UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552 "2006-07-30T03:51:35Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [July 30, 2006, 3:51am UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/1 "2006-07-30T03:51:35Z")

</div>

Right now, render\_tag (in page\_context.rb) rescues all exceptions and  
turns them into HTML output. It’d be really nice to be able to use  
exceptions within behaviors - especially within container tags.  
F’rinstance, I’ve got a “style” tag that nests inside a “navigation”  
container, and if that style tag is missing a required attribute, I’d  
like to raise an exception to the navigation container so it doesn’t  
continue trying to render. But the container calls tag.expand, which in  
turn calls render\_tag, which steals the exception from me.

I understand the intent, but I wonder if there’s a less intrusive way to  
accomplish it, while still allowing outer tags to rescue their own  
exceptions. What if that rescue were executed only on the outermost  
tags? Would that break anything? It seems to me that this would still  
prevent exceptions from crashing Rails, while allowing internal  
exception-handling. Ya?

OT but related: I tried reopening PageContext in my own plugin to make  
this modification, but even a simple

class PageContext  
end

results in the apparent loss of the class; behavior.rb then complains  
that PageContext.new expects 0 arguments. Same if I do

class PageContext \< Radiant::Context  
end

I’m new to reopening classes; what am I doing wrong?

Jay

---

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [July 30, 2006, 1:45pm UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/2 "2006-07-30T13:45:32Z")

</div>

Jay L. wrote:

> I understand the intent, but I wonder if there’s a less intrusive way to  
> accomplish it, while still allowing outer tags to rescue their own  
> exceptions. What if that rescue were executed only on the outermost  
> tags? Would that break anything?

I’ve submitted a patch that accomplishes this - ticket #177.

> OT but related: I tried reopening PageContext in my own plugin to make  
> this modification

Solved: Rails loads models automagically through const\_missing the first  
time they’re referenced. Plugins load before models, so if you define  
the class in the plugin, it’s no longer missing, and the model doesn’t  
get loaded! If I wanted to reopen PageContext in a plugin, I’d need to  
require “page\_context” at the top so it gets loaded first.

Jay

---

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [July 31, 2006, 3:35pm UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/3 "2006-07-31T15:35:58Z")

</div>

John W. Long wrote:

> this can be applied to the core.  
> I’ve been thinking over how to unit test it - more so since I found two  
> bugs in it (one fixed in the second patch, one not yet fixed). The  
> problem, of course, is that disabling exceptions in “test” makes it  
> impossible to test the code path that would trap the exception!

I’m thinking the best way is to add a global like  
RERAISE\_EXCEPTIONS\_IN\_TEST, which the test itself would turn off and  
would otherwise default on. Sound ok?

As for code that makes use of it, here:

tag “outer” do |tag|  
contents = tag.expand  
html = “” + do\_something(contents) + “”  
end

tag “inner” do |tag|  
[‘height’, ‘font\_size’].each do |attr|  
unless tag.attr.include?(attr)  
raise TagError, “the #{name} tag must include a ‘#{attr}’  
attribute.”  
end  
end  
end

With Radiant 0.5, the error returned by “inner” gets trapped by the  
first render\_tag it sees, and so the output is “the inner tag  
must include a ‘height’ attribute”, which (in my case) isn’t the  
desired result; outer depends on inner, and I want everything or  
nothing.

With the patch, render\_tag doesn’t rescue the exception when rendering  
inner, so it goes up the stack. In this particular case, “outer”  
doesn’t catch it either, so the render\_tag for outer rescues it and  
displays the error message in lieu of the outer tag.

If, in fact, I wanted to render outer no matter what, then I’d make  
“outer” something like

tag “outer” do |tag|  
begin  
contents = tag.expand  
rescue TagError =\> e  
LOGGER.debug ("Inner error: #{e.message})  
ensure  
html = “” + do\_something(contents) + “”  
end  
end

Jay

---

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [July 31, 2006, 3:16pm UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/4 "2006-07-31T15:16:45Z")

</div>

Jay L. wrote:

> Jay L. wrote:
> 
> > I understand the intent, but I wonder if there’s a less intrusive way to  
> > accomplish it, while still allowing outer tags to rescue their own  
> > exceptions. What if that rescue were executed only on the outermost  
> > tags? Would that break anything?
> 
> I’ve submitted a patch that accomplishes this - ticket #177.

This sounds like a useful idea. Can you post some code which  
demonstrates why this would be useful? Also I’ll need unit tests before  
this can be applied to the core.

–  
John L.  
[http://wiseheartdesign.com](http://wiseheartdesign.com)

---

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [August 1, 2006, 4:04am UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/5 "2006-08-01T04:04:13Z")

</div>

Jay L. wrote:

> I imagine if I understood continuations better, I’d know how to code  
> this; the inner tag should raise an exception, and the outer tag should  
> note that, continue its processing, and then, at the end, reraise or  
> render. Sadly, I’m too new to Ruby, and non-procedural languages in  
> general, to know how to do that.

Yeah, so, never mind that. I was thinking waaay to hard. I changed the  
default behavior from “outer tag keeps getting rendered” to “outer tag  
doesn’t render when inner tag has an error”, and then wondered why I  
wasn’t seeing the outer tag.

I just have to keep the default behavior the way it is, and then change  
it only for tags that want it. That seems doable. I’ll stop using the  
list to talk to myself now.

Jay

---

<div class="post-metadata">

**Author:** ![jay-levitt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a88e57/32.png) [@jay-levitt](https://www.ruby-forum.com/u/jay-levitt)\
**Post date:** [August 1, 2006, 3:17am UTC](https://www.ruby-forum.com/t/proposal-exception-handling-in-container-classes/100552/6 "2006-08-01T03:17:17Z")

</div>

John W. Long wrote:

> this can be applied to the core.  
> Argh! This is harder than it seemed. In my version, when  
> PageContext::render\_tag reraises the exception, the parent tag rescues  
> it, of course - which means the parent tag never finishes what it’s  
> doing. So anything inside the parent tag following the exception is  
> lost. Oops.

I imagine if I understood continuations better, I’d know how to code  
this; the inner tag should raise an exception, and the outer tag should  
note that, continue its processing, and then, at the end, reraise or  
render. Sadly, I’m too new to Ruby, and non-procedural languages in  
general, to know how to do that.

If anyone else wants to take a crack at this, here’s how far I got… I’m  
about to go read a bunch of “continuations made easy” articles.

* * *

def render\_tag(name, attributes = {}, &block)  
super

rescue Exception =\> e  
nesting = current\_nesting  
@tag\_binding\_stack.pop

```
 if reraise_exception(nesting, name, e)
   p @page.behavior.parser
   raise e
 else
   render_error_message(e.message)
 end

```

end

…  
def reraise\_exception(nesting, name, e)  
tag\_pos = nesting.rindex(name)

```
   # Missing end tag
   return false if tag_pos.nil?

   # Let inner tags pass exceptions to outer tags.
   return true if tag_pos > 1

   # Let bugs report themselves to unit tests.
   return true if RAILS_ENV == "test" and not e.is_a?(TagError)

   false
 end
```
