The ravens are looking a bit sluggish. Tell Malcolm they need new batteries.
Monday, July 02
Aha Moment
What I needed all along was an autovivifying dict/object composite class with virtual leaf methods. You see, where I got stuck (apart from working out how to autovivify in Python, but there are now several recipes around the 'net for that) was on the current implementation of lazy methods. That was a big improvement over the original eager methods, but it still requires the closures to be bound when the subtree is attached, and it means that the parents of the lazy methods can't be accessed in object or nested dict notation, only via dotted keys. But if I make the leaf methods virtual, then (a) they don't need to be bound at all, making the trees smaller and the code faster, and (b) there is no space collision on the parent node, because it's now the leaf, and thus has identical semantics under all three access methods.
What I needed all along was an autovivifying dict/object composite class with virtual leaf methods. You see, where I got stuck (apart from working out how to autovivify in Python, but there are now several recipes around the 'net for that) was on the current implementation of lazy methods. That was a big improvement over the original eager methods, but it still requires the closures to be bound when the subtree is attached, and it means that the parents of the lazy methods can't be accessed in object or nested dict notation, only via dotted keys. But if I make the leaf methods virtual, then (a) they don't need to be bound at all, making the trees smaller and the code faster, and (b) there is no space collision on the parent node, because it's now the leaf, and thus has identical semantics under all three access methods.
What this means to you is that the next version of Minx will run twice as fast. What this means to me is that writing the code just became much less fiddly - the tags you see in your templates now map directly to code objects. (And in the next version, will automatically map to database fields as well.)
Update: Hmm. Still not perfect. The catch now is that that (a) there are inconsistencies between the dotted key accessor and the direct accessors, and (b) you have to munge virtual method calls when accessing them directly.
So, example:
[comment.text] in a Minx template returns the marked-up content of the comment, i.e. BBCode parsed, smilies interpolated, HTML sanitised and so on.
If you want the raw text data (to write a blog exporter, for example) you can use [comment.text.raw].
But in the database interface, and in the back-end code, comment.text needs to refer to the raw data.
That's what the new method does, but that means that it smart and context-sensitive rather than consistent. [comment.text] is not the same as comment.text. But that's okay on the Python side (or Ruby, but I'm not going to mention Ruby yet), because (a) only I see that stuff, and (b) it's exactly what I want for writing the core code.
Where this gets weird is in the Lua API, where tags.comment.text matches the internal (Python) value of comment.text rather than the template tag [comment.text]. So what I need to do there is tweak the data structure so that instead of returning the raw data when called from Lua, it returns a wrapped object with the default text (what you get from the template tag) as its string representation.
With that, (a) naive Lua templates will work: If I say content = content .. tags.comment.text* it will append the processed comment text to the HTML page just like [comment.text]; (b) methods will work, so tags.comment.text.raw will return the same value as [comment.text.raw]; and there will be near zero overhead in creating the tag arrays; the wrapper class will only do its work for fields that are referenced in the Lua script.
Two minor catches, still:
- If you need to treat the wrapped Python strings as Lua strings (tags.comment.text will be wrapped; tags.comment.text.raw won't), i.e. there's no automatic coercion taking place, you'll need to dereference the wrapper to make the automatic conversion happen; that will be something like tags.comment.text.string. If you're just spitting it out as part of the web page, though, no need to do that.
- For Python (and Ruby, but I'm not mentioning Ruby yet) core code, the leaf objects are native data types, so you can't do tags.comment.text.raw in Python the way you can in Lua. Well, you could do that from Ruby, which allows for insane degrees of monkeypatching, but I don't think I want to go there. But I can munge it to allow tags.comment.text_raw to do the same thing (the . notation forces an attribute lookup on text that I can't overload, but _ is just part of the attribute name and I can do whatever I like). And in non-core code (if you're writing trusted native templates in Python or R... Python) you can request the tags structure in magic mode, which will deliver it with the same semantics as in the template language and Lua.
I think that's good enough.
* Actually, real Lua template code would look more like:
for comment in post.comments
print(comment.text, "<br/>")
end
Posted by: Pixy Misa at
01:35 AM
| No Comments
| Add Comment
| Trackbacks (Suck)
Post contains 727 words, total size 6 kb.
50kb generated in CPU 0.0337, elapsed 0.2021 seconds.
49 queries taking 0.1787 seconds, 332 records returned.
Powered by Minx 1.1.6c-pink.
49 queries taking 0.1787 seconds, 332 records returned.
Powered by Minx 1.1.6c-pink.