Fork me on GitHub
#beginners
<
2020-08-10
>
Clark Urzo00:08:12

So I'm starting a server with lein ring server-headless but there's something going wrong when I connect to the accompanying nREPL server via lein repl :connect localhost:<port>

Clark Urzo00:08:02

I'm getting this error:

$ lein repl localhost:38875 
Connecting to nREPL at localhost:38875 
Syntax error (ClassNotFoundException) compiling at (form-init5283084375133054559.clj:1:82). 
nrepl.core 
#object[clojure.lang.Namespace 0x2d4efbbb "user"] 
Error loading namespace; falling back to user 
nil 
user=>

Clark Urzo00:08:13

What's happening here?

Clark Urzo00:08:58

For reference, here's my project.clj file:

(defproject hello-compojure "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :min-lein-version "2.0.0"
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [org.clojure/tools.nrepl "0.2.13"]
                 [nrepl/drawbridge "0.2.1"]
                 [compojure "1.6.2"]
                 [ring/ring-defaults "0.3.2"]]
  :plugins [[lein-ring "0.12.5"]]
  :ring {:handler hello-compojure.handler/app
         :nrepl {:start? true}}
  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring/ring-mock "0.3.2"]]}})

ozzloy00:08:34

can you create a git repo and push the whole project somewhere (eg github) and post a link to it?

ozzloy00:08:46

not that i expect i'll be able to help

ozzloy00:08:53

but seems like it'd be useful

Clark Urzo00:08:47

To be fair, I literally just ran the default compojure template

Clark Urzo00:08:54

But maybe I'm missing something here

ozzloy00:08:23

says i need to sign in or sign up before continuing

ozzloy00:08:22

cloned, trying lein ring server-headless

ozzloy00:08:51

worked for me. i see "Hello World" at localhost:3000

ozzloy00:08:44

have you tried squinting your eyes and looking at the terminal with your head slightly turned away?

ozzloy00:08:55

that's what i did

ozzloy00:08:29

does git status show anything not committed and pushed?

Clark Urzo00:08:50

I mean, try doing a defroute

Clark Urzo00:08:59

It's not being found is what i'm saying

Clark Urzo00:08:36

so i think compojure isn't being loaded properly

ozzloy00:08:36

oh, woops, i forgot that part, sorry. i'll try that

ozzloy00:08:32

so the sequence is: 0. lein ring server-headless 1. lein repl :connect localhost:PORT? where does PORT come from? i was expecting to find it in the output of step 0

ozzloy00:08:47

oh, there it is, i missed it

ozzloy00:08:14

ok, confirmed, i see the same issue

Clark Urzo01:08:36

I'm thinking it could be an unresolved issue or something but my google-fu is failing me

ozzloy01:08:48

i am also not sure

ozzloy01:08:01

i was able to do a plain "lein repl" and that seemed to work

Clark Urzo01:08:28

Yes, but it just starts another nREPL server

seancorfield01:08:01

The problem is that lein-ring uses an older version of nREPL (`org.clojure/tools.nrepl "0.2.3"` per https://github.com/weavejester/lein-ring/blob/master/src/leiningen/ring/server.clj#L45) which is not compatible with modern nREPL (which is nrepl/nrepl "0.6.0" at this point).

seancorfield01:08:25

My advice: do not use lein-ring. Learn to start your server via the -main function and from a regular lein repl.

seancorfield01:08:47

(seriously, most of these plugins meant to "make life easier" just end up making life harder)

seancorfield01:08:38

And it is compounded here because the compojure template for Leiningen doesn't give you a proper "application" with a -main function 😞

seancorfield02:08:05

@signup867 Here's the Compojure template project updated with a proper -main and updated project.clj and handler.clj files: https://github.com/seancorfield/hello-compojure

seancorfield02:08:25

See the README for how to start a server from the REPL, and how to run the project without a REPL.

seancorfield02:08:22

I removed lein-ring, added the full ring/ring dependency, added a :main entry point (that's all project.clj). In handler.clj I added a -main function.

seancorfield02:08:10

The key is ring.adapter.jetty and the run-jetty function. Calling it with just {:port 3000} will block -- until the server exits, i.e., until you kill the process. Calling it with {:port 3000 :join? false} will kick off the server in a background thread.

Clark Urzo02:08:25

Oh wow. Thank you so much @seancorfield!

Clark Urzo02:08:29

I love this community so much

seancorfield02:08:31

LMK if you have any Qs about the changes or the process.

seancorfield02:08:23

You may also find https://github.com/seancorfield/usermanager-example helpful as a way to explore Compojure/Ring with Component, Selmer, and next.jdbc to have a full but small web app with a database.

seancorfield16:08:26

Worth mentioning here for everyone curious about REPL-Driven Development: Eric Normand has made two of the lessons in his excellent RDD course free for a short time (in addition to the overview which was always free): * https://purelyfunctional.tv/lesson/all-about-flow/ -- what is "flow" and why it is important * https://purelyfunctional.tv/lesson/a-map-of-the-repl-driven-development-territory/ -- a look at an idealized development workflow and how it maps onto RDD I highly recommend his paid course (there are several others that make it worth having a monthly membership, even if you only sign up for a month).

salam04:08:41

thanks for sharing this, Sean! this is the course i really wanted out of his subscription. would you recommend this particular course for one who already knows a thing or two about repl-aided development and already established a workflow of his own?

seancorfield04:08:41

Yes, I found it valuable, and I've been doing this for a decade.

👍 3
seancorfield04:08:07

I'm probably going to take the three property-based testing courses at some point.

seancorfield16:08:55

(making sure you have a smooth, fast REPL workflow is the best investment you can make in becoming an effective Clojure programmer)

adnauseum18:08:01

I’ve edited my REPL session to make things simpler, so don’t mind the pointlessness of my code or usage of ->>

(->>
  [132 132]
  (reduce +)
  (mod 11))
This produces 264 which. (mod 264 11) => 0 which is expected, but I was wondering if it were possible to use mod in the thread-last macro? For instance, I can do:
(->>
  [132 132]
  (reduce +)
  (= 264)) => true
But mod doesn’t seem to work that way. Is that truee?

alpox18:08:06

@skendrick366 Thread last would put 264 as last argument so you would end up with (mod 11 264) You can use an anonymous function in the threading though: #(mod % 11)

eval-on-point18:08:33

I have a spec that uses a generator referred from another library for testing. Is there a simple way to disclude the generator from our production build (short of having a test-spec and prod-spec for the same entity) so that we can use spec for validation without having to pull in the generator's dependency?

hiredman20:08:07

you can dynamically load the generator from the other library

hiredman20:08:03

you set the generator to be something like (fn [] ((resolving-require 'some.other.lib.namespace/generator))))

hiredman20:08:14

I forget if it is resolving-require or requiring-resolve

noisesmith20:08:10

the way I remember it is if the verb were require, the thing to resolve would be ambiguous or undecidable

noisesmith20:08:30

when the verb is resolve, the rest is trivial to determine

Justin Roche21:08:28

does anybody do tutoring here? I am confused about the build chain for a template.

nando23:08:05

I'm trying to work out how to wrap a common layout around page content using hiccup and don't understand what I'm doing wrong. A working example would really help, but I haven't found one yet. Here are stripped down versions of the handler functions.

(ns telo.request-handler
  (:require [ring.util.response :refer [response]]
            [hiccup.core :refer [html]]
            [hiccup.page :refer [html5 include-js include-css]]
            [hiccup.element :refer [link-to]])

(defn layout
  [content]
  (html5
   [:head]
   [:body
    content
    ]))

(defn home
  [request]
  (response
   (layout[(html [:div.container
                  [:h1.display3 "Hello there!"]])
                         ])))
Here's the html this is returning, the intended content is missing:

<html><head></head><body><></></body></html>