[Twisted-web] Re: Nevow and template like files
Nuutti Kotivuori
naked at iki.fi
Thu Sep 7 05:18:42 CDT 2006
Valentino Volonghi aka Dialtone wrote:
> On Wed, 06 Sep 2006 11:03:28 +0300, Nuutti Kotivuori <naked at iki.fi> wrote:
>> Valentino Volonghi aka Dialtone wrote:
>> Okay, consider the content page shown above. Now let's assume that
>> most pages don't need the "head" pattern at all. I wouldn't want to
>> write the empty pattern on all pages just because it has to be
>> there, instead I would just want to say that put T.invisible()
>> there if the pattern doesn't exist. (With just the "head" pattern
>> it wouldn't be so much of a problem, but I might later on have to
>> add some more, and I don't want to change every content page just
>> because one content page requires something special.)
>
>> So this is what I'd like the default for. But ofcourse, if I load
>> the entire page first, and then just use the inevow.IQ machinery,
>> making the default patterns is easy.
>
> Another solution is to write your own loader by implementing
> inevow.IDocFactory and the using loaders.xmlfile internally so that
> you can catch exceptions and do what you want with the
> behavior. This also sounds reasonable a reasonably easy.
Yup. This I actually did already. It is used below.
>>> loaded = loaders.xmlfile('file') some_pattern =
>>> inevow.IQ(loaded).onePattern('whatever')
>>
>> That seems to work at first - but if there are any macros or render
>> methods inside the file I load, then I get Could not adapt error to
>> IMacroFactory.
>
> Uhmmm... Indeed the problem of the macro factory is not of secondary
> importance. Basically it doesn't make sense to call load() without a
> MacroFactory. This can be solved by building your own WovenContext
> before passing it to the loader.
I'm still working on this. This would be for the snippet code.
>>> Don't pass the context, what's the problem here?
>>
>> Macros and render methods. In the case of the snippet pages, I
>> would like them to be interpreted in the context of the Fragment
>> class that is loading the entire snippet page.
>
> That is done by default if you pass the context you are given by any
> of the methods in the Fragment.
But I need to call externally into the Fragment, so it doesn't go
through any of the normal entrypoints - so I guess I will have to
build the context myself.
>> I understand that the macro is not reloaded - but each macro will
>> load the page once. Which would be a problem on a page with
>> hundreds of snippets if every snippet would cause the page to be
>> loaded once.
>
> It's still a one time cost.
Yup.
> I'd rewrite the example in the following way:
>
> class TestPage(rend.Page):
> docFactory = loaders.xmlfile('testpage.xhtml')
> patternGenerator = None
>
> def macro_title(self, ctx):
> return inevow.IQ(self.patternGenerator).onePattern('title')
>
> def macro_head(self, ctx):
> return inevow.IQ(self.patternGenerator).onePattern('head')
>
> def macro_content(self, ctx):
> return inevow.IQ(self.patternGenerator).onePattern('content')
>
> class DataPage(TestPage):
> patternGenerator = loaders.xmlfile('datapage.xhtml')
>
> def macro_test(self, ctx):
> return 'Test successful.'
> I think the solution above should work without any problems, except
> I'm not sure that macro_test could actually work at all in nevow
> currently, but it may work.
The macro_test thing does not work in your example, but did work in my
original example.
> In case you want to avoid to call loaders.xmlfile('datapage.html')
> each time you might try a simple metaclass solution that grabs
> patternGenerator attribute before building the class and changes it
> to be an instance of loaders.xmlfile.
Not a problem, actually better that way I think.
Okay, I have the first part of my problem now solved, without the
snippet part. This is my solution:
,----[ testsite.py ]
| _no_default = object()
|
| class patternLoader(loaders.xmlfile):
| implements(inevow.IDocFactory)
|
| def __init__(self, original, pattern, default=_no_default):
| self.original = original
| self.pattern = pattern
| self.default = default
|
| def load(self, *args, **kw):
| doc = self.original.load(*args, **kw)
| if self.default is _no_default:
| return inevow.IQ(doc).onePattern(self.pattern)
| else:
| try:
| return inevow.IQ(doc).onePattern(self.pattern)
| except stan.NodeNotFound:
| return self.default
|
| class TestPage(rend.Page):
| docFactory = loaders.xmlfile('testpage.xhtml')
| datapageFactory = None
|
| def macro_title(self, ctx):
| return patternLoader(self.datapageFactory, 'title')
|
| def macro_head(self, ctx):
| return patternLoader(self.datapageFactory, 'head', T.invisible())
|
| def macro_content(self, ctx):
| return patternLoader(self.datapageFactory, 'content')
|
| class DataPage(TestPage):
| datapageFactory = loaders.xmlfile('datapage.xhtml')
|
| def macro_test(self, ctx):
| return 'Test successful.'
`----
It even does the optional part nicely.
Does this look reasonable? I'm diving in the snippet part next.
-- Naked
More information about the Twisted-web
mailing list