Spinneret: A modern Common Lisp HTML generator
github.com
github.com
* Static syntax-based: https://docs.racket-lang.org/html-template/
* Dynamic data-based: https://docs.racket-lang.org/html-writing/
I like that Spinneret focuses on HTML5. My work started over 20 years ago, with HTML always being quirky, and also sometimes used in conjunction with my permissive HTML parser. So there's a need to maintain backward-compatibility with how things worked before, including weird non-open-source things. (With the parser, I've also recently gotten requests to support 20yo HTML, for dealing with legacy data.) Doing something all new, tailored to HTML5 or something higher-level, would be able to do some things better. (But I strongly recommend trying to stick with SXML representation/syntax at some level, though, since it's a de-facto standard in the Scheme world, and can be used in a way compatible with representing HTML5.)
Always love to see Racket being mentioned!
[0] htdp.org
In TL-WHO, there is a deftag inspired by Spinneret.
https://www.kylheku.com/cgit/tl-who/about/#the-deftag-macro
deftag lets you define macros targeting tags in the HTML structure, which expand into combinations of other tags.
That said, I've been using Spinneret for a side project[1] for a while, and overall I'm very happy with it. It's nice to have macros like deftag and all the other magic powers of Common Lisp, and because of CL's syntactic simplicity, the templates remain easy to read and reason about while getting a lot done.
I recommend giving Spinneret a try!
[1] rpanytime.com
The only slightly tricky part is spinneret’s attribute validation
I'm firmly in camp cl-who, so not a problem for me :)
I use spinneret for a flashcard / boggle website I made. It's nice and compact compared to writing the HTML by hand or using something like Jinga2. You get the full power of a programming language (the same one you're using for other stuff) to generate your html.
I don't do anything fancy. I just use regular Javascript and CSS, though I do want to look into some of these other technologies.
That doesn't seem excessive. I didn't look to see how many imports each gets.
Need the utility libraries? Probably not. Embrace the NIH.
Need both trivia and PPCRE tho? They both pattern match.
1. I've been using CL for longer than Clojure has existed
2. SLIME is better than any Clojure dev setup I've seen
3. Maybe I'm misunderstanding things, but if I get how Leiningen works, I need to restart my REPL any time I want to add dependencies?
4. Kind of a minor thing, but working in a Lisp-1 hits the "uncanny valley" of programming for me; I accidentally shadow an important function at least once an hour when working in Clojure or Scheme.
That is correct, though a lot of people are moving to `deps.edn` which recently lets you add dependencies on the fly.
> I accidentally shadow an important function at least once an hour when working in Clojure
You mean that you accidentally "overwrite" (declare again) a function with the same name as the one you're now declaring, but you didn't mean to?
If so, I'm not sure how that'd be possible. In Clojure you're always in a namespace, and you'd only have one function with that one name in that namespace, and if you're declaring a function with the same name in a different namespace, you now correctly have two functions with the same name, but in different namespaces.
Unless your editor<>repl connection somehow ignores the current ns, I'm not sure how you'd end up in that situation.
> SLIME is better than any Clojure dev setup I've seen
This I'm also curious about, what exactly SLIME gives you that for example Conjure for neovim wouldn't already? Maybe something about continuations perhaps? That seems to be the only feature I've seen from Common Lisp (besides actually being able to compile to binaries) that I'd love to have in Clojure.
I mean I use let to bind a variable with the same name as a function. This is idiomatic in Common Lisp, and totally breaks things in most other languages.
> This I'm also curious about, what exactly SLIME gives you that for example Conjure for neovim wouldn't already? Maybe something about continuations perhaps? That seems to be the only feature I've seen from Common Lisp (besides actually being able to compile to binaries) that I'd love to have in Clojure.
I watched a video and it does seem rather complete, but [1] indicates there is no debugger? That's a rather glaring omission. I also don't see a profiler mentioned, and SLIME with SBCL gives me a profiler (down to the assembly level if needed). I'm sure Java in general has great profiling tools, but how are the integrated into the Clojure system?
As an aside, by "continuations" did you mean "restarts"? First-class continuations are a feature of scheme, not CL. Indeed a huge boost to CL productivity is simply allowing you to handle an exception before the stack is unwound.
Aha, that should be working fine?
(defn add [x y]
(let [add clojure.core/+]
(add x y)))
The `let` binding is local, so it's referring to clojure.core/+, and outside the function `add` I can use the name `add` to call it. Seems it's handling that case correct?> I watched a video and it does seem rather complete, but [1] indicates there is no debugger?
I think debuggers tend to be used as a library across many different editors, rather than the editor/plugin providing that functionality. Personally, I don't use debuggers much as the functions I write tend to be small and evaluating small executions with the repl tends to reveal the issue quickly. Sometimes when refactoring others code I've used https://github.com/philoskim/debux to various degrees of success.
I do think cider (https://github.com/clojure-emacs/cider) has stuff regarding stepping debuggers, but I'm not sure how common it is to use it. Maybe other Clojure users can fill me in :)
> . I also don't see a profiler mentioned
Yeah, as you said, the Java ecosystem basically covers that. For OSS stuff, I use VisualVM, and for professional stuff I use YourKit, both of them work well with Clojure and points out my user-space code with ease. And I've never been paid anything for actually writing/maintaining Java code, so even with that, seems I'm able to use those tools just for Clojure :)
> As an aside, by "continuations" did you mean "restarts"?
Ah yes, of course. The condition system and restarts :) Thanks!
user=> (defn foo [seq]
#_=> (every? seq seq))
#'user/foo
user=> (foo ["1" [1] '(1) {:1 1} #{1}])
Execution error (IllegalArgumentException) at user/foo (REPL:2).
Key must be integer
Note that in a CL with a "seq" function foo would look like: (defun foo (seq)
(every #'seq seq))
So there would be no ambiguity.I don't really care about stepping; for me the debugger is about inspecting the state of my program when an exception (maybe because I interrupted it, or because I inserted a breakpoint, or just because something went wrong) happens. Backtrace, local variables, evaluating forms at different stack frames and so-forth.
https://github.com/clj-commons/pomegranate https://stackoverflow.com/questions/16409182/any-way-to-add-...
=> (use '[cemerick.pomegranate :only (add-dependencies)]) nil => (add-dependencies :coordinates '[[incanter "1.2.3"]])
Boot build comes really close, here, but the community never really adopted it.
This is from my experience creating a small website that runs on AWS with: - nginx - SBCL - hunchentoot - easy-routes - cl-json - cl-sqlite - ...
Most of the positives come from Common Lisp's condition system and built in debugger. I like the ability to hit an unexpected condition, pause, poke around at things, re-compile, and retry the code. This can be very useful for something interactive like a website. It took me a while to get the hang of it, but once you learn it it's quite powerful.
You can also apply the same techniques to the production server with minimal fear you're going to break stuff. Common Lisp is designed with the idea that developers will change state on the fly, so it has mechanisms in place to make this easy and reasonably safe.
SBCL is also "fast", at least when compared to Python or Ruby, but I imagine Clojure is too.
I would assume most other benefits would be similar with Clojure (Macros, html generation, etc.)
Nice job though. The code is clean.
Thus CL-WHO is vulnerable to XSS attack by default.
Just bringing up some history. I don't know the age profile of the developers or readers anymore.
Just trying to look smart.