GithubHelp home page GithubHelp logo

mmontone / djula Goto Github PK

View Code? Open in Web Editor NEW

This project forked from nallen05/djula

149.0 9.0 21.0 4.15 MB

Common Lisp port of the Django templating language

Home Page: http://mmontone.github.io/djula/djula

License: MIT License

Common Lisp 100.00%
template-engine html-template lisp common-lisp

djula's Introduction

Djula

Build Status Quicklisp MIT License

Djula is a port of Python's Django template engine to Common Lisp.

Nutshell

Here a small example of a template::

    {% extends "base.html" %}
    {% block title %}Memberlist{% endblock %}
    {% block content %}
      <ul>
      {% for user in users %}
        <li><a href="{{ user.url }}">{{ user.username }}</a></li>
      {% endfor %}
      </ul>
    {% endblock %}

Philosophy

Application logic is for the controller but don't try to make the life for the template designer too hard by giving him too few functionality.

For more information visit the documentation page.

djula's People

Contributors

aarvid avatar chaitanyagupta avatar cxxxr avatar duikboot avatar eebabe avatar eudoxia0 avatar fjl avatar fukamachi avatar hectorhon avatar hraban avatar jeroenpeters1986 avatar knobo avatar mackram avatar mmontone avatar pocket7878 avatar puercopop avatar vindarel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

djula's Issues

Template Compilation Error

`
Template Compilation Error

Unhandled memory fault at #x0..
In #<COMPILED-TEMPLATE /var/username/.roswell/lisp/quicklisp/dists/quicklisp/software/djula-20170227-git/templates/error-template.djhtml {20629C3B}>.
Date/time: 2017-08-08-08:00An unhandled error condition has been signalled:
Unhandled memory fault at #x0.

Backtrace for: #
0: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE-TO-STREAM #)
1: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE # :OUTPUT NIL :IF-EXISTS :APPEND :VERBOSE NIL)
2: #
`

Error is thrown when a webserver (cavemanbased, just like in #32, related?) calls one of several templates that loops and plots some javascript. The template doesn't have any {%include%} or {%if%}, but some {%for%} loops.

I have severe problems to reproduce the error, but once it shows up, calling that template will produce the same error until the whole process is killed.

The error have been present for several months, but since I have had such problems pinpointing it have felt hesitant to report it until now.

Is it possible to compile/render a template placed anywhere on the disk?

I am working on a small convert-like utility that, given a djula template (specified as command line option), would:

  • Read some text from the standard input
  • Transform it
  • Call RENDER-TEMPLATE* to generate the converted output

The problem that I am currently facing is, how to compile/render the template without having to call ADD-TEMPLATE-DIRECTORY first.

Is it actually possible to do so? Any hint of where should I look to get this implemented?

Thanks in advance.

Disable live template updates

I'm writing this app that's deployed as an executable, and so it would be pretty useful to have a way to tell Djula to not try and find the file for a Djula template once it's been compiled for the first time.

Any chance to add a notation to call functions in templates?

Djula allows to access slots of standard-objects, however, apparently it's not possible to call functions/methods inside templates.

For example:

(defclass person ()
  ((first-name :initarg :first-name
               :accessor person-first-name)
   (last-name :initarg :last-name
              :accessor person-last-name)))

(defgeneric person-full-name (person)
  (:method ((person person))
    (format nil "~A ~A"
            (person-first-name person)
            (person-last-name person))))

In this case, first-name and last-name can be read by obj.first-name and obj.last-name, but there's no way to do it for person-full-name.

Though it can be implemented as a filter, it's not straightforward.

Any ideas?

Adding default template arguments

Is there some mechanism for adding a key/value pair to Djula so I don't have to pass it every time I call render-template*? I'm currently writing a wiki where every view has to explicitly pass an argument with the wiki's name, which is rather cumbersome.

Variable named "format"

I think I'm hitting an interesting corner case with the naming of an object slot. I'm building a site with caveman2, which uses djula for formatting. I pass a list of radio stations in and iterate over them in my template... but one of the slots I'm trying to print is named "format":

    {% for station in stations %}
    <li> <a href="/station/{{ station.callsign }}">{{ station.callsign }} {{ station.city }} {{ station.format }}</a>
    {% endfor %}

When I visit the page, I see this:

KDSK Albuquerque There was an error while accessing the attribute :FORMAT of the object #: invalid number of arguments: 1

Any other slot (power, latitude, longitude, etc.) that's defined on my object can be output just fine

I fear that the name "format" is colliding with the filter named "format", and would appreciate any suggestions ("rename the slot" isn't great but it is an option)

Accessing struct values inside the template

Is it possible to reference struct accessors from the template?

I am moving from treating my lists as

(ID 5 NAME "fake")

using the template like the examples {{ person.id }} {{ person.name }}

to person structures

#S(PERSION :ID 5 :NAME "fake")

but I cannot access the values when they are structures instead of key value pair lists.

I was just checking to see if this is possible before trying a different options.

Thanks for any clarifications.

Review filters implementation

Filters don't work with multiple arguments?

Either allow filters to take arguments, or prepare all of them to work with "with".

Looks like neither is the case at the moment.

Implement, document and test.

Include using variables

The manual (http://mmontone.github.io/djula/doc/build/html/tags.html#include) says: "The template name can either be a variable or a hard-coded (quoted) string, in either single or double quotes.".
Using the template

{% include form %}

I get:

Date/time: 2015-02-25-15:25An unhandled error condition has been signalled:
{# Error: There was an error compiling the token (TAG INCLUDE FORM) : The value
:FORM
is not of type
STRING. #}

Backtrace for: #
0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))
1: (SB-IMPL::CALL-WITH-SANE-IO-SYNTAX #)
2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #)
3: (PRINT-BACKTRACE :STREAM # :START 0 :FROM :DEBUGGER-FRAME :COUNT 4611686018427387903 :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL)
4: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE-TO-STREAM #)
5: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE # :OUTPUT NIL :IF-EXISTS :APPEND :VERBOSE NIL)
6: (DJULA:RENDER-TEMPLATE* # NIL :FORM #P"forms/f1.dtl")
...

If i change it to:

{% include {{ form }} %}

I get:

Date/time: 2015-02-25-15:28An unhandled error condition has been signalled:
{# Error: There was an error compiling the token (TAG INCLUDE {{ FORM }}) : error while parsing arguments to DESTRUCTURING-BIND:
invalid number of elements in
(:{{
:FORM
:}})
to satisfy lambda list
(DJULA::PATH):
exactly 1 expected, but 3 found #}

Backtrace for: #
0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))
1: (SB-IMPL::CALL-WITH-SANE-IO-SYNTAX #)
2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #)
3: (PRINT-BACKTRACE :STREAM # :START 0 :FROM :DEBUGGER-FRAME :COUNT 4611686018427387903 :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL)
4: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE-TO-STREAM #)
5: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE # :OUTPUT NIL :IF-EXISTS :APPEND :VERBOSE NIL)
6: (DJULA:RENDER-TEMPLATE* # NIL :FORM #P"forms/f1.dtl")

Seems like include is expecting a string only (not a variable).
Is there another way to include a template using variables?

Using ifequal (or similar tag) with a filtered value

Hello,

Case is simple, I have a list of list (returned by a SQL request using postmodern) who looks like this

(let ((customers (send-sql "select id, name from customers where account = $1 order by name" account))

It returns something such as

((1,"toto")(2,"titi")(3,"tutu"))

I can use this list inside a select to select a customer 👍

          <select class="form-control" id="accounts" name="account">
	        {% for line in customers %}
	        <option value="{{ line|first }}">{{ line|slice:1|first }}</option>
	        {% endfor %}
          </select>

I would like to pre-select the current selected entry with a code who should look like

{% ifequal line|first customer %}
selected
{% endifequal %}

Maybe I missed something in the doc, but would it not be possible to get a tag to return an entry from the list (such as slice in the filters).

How to access elements of a plist

Sorry if this is obvious, but I've read the docs and although there is a reference to accessing elements of an alist I don't see anything for plists (or lists in general) other than looping over the elements. I want to access arbitrary key value pairs by key.

Parsing a list of hash table

If you would:

(render #P"foods.html"
    (list :foods '((:id 10 :nombre "Pizza" :origin "Italy")
                   (:id 32 :nombre "Sushi" :origin "Japan")
                   (:id 92 :nombre "Taco" :origin "Mexico"))

How would you get the values of every hash table in the list?

{% for food in foods %}
	{% for (key . value) in food %}
		<p>{{ value }}</p>
	{% endfor %}
{% endfor %}

does not work

Can't render a string variable

(defroute "/" ()
(let ((token (cdr (split-sequence:split-sequence #| (drakma:http-request url)))))
(render #P"index.html" '(:token token))))

I need to be able to render a string represented by a variable. Using {{ token }} just renders TOKEN instead of rendering the actual value of the variable 'token.'

How do I pass a string variable to the template?

using length filter as boolean for if conditionals

Hello I am trying to use the length filter to see if my list is a specific size.

{% if list | length >= 2 %} does not work
{% if list | length_is:"2" %} does not work

creating my own filter to do the logic I want does not work.

Is there something I am missing? I get the following errors:

{% if boards | length > 4 %}

{% endif %}

An unhandled error condition has been signalled:
there was an error parsing the tag if boards | length_is:"4" 
{% if boards | length > 4 %}
{% endif %}

An unhandled error condition has been signalled:
there was an error parsing the tag if boards | length > 4 
{{ boards | length_is:"3" }}

An unhandled error condition has been signalled:
{# Error: There was an error rendering the token (VARIABLE (BOARDS) (LENGTH_IS 3)) : Translation backend has not been setup #}
{{ boards | length }}

3

How can I make a comparison boolean statement that works with if conditionals?

If I set the boards length to a variable i pass into the template the comparisons works fine, its only when I want to compare the length of a list inside the template I have the issues.

Appreciate any help.

Consider moving docs away from Sphinx

The docs build gets broken from time to time, and I'm getting tired of it.

I'm considering moving it to something else, more stable. I like TexInfo and cl-docweaver.

'loop' variable in 'for' tag

Although Jinja2 has a special variable called loop (http://jinja.pocoo.org/docs/dev/templates/#for), Djula doesn't seem to have it.

For example, this is an HTML template which shows categories with a comma between each element.

  <dl>
    <dt>Categories</dt>
    <dd>
      {% for category in categories %}
      <a href="/search?q={{ category }}">{{ category }}</a>{% if not loop.last %}, {% endif %}
      {% endfor %}
    </dd>
  </dl>

As loop.last is always false, a comma is shown in the last of the line.

It'd be great if this feature is also available in Djula. Or, any other ideas to do it?

Proposal to iterate a fixed number of times with `for` (à la dotimes)

Hi,

I'd like to iterate a fixed number of times. The for tag doesn't accept an integer, there is no dotimes.

But maybe adding this clause to create an iterable out of the integer:

;; 
(defun iterable-list (iterable)
  (typecase iterable
    (array (coerce iterable 'list))
    (hash-table (alexandria:hash-table-alist iterable))
    (sequence iterable)
    (integer (make-list iterable))  ;; <---------- added
    (t (error "Cannot iterate on ~A" iterable))))

I just borked my environment so I'll try later, so if you have better ideas I'm all ears.

Best,

accessing djula internals.

I have a one-off project to generate and update cl-locale's message.lisp dictionary files from Djula Html Template files. I have decided to clean it up and release it figuring others could use it.

Currently the project uses the internal function djula::parse-template-string and searches for :unparsed-translation-variable to find the strings that need to be translated.

Is there a better way without accessing this internal function?

How to build the Sphinx documentation?

Hi, I tried to build the Sphinx documentation with these packages:

    pip2 install --user sphinx sphinx_bootstrap_theme sphinxcontrib.cldomain

but with make html:

Could not import extension sphinxcontrib.cldomain (exception: cannot import name Directive)

Did I fetch the right packages? What's in your local installation?

regexp filter

Any reason we don't have filters like this:

(def-filter :replace (it regex)
  (lambda (replace)
    (cl-ppcre:regex-replace-all regex it replace)))

(def-filter :with (it replace)
  (funcall it replace))

(def-filter :scan (it regex)
  (cl-ppcre:scan-to-strings regex it))

;; Use like this:   {{ data  | replace:1| with:2}}

Broken Dependency Arnesi

I have been unable to install Djula using quicklisp on LispWorks on Windows. During installation it throws an error about missing package 'lexical' when compiling Arnesi package.

I had a look into the source, it indeed appears to access the package named lexical, however it does not appear to define in anywhere before hand.

Is that a known problem? The library appears to be almost 10 years old, I would not be holding my breath trying to get help from the author, this is why I am asking here.

Provide an iteration protocol

Currently the iterables are a 'closed abstraction'. An iterator protocol would allow the user to 'teach' the for tag how to iterate different the objects.

I propose something similar to python iterators. a next generic function and a stop-iteration condition. An addition to consider would be that the iterator knows how many values per iteration it provides. Although just using values could be a better choice.

Ideally this would help to break up the implementation of :parsed-for which is currently too large.

Is this extension desirable?

[Q] Help setting up i18n and xgettext?

Hi there, I'd be obliged if someone could help me set up i18n with Djula.

Looking at the doc, we have clean explanations on how to mark translatable strings in templates.

{% trans "hello" %}

{_ "hello _}

I am trying the gettext backend.

(gettext:setup-gettext #:abstock "abstock")

(gettext:preload-catalogs #.(asdf:system-relative-pathname :abstock "locale/"))

(setf gettext:*current-locale* "fr")

The first line creates the _ function: (_ "hello") returns "hello".

There is the update-translations.sh script to help use xgettext and friends.

=> I am trying to extract template strings and code strings with xgettext, to no avail:

mkdir locale
$ xgettext --from-code=UTF-8 -o locale/myapp.pot src/templates/search-form.html  
=> xgettext: warning: file 'src/templates/search-form.html' extension 'html' is unknown; will try C

$ xgettext --from-code=UTF-8 -o locale/abstock.pot src/myfile.lisp
=> nothing (what patterns does xgettext recognize for lisp anyways?)

in both cases locale/myapp.pot is not created.

While this isn't strictly related to Djula any help would be appreciated. Then I'll contribute doc :)

Quicklisp?

So, have you thought about adding this to Quicklisp? Would you rename it to Djula2 and add it a a separate project, or ask Zach to make this the new repo source for the existing Djula project?

Tests are fails on macOS 14 at CLisp

Hey,

The test are failed on CLisp, but works well on SBCL for example on the same system.

The log:

:info:test *** - The following check failed:
:info:test        (STRING=
:info:test         "
:info:test        I never could get the hang of Thursdays.
:info:test        "
:info:test         (RENDER-TEMPLATE* FN NIL :DAY "Thursday"))
:info:test       (RENDER-TEMPLATE* FN NIL :DAY "Thursday")
:info:test       evaluated to
:info:test       "
:info:test       I never could get the hang of Thursday
:info:test       s.
:info:test       "
:info:test       which is not
:info:test       STRING=
:info:test       to
:info:test       "
:info:test       I never could get the hang of Thursdays.
:info:test       "
:info:test       .

Is it possible to use Djula templates in a (hopefully) self-contained binary?

(I contacted Mariano by email, but since he already sent me a snippet to try out it's better if we continue the discussion in the open. I'll copy my question and his first answer(s))

I am getting my feet wet at running a web app from a binary, not from sources, and I am now trying to figure out how to use Djula templates from there.

Do you have any experience, any hints for this?

I use Deploy.
I initialize Djula templates at run time, not build time, but that is not enough for a binary, because the templates are not in a "src/templates/" directory any more, they are compiled and somewhere else in the binary, maybe…

For example:

(defun init-error-templates ()
   "Set the default error templates to the system's absolute location.
   Called at startup."
   (format! t "--- setting default error templates to ~a~&"
            (setf *error-template-directory*
               (asdf:system-relative-pathname :cosmo
  *default-error-template-directory*))))

I used asdf:system-relative-pathname, it's necessary or even required when working on the REPL (where the current working directory can be
anything).

I learnt how to declare my templates as static files in the .asd:

                (:module "src/templates"
                         :components
                         ((:static-file "admin.html")
                          (:static-file "base.html")
                          (:static-file "list.html")
                          …

but I don't know how to access them.
(edit) I learned how to list them and get their names and their absolute path: lisp-tips/lisp-tips#37

But I still don't know if I can use them with my binary.

Finally, on Discord, Shinmera shows me the use of deploy:runtime-directory:
https://github.com/Shirakumo/trial/blob/master/toolkit.lisp#L46-L50
maybe it helps…

I understand that, to be present in a self-contained binary, a Lisp thing has to be compiled. So maybe I should declare all the templates I use as parameters at build time.


addition: I also went to the 40ants' Gitter, Alexander created a demo project to show how to embed any static resource in a binary: https://github.com/svetlyak40wt/cl-static-resources and yes, it's easy (just create a defvar and store the file content), but it doesn't use Djula templates.

Better filters arguments parsing

Filters arguments parsing is too limited at the moment.

For instance, in:

(djula::parse-filter-string "my-filter: x y z")

x, y and z variables are not parsed appropriately. This makes it difficult to implement filters with more than one argument, and with optional arguments.

Maintain indentation

I would be very nice if block inheritence maintained the indentation level and newlines. For example:

{# base.html #}
<html lang="en">
  <head>
  </head>
  <body>
    <div>
      <div>
        <div>
          <div>
            {% block content %}{% endblock content %}
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
{# child.html #}
{% extends "base.html" %}
{% block content %}
<p>Some text</p>
{% endblock content %}

should be rendered as:

<html lang="en">
  <head>
  </head>
  <body>
    <div>
      <div>
        <div>
          <div>
            <p>Some text</p>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

and NOT as:

<html lang="en">
  <head>
  </head>
  <body>
    <div>
      <div>
        <div>
          <div>

<p>Some text</p>

          </div>
        </div>
      </div>
    </div>
  </body>
</html>

Question: replacing a placeholder in a placeholder?

I have a text variable that uses other variable placeholders:

;; var1
      <li> {{ contact.phone }} </li>

This var1 is rendered in the template literally, the contact.phone variable is not replaced:

{{ var1 }}
=>
      <li> {{ contact.phone }} </li>
;; instead of
0098 9 8 7…

This is the expected behaviour.

But maybe is there a Djula trick to make it re-evaluate the rendered text?

With simple variables like this I can still render var1 differently with a match and replace, even though it is less practical, but as soon as there are conditionals and other template tags, we'll want Djula's machinery.

      {% if contact.phone %}
      <li> {{ phone }} </li>
      {% endif %}

thanks

edit: looks totally like I should use templates now… looking into that.

Implement divisibleby or modulus equivalent

I'm missing the possibility of modulus operating on Djula templates.

On Django, it can be done with divisibleby. Ex: {% if forloop.counter0|divisibleby:4 %}. However, I can't do this on Djula. Obviously, forloop.counter0 % 4 also won't work, as % is a special character.

Would it be possible to implement modulus operator on templates?

cannot use base.html and subdir/base.html in inheritance chain

Hi!,
Djula is great!

I am a django template user from way back.

I have just debugged a weird case with a common inheritance pattern.

I have the bottom "base.html".

In a subdirectory I want to extend it with common features to some module.

So I have "search/base.html" extends "base.html".
And then everything in search/ will extend the local search/base.html.
Pretty typical pattern, i almost make it more confusing explaining it.

Ok with that above pattern I get:
fatal error encountered in SBCL pid 55444 pthread 0x1ac6c06fc30:
Control stack exhausted while pseudo-atomic, fault: 0x1ac40d17fa0, PC: 0x1ac6c066f86

Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb>

If I change search/base.html to search/base_search.html (or whatever) it works.

So something with the common base name is causing some loop ? obviously i have no idea :)

Anyways the workaround works but i did narrow it down enough to repro in case this interests you.

Thanks!!!!
Paul SomeoneElse

Error loading with quicklisp

Hi all,

I'm trying to make a project with caveman 2, and loading it with quicklisp I get the following error on the library:

;
; caught ERROR:
; READ error during COMPILE-FILE:
;
; unmatched close parenthesis
;
; Line: 64, Column: 23, File-Position: 2075
;
; Stream: #<SB-INT:FORM-TRACKING-STREAM
; for "file /Users/toni/.roswell/impls/ALL/ALL/quicklisp/dists/quicklisp/software/djula-20151031-git/src/lexer.lisp"
; {10082EC853}>

with the following trace:

COMPILE-FILE-ERROR while
compiling #<CL-SOURCE-FILE "djula" "src" "lexer">
[Condition of type UIOP/LISP-BUILD:COMPILE-FILE-ERROR]

Restarts:
0: [RETRY] Retry compiling #<CL-SOURCE-FILE "djula" "src" "lexer">.
1: [ACCEPT] Continue, treating compiling #<CL-SOURCE-FILE "djula" "src" "lexer"> as having been successful.
2: [RETRY] Retry ASDF operation.
3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
4: [ABORT] Give up on "sample-web-app"
5: [*ABORT] Return to SLIME's top level.
--more--

Backtrace:
0: (UIOP/LISP-BUILD:CHECK-LISP-COMPILE-RESULTS NIL T T "~/asdf-action::format-action/" ((#<ASDF/LISP-ACTION:COMPILE-OP > . #<ASDF/LISP-ACTION:CL-SOURCE-FILE "djula" "src" "lexer">)))
1: ((SB-PCL::EMF ASDF/ACTION:PERFORM) # # #<ASDF/LISP-ACTION:COMPILE-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "djula" "src" "lexer">)
2: ((:METHOD ASDF/ACTION:PERFORM-WITH-RESTARTS :AROUND (T T)) #<ASDF/LISP-ACTION:COMPILE-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "djula" "src" "lexer">) [fast-method]
3: ((:METHOD ASDF/PLAN:PERFORM-PLAN (LIST)) ((#1=#<ASDF/LISP-ACTION:PREPARE-OP > . #2=#<ASDF/SYSTEM:SYSTEM #3="lack-component">) (#1# . #4=#<ASDF/LISP-ACTION:CL-SOURCE-FILE #3# "src/component">) (#5=#<AS..
4: ((FLET SB-C::WITH-IT :IN SB-C::%WITH-COMPILATION-UNIT))
5: ((:METHOD ASDF/PLAN:PERFORM-PLAN :AROUND (T)) ((#1=#<ASDF/LISP-ACTION:PREPARE-OP > . #2=#<ASDF/SYSTEM:SYSTEM #3="lack-component">) (#1# . #4=#<ASDF/LISP-ACTION:CL-SOURCE-FILE #3# "src/component">) (#5..
6: ((FLET SB-C::WITH-IT :IN SB-C::%WITH-COMPILATION-UNIT))
7: ((:METHOD ASDF/PLAN:PERFORM-PLAN :AROUND (T)) #<ASDF/PLAN:SEQUENTIAL-PLAN {100710E6E3}> :VERBOSE NIL) [fast-method]
8: ((:METHOD ASDF/OPERATE:OPERATE (ASDF/OPERATION:OPERATION ASDF/COMPONENT:COMPONENT)) #<ASDF/LISP-ACTION:LOAD-OP :VERBOSE NIL> #<ASDF/SYSTEM:SYSTEM "sample-web-app"> :VERBOSE NIL) [fast-method]
9: ((SB-PCL::EMF ASDF/OPERATE:OPERATE) # # #<ASDF/LISP-ACTION:LOAD-OP :VERBOSE NIL> #<ASDF/SYSTEM:SYSTEM "sample-web-app"> :VERBOSE NIL)
10: ((LAMBDA NIL :IN ASDF/OPERATE:OPERATE))
11: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) #<ASDF/LISP-ACTION:LOAD-OP :VERBOSE NIL> #<ASDF/SYSTEM:SYSTEM "sample-web-app"> :VERBOSE NIL) [fast-method]
12: ((SB-PCL::EMF ASDF/OPERATE:OPERATE) # # ASDF/LISP-ACTION:LOAD-OP "sample-web-app" :VERBOSE NIL)
13: ((LAMBDA NIL :IN ASDF/OPERATE:OPERATE))
14: (ASDF/CACHE:CALL-WITH-ASDF-CACHE #<CLOSURE (LAMBDA NIL :IN ASDF/OPERATE:OPERATE) {10070FEC1B}> :OVERRIDE NIL :KEY NIL)
15: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) ASDF/LISP-ACTION:LOAD-OP "sample-web-app" :VERBOSE NIL) [fast-method]
16: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) ASDF/LISP-ACTION:LOAD-OP "sample-web-app" :VERBOSE NIL) [fast-method]
17: (QUICKLISP-CLIENT::CALL-WITH-MACROEXPAND-PROGRESS #<CLOSURE (LAMBDA NIL :IN QUICKLISP-CLIENT::APPLY-LOAD-STRATEGY) {1006F0A77B}>)
18: (QUICKLISP-CLIENT::AUTOLOAD-SYSTEM-AND-DEPENDENCIES "sample-web-app" :PROMPT NIL)
19: ((:METHOD QL-IMPL-UTIL::%CALL-WITH-QUIET-COMPILATION (T T)) # #<CLOSURE (FLET QUICKLISP-CLIENT::QL :IN QUICKLISP-CLIENT:QUICKLOAD) {1004205EBB}>) [fast-method]
20: ((:METHOD QL-IMPL-UTIL::%CALL-WITH-QUIET-COMPILATION :AROUND (QL-IMPL:SBCL T)) #<QL-IMPL:SBCL {10050728F3}> #<CLOSURE (FLET QUICKLISP-CLIENT::QL :IN QUICKLISP-CLIENT:QUICKLOAD) {1004205EBB}>) [fast-me..
21: ((:METHOD QUICKLISP-CLIENT:QUICKLOAD (T)) # :PROMPT NIL :SILENT NIL :VERBOSE NIL) [fast-method]
22: (QL-DIST::CALL-WITH-CONSISTENT-DISTS #<CLOSURE (LAMBDA NIL :IN QUICKLISP-CLIENT:QUICKLOAD) {10041E852B}>)
23: (SB-INT:SIMPLE-EVAL-IN-LEXENV (QUICKLISP-CLIENT:QUICKLOAD :SAMPLE-WEB-APP) #)
24: (EVAL (QUICKLISP-CLIENT:QUICKLOAD :SAMPLE-WEB-APP))
25: (SWANK::%EVAL-REGION "(ql:quickload :sample-web-app) ..)
26: ((LAMBDA NIL :IN SWANK::%LISTENER-EVAL))
27: (SWANK-REPL::TRACK-PACKAGE #<CLOSURE (LAMBDA NIL :IN SWANK::%LISTENER-EVAL) {10041E83EB}>)
28: (SWANK::CALL-WITH-BUFFER-SYNTAX NIL #<CLOSURE (LAMBDA NIL :IN SWANK::%LISTENER-EVAL) {10041E83CB}>)
29: (SWANK::%LISTENER-EVAL "(ql:quickload :sample-web-app) ..)
30: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK-REPL:LISTENER-EVAL "(ql:quickload :sample-web-app) ..)
31: (EVAL (SWANK-REPL:LISTENER-EVAL "(ql:quickload :sample-web-app) ..)
32: (SWANK:EVAL-FOR-EMACS (SWANK-REPL:LISTENER-EVAL "(ql:quickload :sample-web-app) ..)
33: (SWANK::PROCESS-REQUESTS NIL)
34: ((LAMBDA NIL :IN SWANK::HANDLE-REQUESTS))
35: ((LAMBDA NIL :IN SWANK::HANDLE-REQUESTS))
36: (SWANK/SBCL::CALL-WITH-BREAK-HOOK # #<CLOSURE (LAMBDA NIL :IN SWANK::HANDLE-REQUESTS) {1002F8800B}>)
37: ((FLET SWANK/BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/Users/toni/.roswell/impls/ALL/ALL/quicklisp/dists/quicklisp/software/slime-2.14/swank/sbcl.lisp") # #<CLOSURE (LA..
38: (SWANK::CALL-WITH-BINDINGS ((STANDARD-OUTPUT . #1=#<SWANK/GRAY::SLIME-OUTPUT-STREAM {1002F5E343}>) (STANDARD-INPUT . #2=#<SWANK/GRAY::SLIME-INPUT-STREAM {1002AE82D3}>) (TRACE-OUTPUT . #1#) (*ERR..
39: (SWANK::HANDLE-REQUESTS #<SWANK::MULTITHREADED-CONNECTION {1005E408A3}> NIL)
40: ((FLET #:WITHOUT-INTERRUPTS-BODY-1002 :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
41: ((FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
42: ((FLET #:WITHOUT-INTERRUPTS-BODY-335 :IN SB-THREAD::CALL-WITH-MUTEX))
43: (SB-THREAD::CALL-WITH-MUTEX #<CLOSURE (FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE) {DA83CFB}> #<SB-THREAD:MUTEX "thread result lock" owner: #<SB-THREAD:THREAD "..
44: (SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE #<SB-THREAD:THREAD "repl-thread" RUNNING {1002F80003}> NIL #<CLOSURE (LAMBDA NIL :IN SWANK-REPL::SPAWN-REPL-THREAD) {1002F7FF7B}> (#<SB-THREAD:THREAD "re..
45: ("foreign function: call_into_lisp")
46: ("foreign function: new_thread_trampoline")
47: ("foreign function: _pthread_body")
48: ("foreign function: _pthread_body")
49: ("foreign function: thread_start")

Problem with ifchanged tag

I've found strange behaviour of the ifchanged tag. Looks like last value is cached somewhere, so when the loop is rerunned (on second render-template* call, for example), tag doesn't work as intended.

Simple testcase:

(defparameter +tpl+ (djula::compile-string "start {% for i in data %}{% ifchanged i %}[changed] {% endifchanged %}{{ i }} {% endfor %}end
"))

(djula:render-template* +tpl+ *standard-output* :data '(1 2)) ; Ok
(djula:render-template* +tpl+ *standard-output* :data '(1 1)) ; Ok
(djula:render-template* +tpl+ *standard-output* :data '(1 1)) ; Wrong

Results:

start [changed] 1 [changed] 2 end
start [changed] 1 1 end
start 1 1 end

That can lead to strange outcome: in real life web application, when loop has one iteration, ifchanged works only when page is opened first time, and doesn't show anything after.

Is it a bug or am I doing something wrong?

Test broken on ECL `(ASDF/SYSTEM:SYSTEM-RELATIVE-PATHNAME :DJULA "test/templates/t1.djula")`

Running (asdf:test-system "djula") with ECL 23.9.9 on an ARM Mac I get:

Running test suite DJULA-TEST
 Running test COMPILER .
 Running test CATCH-ERRORS-TEST ....
 Running test FILTERS ...........................
 Running test APPLY-FILTERS .
 Running test REGEX-FILTERS ...
 Running test LEXER ...
 Running test PARSER .
 Running test FIRSTOF ......
 Running test CYCLE .
 Running test JS ..
 Running test LANGUAGE ..
 Running test LOGIC ..
 Running test CONDITIONAL-TEST ..........................
 Running test ELIF-TEST ...
 Running test LOOP-TEST ................
 Running test NESTED-LOOP-TEST .
 Running test LOGICAL-STATEMENTS-TEST ...........
 Running test LISP-TAG-TEST ...
 Running test COMMENT-TEST ..
 Running test IFEQUAL-TEST .......
 Running test IFNOTEQUAL-TEST ...
 Running test VERBATIM-TEST ..
 Running test AUTOESCAPE-TEST ...........
 Running test IFCHANGED-TEST ...
 Running test VARIABLES-TEST ....
 Running test APPLY-KEYS/INDEXES-TEST .
 Running test VARIABLES-ACCESSING-TEST .............
 Running test ESCAPING-TEST ......
 Running test DEFAULT-TEMPLATE-ARGUMENTS ....
 Running test SIMPLE-BLOCK-TEST .
 Running test ONE-LEVEL-BLOCK-INHERITANCE-TEST .
 Running test TWO-LEVELS-BLOCK-INHERITANCE-TEST .
 Running test EXTENDS-ERROR-TEST .
 Running test SIMPLE-SUPER-TEST .
 Running test SIMPLE-ANNON-SUPER-TEST .
 Running test SUPER-ERROR ..
 Running test INCLUDE-TEST .
 Running test INCLUDE-WITH-VARS-TEST .
 Running test MULTIPLE-LEVELS-BLOCK-INHERITANCE-TEST .
 Running test PARAMETERIZED-INCLUDE-TEST .
 Running test PARAMETERIZED-INCLUDE-WITH-VARS-TEST .
 Running test RELATIVE-EXTENDS-1-TEST .
 Running test RELATIVE-EXTENDS-2-TEST .
 Running test RELATIVE-EXTENDS-3-TEST .
 Running test RELATIVE-EXTENDS-4-TEST .
 Running test FIND-TEMPLATE-TEST An error occurred during initialization:
The following check failed: (EQUALP (FIND-TEMPLATE* "t1.djula" NIL)
                                    (ASDF/SYSTEM:SYSTEM-RELATIVE-PATHNAME
                                     :DJULA
                                     "test/templates/t1.djula"))

(ASDF/SYSTEM:SYSTEM-RELATIVE-PATHNAME :DJULA "test/templates/t1.djula")

 evaluated to

#P"/Users/user/code/common-lisp/djula/test/templates/t1.djula"

 which is not

EQUALP

 to

#P"/Users/user/code/common-lisp/djula/test/templates/t1.djula"

..

(pretty weird error message tbh 🤔)

Works fine on SBCL.

comparison in if blocks

Comparison expressions (using == or !=) in if blocks currently don't work, because the parser isn't looking for them. It will pick up 'and' and 'or', but == and != just get parsed as variables. Parentheses are also broken in that context (it parses a list of items and attempts to coerce it to a string).

An expression parser would be pretty simple to do, given the limited number of operators, but I won't have time to work on it for a bit and thought you might like to know about the issues anyway.

Tests take too long due to runtime compilation

For example, in my machine (run 'filters) took ~10 seconds and crashed sbcl due to heap exhaustion if ran twice w/o calling gc.

Scymtm pointed out hat by default fiveam compiles tests at runtime. We should use (def-test <name> (:compile-at :definition-time) ...) instead. Although I'm unsure of the implications of that except for faster test times.

Is moving to prove an option?

Erroneous function type declarations

Function find-template may return a pathname (the result of uiop:file-exists-p when passed a pathname that designates an existing file), but the ftype declaration in specials.lisp claims that the return type is (or string null).

Feedback: possible issue with string-downcase in backend-translate for gettext

Currently:

(defmethod backend-translate ((backend (eql :gettext)) string language &rest args)
  (apply #'format-translation
         (gettext:gettext* string *gettext-domain* nil (string-downcase (string language)))
         args))

this string-downcase made us spend some more debugging time (all credit to @fstamour).

Shall we remove it?

Or, maybe, there could be a set-locale interface between us and djula:*current-language* that does the right thing (a downcase too?). fstamour came up with these helpers in our i18n.lisp:

(defun list-loaded-locales ()
  "Get the list of locales loaded in gettext's cache."
  (remove-duplicates
   (mapcar #'first
           (alexandria:hash-table-keysfunction
            gettext::*catalog-cache*))
   :test #'string=))

(defun set-locale (locale)
  "Setf gettext:*current-locale* and djula:*current-language* if LOCALE seems valid."
  ;; It is valid to set the locale to nil.
  (when (and locale
             (not (member locale (list-loaded-locales)
                          :test 'string=)))
    (error "Locale not valid or not available: ~s" locale))
  (setf *current-locale* locale
        djula:*current-language* locale))

Documentation filters: 'add' arguments

Hi, it seems that the docs state that the filter add works like this: {{ value|add "2" }}

It returns an {# Error: Unknown filter ADD "2" #} on my end.
It does work in my project when I use it like this: {{ value|add:2 }}

My guess is is that this is incorrect in the docs, is that right?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.