-
-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Rust verbatim or use Jinja-esque syntax #95
Comments
First off, a meta-comment: your bug reports so far often employ a tone that rubs me the wrong way, as in "extremely useful", "extremely useful", "gigantic blocker" (all in the initial post in #85), and in this case "extremely difficult", "huge source of confusion and frustration". I understand that you're frustrated, but implicitly blaming that on me or the tool I created seems neither fair nor productive. Maybe you should write the bug report after a bit of a cooling down? Second, if you want to suggest solutions, you're going to have to work a bit harder to understand the constraints in which Askama is operating, which make some of the things you suggest just impossible. With a static type system and very limited type information available to it, the code generator can only do so much, so I carefully try to balance Askama between being expressive and not take on the complexity of trying to reproduce the full complexity of Rust in templates. That's not what this templating tool is designed for, anyway. Third, solutions that work today that you could employ today that seem fairly usable to me: if you have something like an {% match form %}
{% when Some with (form) %}
value={{ form.get("name").unwrap() }}
{% else %}
{% endmatch %} This seems like a reasonably concise solution, though definitely not as concise as in Jinja (but I don't think that level of conciseness is technically possible in a statically typed language like Rust). For All that said, I think there are a few things that would be straightforward to improve (and thanks for the guide to all the things that you tried, which informed this list):
|
Thanks for your reply. In response to your meta comment, I apologise if these things come off in a negative way. I'm not sure why calling things useful or blockers for use rub you the wrong way, but I have no ill intent, and I'm definitely not trying to blame you or askama for anything. None of the issues I've written have been written with anger. The "extremely difficult" you mention is actually sympathetic, since I understand that many of these things may not be possible or may be... extremely difficult to do. The disconnect between expectations and reality when using askama, however, is a source of frustration and confusion for me, and I think that any software author should want to know what is causing their users frustration. The point is not that you should make askama exactly equivalent to Jinja. That would be nice, but I think that it's not feasible when dealing with Rust and its type system so directly. The point I meant to make, whether or not I did so successfully, is that it's very confusing to use askama. I do not see any documentation for what is and isn't expected in code blocks, and sometimes the necessary workarounds seem overly complex. The actual necessary code to do what the form example did without unwrapping, since each member is optional, would be as follows. {% match form %}
{% when Some with (form) %}
{% match form.get("name") %}
{% when Some with (name) %}
value="{{ name }}"
{% else %}
{% endmatch %}
{% else %}
{% endmatch %} I don't know the nitty-gritty details of how askama works, but I have a general idea. Perhaps there is some way to do the following, where {% try %}
{{ form?.name? }}
{% endtry %} fn generated_name() -> Option<String> {
form?.name?
}
if let Some(generated_name) = generated_name() {
// do writing
} This would need to be adapted for I only suggested the "solutions" of using Rust verbatim or using a Jinja-esque system because it's currently unclear which you are expected to use when templating with askama. Don't get me wrong. I really enjoy askama and its idea, and I'm really excited to continue using it. |
To me, the way you use "blocker" or "useful" in combination with these superlatives exaggerates the importance of your particular use case, when, according to download statistics and lack of bug reports so far, quite a few people have been able to use Askama just fine without these features. As for |
The problem with using I've played around with the expression form, but it can only be supported in a subset of cases (for example, I don't think |
Being able to use When I wrote about the potential {% try Option %}
{{ a?.b }}
{% endtry %} Where At least in this case, it makes the nested To use your example, what I was thinking was the following. {% try Option %}
A
{{ form?.get("name")? }}
B
{% endtry %} // let's just ignore whitespace in this example
// struct Context { form: Option<HashMap<String, String>> }
// try block uses Option, so we use Option and Some
// if it had specified Result, though, things get trickier when specifying the return result
let try_block = || -> Option<()> {
write("A");
let value = self.form?.get("name")?;
write("{}", value);
write("B");
Some(())
};
try_block(); Alternatively, each expression could be wrapped in a closure and then looked at via The closure would probably need to be given My thinking is that you were looking at doing a
What specifically poses a problem with naming the unwrapped value? In the generated code, I see |
It appears that most of what is in an
if
block gets translated straight into the generated Rust code, but askama fails to parse much Rust syntax. In my opinion, askama should either accept Rust code verbatim in blocks or warp it to work like Jinja.Currently, I can't figure out a better way to do this. Option support in general is difficult, even with
match
, and[
and]
can't be used forIndex
. Similarly, comparison can't be done a la== Some("string literal")
, but== "string literal".into()
works.To make things worse, I can't use
.map(...)
because pipes (|
) cause the template to fail to parse.If handled like Jinja, though, it turns into this.
Another point where I was confused about how to do something in askama due to not knowing what is and isn't allowed in terms of syntax:
No truncate filter, so what about taking a substring?
{{ &some_string[..7] }}
No, that doesn't parse.
That also doesn't parse. Presumably using
..
and..=
notation will not parse, soRange
s cannot be created that way. I assume that since you can't doSome(x)
, you can't create a Range struct, either.Basically, letting the user use methods on variables is nice, but it's unclear how exactly they can be used. Rust types being used directly in the template is really useful for some things, but not having Jinja-esque patterns to deal with them makes code unreadable, confusing, and unwieldy (see the first example above).
I'm never sure if I'm supposed to use code that looks like Jinja or use code that looks like Rust.
I realise that it's extremely difficult to have some of these things work, but I'm just pointing out a huge source of confusion and frustration for me when I'm trying to use askama. I still have no idea how I'm supposed to substring besides making my own trait and implementing it on
str
.The text was updated successfully, but these errors were encountered: