How can I provide data to a tempo template? - templates

I'm trying to combine auto-insert and tempo templates to fill new files with the right content automatically.
My goal is to make auto-insert call a tempo template, providing it with some data (a class' name for example).
Something like this :
(eval-after-load 'autoinsert
'(define-auto-insert
(cons "\\.\\([Hh]\\|hh\\|hpp\\)\\'" "My C / C++ header")
(lambda()
(tempo-template-c++-class))))
I'd like to provide the C++ class template the buffer's file name so it can expand nicely. Ideally, creating a file named 'foo.h' would expand the template with 'foo' as data, creating the 'foo' class.
I tried to play around with the "save list" as explained in the Tempo Manual, but no luck so far.
Thanks for the help.
En passant, is there a better way than
(file-name-sans-extension (file-name-nondirectory buffer-file-name))
to get a class name from the file's?

C-h f tempo-define-template RET gives a list of template elements and their meaning:
A string: It is sent to the hooks in `tempo-insert-string-functions',
and the result is inserted.
...
Anything else: It is evaluated and the result is treated as an
element to be inserted. One additional tag is useful for these
cases. If an expression returns a list '(l foo bar), the elements
after `l' will be inserted according to the usual rules. This makes
it possible to return several elements from one expression.
So just put (file-name-sans-extension (file-name-nondirectory buffer-file-name)) in the template where you want the class name (and yes, I think this is indeed the best way to get a class name out of a file name).

Related

Check if a list is defined and avoid the "UNDEFINED" error

In the original TI-BASIC (for TI-83/84+) is there a way to check if a list has been defined?
Currently calling dim(⌊LIST) will return an error if the list is not defined.
Is there a way to handle that error gracefully?
Possible Workaround:
The only hacky way I can think of doing so is to redefine the list with more items than you're expecting such as 99→dim(⌊LIST) and check if the first few values are not zero. But that seems wasteful and slow.
Any suggestions?
Unfortunately there doesn't seem to be a clean, simple function for checking if a list already exists, but thanks to harold who posted this as a comment, there is a workaround:
The SetUpEditor command.
This is typically used for specifying which lists are displayed in the list editor, but the command has the side-effect of creating a zero-length list if it does not exist yet.
So here's some sample code, with comments:
"Create two empty lists if they do not exist yet
SetUpEditor FOO,BAR
"Check the size of FOO
dim(∟FOO)→X
"Clean up by returning the list editor back to
"its default state (∟1-∟6)
SetUpEditor
If you have control during the lists's creation, then another workaround would be to use another list with only one element (or a list of another fixed size, or a letter variable) as a flag that indicates this main list exists.
Something like this, for lists LMAIN and LFLAG:
1->dim(LFLAG
If 5784923472≠LFLAG(1
Then
"assume LMAIN does not exist because flag hasn't been set
"insert optional other code here
0->dim(LMAIN
5784923472->LFLAG(1
End

Nested namespaced keys in HugSQL Query

I have a nested map with namespaced keys like this:
{
:model.person/primary {:model.person/name "John Smith"}
}
Instead of simpliying this into a flat map I'd like to pass it straight through to a HugSQL function. The docs say HugSQL supports a deep parameter get and namespaced keys but I'm not sure how to combine them.
(hugsql/def-sqlvec-fns-from-string
"-- :name get_person :? :1
-- :doc Get a person
SELECT * FROM person WHERE name = :value:model.person/primary:model.person/name")
Now if I execute the function it generates with my original map I get this:
(get_person-sqlvec {:model.person/primary {:model.person/name "John Smith"}})
Execution error (ExceptionInfo) at hugsql.core/validate-parameters! (core.clj:83).
Parameter Mismatch: :model.person/name parameter data not found.
I would imagine the variable naming convention in the SQL is the source of the problem:
:value:model.person/primary:model.person/name
But I'm not sure what the correct value should be.
First off, the deep parameter get uses . between keys, not :, so that is part of your problem.
However, right now HugSQL only supports one level of qualified keywords -- because there is an inherent ambiguity between . for separating deep parameter get keys and the . that can be part of (qualified) keywords.
You could have where name = :value:model.person/primary.name and then a hash map like {:model.person/primary {:name "John Smith"}}
Or you could have where name = :value:model.person/name and pass {:model.person/name "John Smith"}
HugSQL will need a different syntax to support nested qualified keys (to resolve the . ambiguity). I mentioned Selmer's approach to Curtis Summers, HugSQL's maintainer: using .. to indicate the dot that is part of a keyword, so you could have:
where name = :value:model..person/primary.model..person/name
(that's how Selmer indicates nested qualified keys) but there are backward compatibility issues to consider as well as whether that's a good syntax in the first place (I'm a heavy user of Selmer and I don't like that, but I understand why they did it).

Python pptx: how to find and delete the empty or unpopulated placeholders

I have created a presentation using python-pptx. However, some slides have the empty placeholders with default text click to add title/text that looks like the one below.
So basically, there are non-empty placeholder with text Some texts here and other two are empty placeholders. How can I find and delete them? Also, there are same empty placeholders for images. How can I find them as well. Thanks
Finding them is fairly easy; something roughly like this should do the trick:
for placeholder in slide.shapes.placeholders:
if placeholder.has_text_frame and placeholder.text_frame.text == "":
print("found one %s" % placeholder)
Deleting it is harder, because there is no direct API support for deleting shapes. However, in this simple case of text placeholders, this should work:
sp = placeholder._sp
sp.getparent().remove(sp)
The ._sp attribute is the lxml etree._Element object representing the actual shape XML element (a placeholder <p:sp> element in this case). .getparent() and .remove() are methods on etree._Element and calling these manipulates the underlying XML directly. This can be dangerous, like if you tried this with a chart shape you'd probably get a repair error when you tried to load the presentation, but in this case it's safe enough.

SQLalchemy: iterate through raw SQL query in template

Have a code in function, which renders ResultProxy (as I understand), to template, like this:
query = db_session.execute(serious_business_query) #raw sql
return render_template('result.html', query=query)
I want to iterate through it in my template, but see nothing. How can I iterate through ResultProxy object? Or what should I pass to template to simply iterate through it?
Links to docs are OK, cant find what I need.
You might want to try this suggestion https://stackoverflow.com/a/17987782/1307985
and when you fill in a list from the cursor then to pass it to the template.
I am guessing, but probably the jinja2 template does not know how to itterate over cursor or query like object so it have to be converted to a list object.

How to force Acceleo to iterate over a collection in the same order on every template execution?

I'm using an EMF model based on Modisco KDM metamodel. At some point of my Acceleo template I need to iterate over a collection, e.g.:
[for (e: AbstractCodeElement | action.codeElement) separator(', ')][e.generateCode() /]
The action.codeElement is a collection and modisco's kdm.ecore metamodel defines it as non-ordered.
Every time I run my generator, the output is generated on a different order. Cleary the serialized model xmi enforces a specific order, and every model editor (emf default editor, modisco editor) I open the model shows the same order always (matching the order the elements were serialized to the xmi file).
Since I cannot change the kdm.ecore metamodel to make the set ordered, would there be a workaround to get Acceleo to always iterate on the same order?
Thanks in advance
I'm afraid you can't.
Try and cast it to a sequence:
action.codeElement->asSequence()
but I don't think anything guarantees that the sequence you get will always be sorted in the same order.
If the metamodel is made that way, there should be a reason, so either you can contact the metamodel authors to check this reason, or you should sort the result of action.codeElement with some stable criterion:
action.codeElement->sortedBy( some OCL expression)
I don't know of a clean way. I solved the problem by altering the name attribute of a child element so that it was sortable alphabetically in the way I wanted.
I wanted Slots in the same order every time, so I changed the name of each of their "value" child.
The names looked like: "01_id", "02_username", "03_city", ... "10_instructions", "11_contact". I didn't have to change what the "value" elements held, just their name, which I wasn't using for anything anyways. Hope this helps.
[for (s : Slot | instanceSpecification.slot->select(definingFeature.name = 'column')->sortedBy(value->asSequence()->first().name)]
... do work here ...
[/for]