Repository: djc/askama (rust)

Issue:
0.12.1 only allow lower-case variable name in template
I don't know if I asked a stupid question, but I spend one day to find it ! my rust version is 1.74.0, I run it on my win11 and WSL ubuntu 22.04, see the same error below
```rust
use askama::Template;

#[derive(Template)] 
#[template(path = "hello.html")]
struct HelloTemplate<'a> {
    nAme: &'a str, 
}
fn main() {
    let hello = HelloTemplate { nAme: "world" }; 
    println!("{}", hello.render().unwrap());
}
```
```html
Hello, {{ nAme }}!
```
```toml
[package]
name = "hello"
version = "0.1.0"
edition = "2021"

[dependencies]
askama="0.12.1"
```
[xxx.DESKTOP-ABCDE12] ⮞ cargo run -p hello
   Compiling hello v0.1.0 (C:\xx\xx\xx\hello)
error[E0425]: cannot find value `nAme` in this scope
 --> hello\src\main.rs:3:10
  |
3 | #[derive(Template)]
  |          ^^^^^^^^
  |
  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you might have meant to use the available field
  |
3 | #[derive(self.Template)]
  |          +++++

For more information about this error, try `rustc --explain E0425`.
error: could not compile `hello` (bin "hello") due to previous error


Pull request description:
Fix support for mixed case variables
Fixes #924. Looks like this might have regressed in #840. I think checking only the first letter is a better heuristic than checking if any letters are uppercase.

Patch:
diff --git a/askama_parser/src/lib.rs b/askama_parser/src/lib.rs
index e6f133c..1cb0e87 100644
--- a/askama_parser/src/lib.rs
+++ b/askama_parser/src/lib.rs
@@ -349,9 +349,9 @@ fn path_or_identifier(i: &str) -> ParseResult<'_, PathOrIdentifier<'_>> {
     let rest = rest.as_deref().unwrap_or_default();
 
     // The returned identifier can be assumed to be path if:
-    // - Contains both a lowercase and uppercase character, i.e. a type name like `None`
-    // - Doesn't contain any lowercase characters, i.e. it's a constant
-    // In short, if it contains any uppercase characters it's a path.
+    // - it is an absolute path (starts with `::`), or
+    // - it has multiple components (at least one `::`), or
+    // - the first letter is uppercase
     match (root, start, rest) {
         (Some(_), start, tail) => {
             let mut path = Vec::with_capacity(2 + tail.len());
@@ -360,7 +360,7 @@ fn path_or_identifier(i: &str) -> ParseResult<'_, PathOrIdentifier<'_>> {
             path.extend(rest);
             Ok((i, PathOrIdentifier::Path(path)))
         }
-        (None, name, []) if !name.contains(char::is_uppercase) => {
+        (None, name, []) if name.chars().next().map_or(true, |c| c.is_lowercase()) => {
             Ok((i, PathOrIdentifier::Identifier(name)))
         }
         (None, start, tail) => {


Test patch:
diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs
index f0f0a26..ba806e2 100644
--- a/testing/tests/simple.rs
+++ b/testing/tests/simple.rs
@@ -484,3 +484,23 @@ fn test_num_literals() {
         "[90, -90, 90, 2, 56, 240, 10.5, 10.5, 100000000000, 105000000000]",
     );
 }
+
+#[allow(non_snake_case)]
+#[derive(askama::Template)]
+#[template(source = "{{ xY }}", ext = "txt")]
+struct MixedCase {
+    xY: &'static str,
+}
+
+/// Test that we can use mixed case in variable names
+///
+/// We use some heuristics to distinguish paths (`std::str::String`) from
+/// variable names (`foo`). Previously, this test would fail because any
+/// name containing uppercase characters would be considered a path.
+///
+/// https://github.com/djc/askama/issues/924
+#[test]
+fn test_mixed_case() {
+    let template = MixedCase { xY: "foo" };
+    assert_eq!(template.render().unwrap(), "foo");
+}