Fork me on GitHub
#beginners
<
2022-03-18
>
Thomas Harned00:03:56

I'm looking to create a static website with Clojure. Is Cyrogen my best bet or are there other clojure-based site generators I should be looking at?

Cora (she/her)01:03:35

misaki is a Jekyll inspired static site generator in Clojure.
    Madness is a static site generator, based on Enlive and Bootstrap.
    Static is a simple static site generator written in Clojure.
    Ecstatic creates static web pages and blog posts from Hiccup templates and Markdown.
    incise is an extensible static site generator written in Clojure.
    Cryogen is a static sites generator written in Clojure

Cora (she/her)01:03:48

you can find the links in the stasis readme

craftybones01:03:59

Stasis is simple enough. Requires you to hand roll everything though, but useful

craftybones01:03:36

Here are some more options.

craftybones01:03:03

Neither are frameworks however.

tschady01:03:25

TIL cryogen has asciidoc support, that does it for me

practicalli-johnny14:03:28

http://cryogenweb.org/ is a good solution if you want an easy to generate blog website so you can focus on writing content, as its all self contained. Its fairly easy to create a custom theme, by editing the html and css templates from an existing theme. Content can be written in markdown or asciidoc. Its relatively easy to use CI to deploy cryogen, https://practical.li/blog/posts/automate-cryogen-clojure-blog-with-github-actions/ I also use https://figwheel.org/ to generate landing pages. With figwheel-main you can build a front-end UI with ClojureScript and generate a 'static' site (with dynamic UI generated from ClojureScript. I take this approach want more control over the web design or doing something other than a blog site, also deployed on GitHub pages If you want something more akin to a content management system, then https://github.com/juxt/site is a very interesting project

Sturm01:03:18

can any file declare any namespace? For example, can I write (ns clojure.string.foo) (def x 1) and have that available to other code? I'm kinda hoping the answer is no because that seems like it could get confusing.

Sturm01:03:08

or do the path and namespace have to align?

dpsutton01:03:05

Depends on the context. Any file can declare any namespace and multiple namespaces. But if you require a namespace, it will look for it by the traditional convention

dpsutton01:03:04

but you can certainly put a file clojure/string/foo.clj anywhere on your classpath and it would find it if you (require 'clojure.string.foo). There's nothing special about clojure in the segment of a namespace that i'm aware of. But very frowned upon to do so

Sturm01:03:11

@dpsutton I was watching https://clojuresync.com/david-nolen/ announcing cljs.main and he mentions at 26:00 that the --repl-env x command line argument just looks for cljs.repl.x. Is what he's talking about there doing the "putting a file anywhere on classpath" you mentioned above?

dpsutton01:03:27

yes it looks like it. When it starts up it takes whatever arg you give it (if its single segment) and does (require cljs.repl.X): https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/main.clj#L20-L26

dpsutton01:03:21

so that code requires that namespace and then expects there to be a var called repl-env in that namespace

Sturm01:03:15

thanks very much - makes sense! So you were walking up to an unknown system to troubleshoot it, how would you determine which file the cljs.repl.X code is in?

dpsutton02:03:38

what's your actual problem here? I would be surprised if there was a problem with the --repl-env node argument to the clojurescript compiler

dpsutton02:03:15

if your question is in general what file was found with require, i think you can use io/resource to find the actual file that would be found

Sturm02:03:02

sorry, not specific to cljs.repl - just if you wanted to know where the code lived for x.y.z. For example in Python I'd do import x.y.z x.y.z.__file__

dpsutton02:03:27

word=> (io/resource "clojure/set.clj")
#object[java.net.URL 0x2360f983 "jar:file:/Users/dan/.m2/repository/org/clojure/clojure/1.10.3/clojure-1.10.3.jar!/clojure/set.clj"]

dpsutton02:03:50

but there isn't necessarily a file behind every namespace. they can easily be created programmatically.

Sturm02:03:37

ouch! that would be a challenge trying to debug something you couldn't even find on disk heh. It's like when you run into a PHP system that stores code in the database

dpsutton02:03:38

i still suspect you have an actual, tangible problem in mind that you haven't said. All of this is not a problem that pops up in real life for me

Sturm02:03:28

no, no real problem in mind. I'm just working through the Luminus book and wondering

dpsutton02:03:37

you can do all kinds of shenanigans. of course there's eval as well. But i find that for the most part in production code things are pretty mundane

Sturm02:03:04

that's good to hear you don't need that stuff in practise. I just find as a solo Python consultant, I do sometimes have to locate the code for a Python module like this to troubleshoot confusing import path issues on existing systems. Maybe it's not such an issue with classpath.

walterl08:03:38

Tooling like https://clojure-lsp.io/features/#find-a-functionvar-definition (usually integrated into your editor) makes it easy to find code. Just like you could with pyls (quicker than x.y.z.__file__).

dpsutton02:03:22

I've never had an issue finding code

Sturm02:03:53

I'm doing something wrong here - why doesn't (require '( :as io)) work when I type it into the repl? Copied from https://clojuredocs.org/clojure.java.io/resource

Sturm02:03:09

Don't know how to create ISeq from: clojure.lang.Keyword

dpsutton02:03:37

looks like require requires vectors. Check out (doc require). > Libspecs > A libspec is a lib name or a vector containing a lib name followed by > options expressed as sequential keywords and arguments.

dpsutton02:03:46

so do (require '[ :as io])

Michaël Salihi11:03:06

Hi! I would like some advice about the best Clojure data structure when there will be a lot of move inside a vector itself (reordering) or move in another one? Eg. Move card with ID 1 First Card from the list To Do to the cards vector inside the Doing list (ID 2) at defined index (here index 1) :

(def lists (atom [{:id "1"
                   :name "To Do"
                   :cards [{:id "1" :label "First Card"}
                           {:id "2" :label "Second Card"}]}
                  {:id "2"
                   :name "Doing"
                   :cards [{:id "3" :label "First Card"}
                           {:id "4" :label "Second Card"}
                           {:id "5" :label "Third Card"}]}]))

delaguardo11:03:25

consider also having one list of cards with labels inside each of them. Then "moving" from "To Do" to "Doing" will be simple label change.

2
Michaël Salihi12:03:42

Interesting, thanks. Let me think about it and/or try. The front end usage of these datas is for a kanban. So with your solution, then we'll have to transform with group-by right?

Ferdinand Beyer12:03:59

I think the label idea might not work when you care about the order of cards in a list. In that case your current solution is probably better. You can also think about modelling this like a database:

(def db (atom {:cards {"1" {:id "1", :label "...}
                       "2" ...}
               :lists {"1" {:id "1", :name "To Do", :cards ["1" "2"]}}}))
This means you can change card labels, names, etc, independent on the list they are in. Changing order or lists would evolve updating the list vectors, but that should be OK.

1
Michaël Salihi13:03:03

Sound good! Thanks both 🙏 I'm going to test this second solution.

Michaël Salihi14:03:13

Of course, other suggestions are welcome. 😉

pavlosmelissinos15:03:20

Are the card ids unique across lists?

borkdude16:03:41

What @U04V4KLKC said would probably be my approach too

borkdude16:03:10

you could possibly also use multiple indexes by card id

borkdude16:03:44

or move to a database, e.g. sqlite ;)

2
borkdude16:03:01

it seems you want to preserve the state of these cards when the server goes down anyway

noisesmith18:03:59

as an aside, the name lists is weird because list is a clojure data type, and it's not used here

Michaël Salihi18:03:03

Yes something like board is more appropriate, thanks for the suggestion @U051SS2EU.

Michaël Salihi11:03:22

to

(def lists (atom [{:id "1"
                   :name "To Do"
                   :cards [{:id "2" :label "Second Card"}]}
                  {:id "2"
                   :name "Doing"
                   :cards [{:id "3" :label "First Card"}
                           {:id "1" :label "First Card"}
                           {:id "4" :label "Second Card"}
                           {:id "5" :label "Third Card"}]}]))

adi17:03:03

x-posting, because FizzBuzz is such a rite of passage for newcomers to any $ProgLang, and because I'm having fun playing the fool and seeing where it goes! 🤓

👀 1
clojure-spin 1
leifericf19:03:18

Funny you should mention that! Yesterday, I was learning about some-> and cond-> when I came across https://clojuredocs.org/clojure.core/cond-%3E#example-570c2e57e4b0fc95a97eab4a that blew me away. I see it’s not mentioned in your blog post (which is very nice by the way!), so I thought you might also enjoy seeing it. I was blown away by the incredibly succinct, yet readable implementation.

gratitude 1
leifericf19:03:13

Oh! And https://github.com/clojure/core.match#example-usage which uses core.match is also pretty neat!

adi20:03:30

Hah in fact, I saw FizzBuzz as a Service earlier today ... hilarious :) re: core.match, I've chosen to stick to clojure.core only for this post. The goal is to tour the standard library as much as possible, and to highlight ideas and ways of thinking that would be surprising but useful to newcomers. Re: the some-> cond->, thanks for the note! Maybe I'll bring those in at some point. I'm in two minds about macrology... It may be too confusing to newcomers. The linked cond-> fizzbuzz for example contains rather subtle interactions of macro-expansion with nil-punning and non short-circuiting behaviour. Deconstructing that properly for the uninitiated probably requires a blog post of its own! 😅

👍 1
Lennart Buit22:03:44

haha the data driven one is my party trick when someone asks me how to fizzbuzz

lightsaber 1
adi19:03:35

"Dispatch Buzz" just dropped 🤓 ... this was a nice little rabbit hole to fall into today! https://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/#dispatch-buzz

❤️ 3
adi22:03:33

So, things have gotten a little out of hand. It is now well past 3 AM and there are five-and-a-half more fizzbuzzes. • https://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/#embarrassingly-parallel-fizzbuzz, • https://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/#oop-buzz, and • 3.5 kinds of https://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/#non-destructive-fizzbuzzhttps://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/#non-destructive-fizzbuzz. Please enjoy these delicious new FizzBuzzes. (And please complain if any of them taste funny). 🤓

😆 2
🥴 1
👀 1
gratitude 1
teodorlu22:03:45

Man, this is pure joy to read! 😄❤️💯

teodorlu22:03:04

Love your style.

😄 1
🙏 1
gratitude 1
noisesmith00:03:44

one of the few cases where using pmap actually makes sense (it's designed for CPU bound tasks (the parallelism is limited by available processors), and most times I see attempts to use it it's around IO, where it's far from optimal)

1
adi05:03:25

> one of the few cases where using pmap actually makes sense Yup, one of my self-imposed constraints is to not do non-useful FizzBuzzes. Each one---even the silly ones---should have a valid reason to exist and should show some real-world Clojure thinking.

👍 1
John Bradens19:03:25

Hey everyone, we've got a Clojure Study group going on Discord. We are all somewhat beginner level, and we are talking about building a full stack app together to learn. If it gets to be a big group, we can always split into smaller projects too. I hope posting a discord link isn't against the rules. I'll post the invite in case anyone is interested

🙌 1
John Bradens19:03:53

https://discord.gg/TEB7SU6Ark Once again, hope this isn't against rules to have this link, please message me if so & I can edit accordingly.

leifericf20:03:03

I think it’s great that there is some cross-pollination of the different Clojure “sub-communities!” I wish we were less fragmented as a community with respect to communication platforms.

❤️ 1
practicalli-johnny10:03:26

I joined and had a quick look, seemed a lot of noise, hard to find anything useful. I am sure I missed something though. Suggest it needs a bit of thought as to what it's trying to achieve and a bit of organisation to be more widely useful.

John Bradens01:03:38

@U05254DQM Thanks for the feedback! It's definitely a work in progress & hasn't fully taken shape yet.