Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:47:15 +08:00
commit d024d22cd1
30 changed files with 9249 additions and 0 deletions

285
skills/selmer/examples.clj Normal file
View File

@@ -0,0 +1,285 @@
#!/usr/bin/env clojure
;; Selmer Examples
;; NOTE: Selmer requires Clojure (JVM) and is NOT compatible with Babashka
;; Run with: clojure -M examples.clj
;; Or add deps.edn with selmer dependency
(comment
"To run these examples, create a deps.edn file:"
{:deps {selmer/selmer {:mvn/version "1.12.65"}}}
"Then run: clojure -M examples.clj")
(require '[selmer.parser :as parser])
(require '[selmer.filters :as filters])
(println "=== Selmer Templating Examples ===\n")
;; ============================================================================
;; Basic Rendering
;; ============================================================================
(println "1. Basic Variable Rendering")
(println (parser/render "Hello {{name}}!" {:name "World"}))
(println (parser/render "{{greeting}}, {{name}}!"
{:greeting "Hi" :name "Alice"}))
(println)
(println "2. Nested Data Access")
(println (parser/render "{{person.name}} is {{person.age}} years old"
{:person {:name "Bob" :age 30}}))
(println (parser/render "First item: {{items.0}}"
{:items ["apple" "banana" "cherry"]}))
(println)
;; ============================================================================
;; Filters
;; ============================================================================
(println "3. String Filters")
(println (parser/render "{{name|upper}}" {:name "alice"}))
(println (parser/render "{{name|lower}}" {:name "ALICE"}))
(println (parser/render "{{text|capitalize}}" {:text "hello world"}))
(println (parser/render "{{text|title}}" {:text "hello world"}))
(println)
(println "4. Filter Chaining")
(println (parser/render "{{text|upper|take:5}}" {:text "hello world"}))
(println (parser/render "{{items|join:\", \"|upper}}"
{:items ["a" "b" "c"]}))
(println)
(println "5. Collection Filters")
(println (parser/render "Count: {{items|count}}"
{:items [1 2 3 4 5]}))
(println (parser/render "First: {{items|first}}, Last: {{items|last}}"
{:items [10 20 30]}))
(println (parser/render "Joined: {{items|join:\", \"}}"
{:items ["red" "green" "blue"]}))
(println (parser/render "Reversed: {{items|reverse|join:\"-\"}}"
{:items [1 2 3]}))
(println)
(println "6. Utility Filters")
(println (parser/render "Value: {{val|default:\"N/A\"}}" {:val nil}))
(println (parser/render "Value: {{val|default:\"N/A\"}}" {:val "Present"}))
(println (parser/render "Length: {{text|length}}" {:text "hello"}))
(println)
;; ============================================================================
;; Control Flow
;; ============================================================================
(println "7. If/Else Tags")
(println (parser/render "{% if user %}Hello {{user}}!{% else %}Please log in{% endif %}"
{:user "Alice"}))
(println (parser/render "{% if user %}Hello {{user}}!{% else %}Please log in{% endif %}"
{}))
(println)
(println "8. If with Comparisons")
(println (parser/render "{% if count > 10 %}Many{% elif count > 0 %}Few{% else %}None{% endif %}"
{:count 15}))
(println (parser/render "{% if count > 10 %}Many{% elif count > 0 %}Few{% else %}None{% endif %}"
{:count 5}))
(println (parser/render "{% if count > 10 %}Many{% elif count > 0 %}Few{% else %}None{% endif %}"
{:count 0}))
(println)
(println "9. Ifequal/Ifunequal")
(println (parser/render "{% ifequal role \"admin\" %}Admin panel{% endifequal %}"
{:role "admin"}))
(println (parser/render "{% ifunequal status \"active\" %}Inactive{% endifunequal %}"
{:status "pending"}))
(println)
;; ============================================================================
;; Loops
;; ============================================================================
(println "10. For Loops")
(def for-template
"{% for item in items %}{{forloop.counter}}. {{item}}\n{% endfor %}")
(println (parser/render for-template {:items ["apple" "banana" "cherry"]}))
(println "11. For Loop Variables")
(def loop-vars-template
"{% for item in items %}{{item}}{% if not forloop.last %}, {% endif %}{% endfor %}")
(println (parser/render loop-vars-template {:items [1 2 3 4 5]}))
(println)
(println "12. For with Empty")
(def for-empty-template
"{% for item in items %}{{item}}\n{% empty %}No items found{% endfor %}")
(println (parser/render for-empty-template {:items []}))
(println (parser/render for-empty-template {:items ["present"]}))
(println)
(println "13. Destructuring in For Loops")
(def destructure-template
"{% for [k v] in pairs %}{{k}}: {{v}}\n{% endfor %}")
(println (parser/render destructure-template
{:pairs [["name" "Alice"]
["age" "30"]
["city" "NYC"]]}))
;; ============================================================================
;; Template Includes (Inline)
;; ============================================================================
(println "14. Template Composition with Render")
(def header-template "=== {{title}} ===")
(def content-template "{{header}}\n{{body}}")
(let [header (parser/render header-template {:title "Welcome"})
result (parser/render content-template
{:header header
:body "This is the content"})]
(println result))
(println)
;; ============================================================================
;; Custom Filters
;; ============================================================================
(println "15. Custom Filters")
(filters/add-filter! :shout
(fn [s] (str (clojure.string/upper-case s) "!!!")))
(println (parser/render "{{msg|shout}}" {:msg "hello"}))
(filters/add-filter! :repeat
(fn [s n] (apply str (repeat (Integer/parseInt n) s))))
(println (parser/render "{{x|repeat:3}}" {:x "ha"}))
(println)
;; ============================================================================
;; Custom Tags
;; ============================================================================
(println "16. Custom Tags")
(parser/add-tag! :uppercase
(fn [args context-map]
(clojure.string/upper-case (first args))))
(println (parser/render "{% uppercase \"hello world\" %}" {}))
(println)
;; ============================================================================
;; Escaping
;; ============================================================================
(println "17. HTML Escaping (Default)")
(println (parser/render "{{html}}" {:html "<b>Bold</b>"}))
(println "\n18. Safe Filter (No Escaping)")
(println (parser/render "{{html|safe}}" {:html "<b>Bold</b>"}))
(println)
;; ============================================================================
;; Variable Introspection
;; ============================================================================
(println "19. Known Variables")
(println "Variables in template '{{x}} {{y.z}}':")
(println (parser/known-variables "{{x}} {{y.z}}"))
(println)
;; ============================================================================
;; Practical Examples
;; ============================================================================
(println "20. Email Template Example")
(def email-template
"Dear {{name}},
Thank you for registering! Your account details:
Username: {{username}}
Email: {{email}}
Registered: {% now \"yyyy-MM-dd HH:mm\" %}
{% if premium %}
Premium features are now available!
{% else %}
Upgrade to premium for additional features.
{% endif %}
Best regards,
The Team")
(println (parser/render email-template
{:name "Alice Johnson"
:username "alice"
:email "alice@example.com"
:premium true}))
(println)
(println "21. HTML List Example")
(def list-template
"<ul>
{% for item in items %}
<li class=\"{% cycle 'odd' 'even' %}\">
{{item.name}} - ${{item.price|double-format:\"%.2f\"}}
</li>
{% endfor %}
</ul>")
(println (parser/render list-template
{:items [{:name "Widget" :price 19.99}
{:name "Gadget" :price 29.50}
{:name "Doohickey" :price 9.99}]}))
(println)
(println "22. Conditional Navigation")
(def nav-template
"<nav>
{% if user %}
Welcome, {{user.name}}!
{% ifequal user.role \"admin\" %}
<a href=\"/admin\">Admin Panel</a>
{% endifequal %}
<a href=\"/logout\">Logout</a>
{% else %}
<a href=\"/login\">Login</a>
<a href=\"/register\">Register</a>
{% endif %}
</nav>")
(println "Admin user:")
(println (parser/render nav-template
{:user {:name "Admin" :role "admin"}}))
(println "\nRegular user:")
(println (parser/render nav-template
{:user {:name "Bob" :role "user"}}))
(println "\nNot logged in:")
(println (parser/render nav-template {}))
(println)
(println "23. Data Table Example")
(def table-template
"<table>
<thead>
<tr><th>#</th><th>Name</th><th>Status</th></tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{user.name|title}}</td>
<td>{% if user.active %}Active{% else %}Inactive{% endif %}</td>
</tr>
{% empty %}
<tr><td colspan=\"3\">No users found</td></tr>
{% endfor %}
</tbody>
</table>")
(println (parser/render table-template
{:users [{:name "alice" :active true}
{:name "bob" :active false}
{:name "charlie" :active true}]}))
(println "\n=== Examples Complete ===")