This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-05
Channels
- # babashka (1)
- # beginners (75)
- # clojure (8)
- # clojure-uk (7)
- # clojurescript (14)
- # code-reviews (6)
- # conjure (5)
- # cursive (13)
- # data-science (1)
- # datomic (46)
- # fulcro (10)
- # helix (15)
- # jackdaw (1)
- # jobs-discuss (10)
- # jobs-rus (1)
- # off-topic (17)
- # pathom (1)
- # re-frame (19)
- # releases (1)
- # spacemacs (9)
- # sql (29)
- # test-check (18)
- # tools-deps (6)
- # xtdb (3)
https://youtu.be/75U3W8Y2zzw?t=270
I was recently watching @seancorfield 's talk named "Real World Clojure Doing Boring Stuff With An Exciting Language Sean Corfield" and the part where he talks about how they do deployment just blew my mind(in a good way). The quote starts at ~ 4:30:
> We had to go down :gen-class
for a couple of things.
> We have tried where possible to do everything through clojure.lang.RT
.
> So we essentially load up all of the namespaces we're going to expose into our code dynamically.
> And just let Clojure get on with it. That has the benefit that we can reload the application without the downtime and it just picks up any new Clojure code and recompiles it. So we can do deployments very easily
Sounds like a really neat way of doing zero-downtime deployments(if I got it right). I couldn't find much info on clojure.lang.RT
or any examples of how people do it. Any hints to get me unstuck are greatly appreciated.
these days clojure.java.api
is preferred https://clojure.org/reference/java_interop#_calling_clojure_from_java
an example of usage here https://github.com/noisesmith/clj-jsvc-adapter/blob/master/src/java/org/noisesmith/Cljsvc.java - there's not too much to get, you use require
to make a namespace load, and var
to get a function or value out of that namespace
thanks I'll check it out. Although I'm not sure how it is related to the question. I don't need to call Clojure from other JVM languages. It is all Clojure
one approach I guess would be to use var
to pull in clojure.core/load-file
which explicitly pulls in new code from that file
oh, I don't know why you'd need clojure.lang.RT then either, just use load-file
so it's like, update your source code to a new git tag/branch, connect to existing repl process.
Build a list of all files/namespaces and clojure.core/load-file
them all? It is oversimplified, just trying to understand the workflow
if it's an entire source tree, already on your running classpath, just call (require 'some.ns :reload-all)
on the top-level ns
I don't know how one would handle deps with a system like this though - Sean hangs out here a lot so he probably has more insight
@U0113AVHL2W That's an old talk, based on using an old version of Clojure. We switched to the newer clojure.java.api
once it appeared and nowadays we use (the undocumented) serialized-require
from 1.10 so require operations are thread-safe.
It's also worth noting that we're loading Clojure into a ColdFusion (CFML) app -- which is why we're using this API in the first place.
(and we started doing this back in 2011 -- and we still have a couple of small CFML apps in production that have not yet been rewritten in Clojure so we're still doing this a bit: everything else got rewritten over that time)
I've been trying to use expectations/clojure-test``. Am I understanding it correctly, and expectations can only test for equality. Say I want to test if something is >= 10:
(defexpect digit-test
(expect >= 5 (+ 1 9)))
This doesn't work. I can do it in clojure.test with:
(deftest addition-test
(is (>= 4 (+ 1 9))))
I know I can fall back to using deftest - just checking I've understood correctly that Expectations only handles testing equality.@UTQEPUEH4 ah yes, 'expect true' definitely works - thank-you.
I have a data structure that looks like {:last_insert_id() 1}
. I've tried ((symbol ":last_insert_id()) my-structure)
and (get-in my-structure [(symbol ":last_insert_id()")])
. But I'm getting nil for both of those. How can I extract this value?
if you are using get-in
anyway, you could skip whatever step turns last_insert_id() into a keyword and just use strings
Oops. I figured it out. I was using (symbol)
instead of (keyword)
hey team, i have a v annoying bug with mailgun, where messages they send seems to be an incorrectly formatted string.
"<html><head></head><body><div dir=\"ltr\">đŸ“ this is an example response!</div><br></body></html>"
đŸ“`` is supposed to be an emoji. If ya'll have some insights, on if there's a way I can fix this on my end, would love thoughts!
Initially thought if I can guess w/e encoding this is, I can fix it -- but had no luck so far
ā¢ i.e:
(slurp (.getBytes x "utf-8") :encoding "iso-8859-1")
That ampersant indicates that the thing following is a so called html entity. For example, a <
can obviously not be part of the content of a HTML document (its used for tags, after all), so there is a special syntax, <
, indicating a less-than sign as part of the content.
That said, the sequence you are posting doesnāt make much sense: https://mothereff.in/html-entities#%C4%91%C5%B8%C2%8F%E2%80%9C
I see, thanks for the context. I guess their parser may be bungling something up. It is supposed to be :table_tennis_paddle_and_ball:
Yeah, so that same website is saying that that could be escaped as 🏓
Wait, that does seem to be the emoji I want. Mind explaining to me how the website is saying that? (If there's some fn I can run to escape it into the html, that would be great!)
;;:table_tennis_paddle_and_ball: ;;table tennis bat and ball ;;Unicode: U+1F3D3, UTF-8: F0 9F 8F 93 (String. (byte-array [240 159 143 147]))
For some reason the first entity in your sample is 273 (hex 111) and not 240 (F0) as the table tennis bat should have. I'm mystified to this part of it. What otherwise seems to have happened is that an UTF-8 byte stream has been treated as (some) 8-bit character set (say iso-latin-1) when rendered to html causing the incorrect entity encoding, as the encoding for a html page without any charset specification is today considered to be utf-8, 🏓 is afiact the correct entity representation. The given 273 159 143 147 the entity encoding for the separate bytes in the utf-8 entity, as the small code snippet I posted shows.
Indeed this off-by-one error looks v wacky. Okay, for now will stick with a hack -- maybe mailgun will get back with something too
I've recently noticed that I'm starting to get less helpful error messages, as they don't tell me the Clojure file where the error occurred -- rather it's in some deeply tested temp directory. Any idea why it would do this? (Did I bork myself by adding (:gen-class) somehow?)
e.g.,
Syntax error compiling at (/private/var/folders/rk/0qy1s9bj16n265fq48k0_z3h0000gn/T/form-init4186707578230173306.clj:1:125).
I'm pretty sure I remember seeing it call out specific .clj files a few days/hours ago. (IntelliJ 2020.1, Cursive 1.9.2-2020.1)
Do you get the same if you re-evaluate the entire file (load file in repl menu) or runs sync files in repl before evaluating the expression?
It is happening when I go from a stopped REPL and completely restart the REPL. Happens even after a lein clean.
the initial load doesn't use your real file, I typically solve this by not using the init-ns
feature, and doing a normal require
in the repl
after the initial load, it's not lein loading the files, it's clojure, so you get the correct and helpful behavior
So, putting the 'beginner' in the #beginners channel... In IntelliJ, I click on the Run REPL button. And from that clean start, I get a syntax error, but then immediately a Process finished with exit code 1, No nREPL ack received -- and the REPL isn't running. Additionally, I'm not using init-ns. I'm just trying to get the code to compile first and then start the REPL. (you may be thinking I'm further along than I am)
there's no such thing as compiling before running the REPL, clojure's repl is the compiler
there is an Nrepl server (separate from the default repl) and a compile
(which is optional, used in deployment, puts byte-code on disk)
but for normal interaction the repl is the compiler
the thing that's more reliable for iterated development is to turn off the project.clj
:init-ns
config - it wouldn't be trying to load any of your code if that wasn't set
though if the process exits 1 before your repl starts, that could mean an error in compiling your project.clj itself
The light bulb is slowly coming on -- what's the difference between the REPL and nREPL server? ...checking the project.cli. (fyi, that's still a little bit of black magic DSL I haven't fully groked yet)
do you mind sharing the file?
to see the docs for the project config you can run lein help sample
it's a data literal that tells lein how to resolve your deps, and how to run your code
Actually, I think you've just nailed it on several fronts. Making a note about the lein sample. I appear to have told you wrong, as I though the (init-ns) was done from the REPL or in my code. Turns out, found this in the project.clj file.
:repl-options {:init-ns myproject.core}
I suspect I copied that from some helpful website.
What exactly is that doing? (I now feel I should remove it.)it's a convenience that loads your ns on startup
I don't like it because it points to a weird tmp file instead of your actual source of your problem
Ah, so I'm sitting in "user" by default, and this puts me in my application's name space....
and puts your repl in a bad state (or could even crash it), rather than letting you debug and move forward
Just comment that out?
right - that config asks that your namespace be loaded up, and for your repl to switch there before you get your prompt
Let me reintroduce the syntax error and see if I can trigger it.
(and import the changes <facepalm/>)
IT WORKED! Thank you so much!!!!!!!!!!
btw import
exists, and is only for java classes, for clojure code you want require
specifically in interactive dev you would use (require 'my.ns :reload)
though there's probably a plugin in your IDE that does that behind the scenes for you
I knew I'd seen the behaviour somewhere but didn't ever connect it with init-ns, good to know. In cursive I create a REPL command (Add New REPL Command) that syncs/loads namespaces which I bind to a convenient key. They can be set as project specific and run arbitrary repl commands.
Actually, I've bumped into both of those issues -- the first was when I tried to get at a real Java class outside the Clojure world.... The second was that I thought I was certainly doing something wrong stopping and restarting the REPL each time I made a minor change.... that require has been so helpful. Thank you again! (I'm trying a slightly larger project to force me into real-world problems and give me a little more practice at the language and the idioms.)
very cool - you'll see a pattern in my help that I try to steer people away from the things their tooling does and toward what clojure itself does - that just means I can help more people as I don't know all the tools
but if your tool works, cheers
Brilliant. That truly makes a lot of sense. I have this same concern with the other languages I'm more familiar with, in that it allows folks to code with an apparent competency higher than what they really have. And I just experienced it. The tooling was being helpful, but if something goes wrong, there's no way to know where to look if you're unfamiliar with all the inner workings. Thank you for helping to keep me honest.
@U051SS2EU I never knew :init-ns
had that quirk... one more reason to be glad I stopped using Leiningen years ago, I suppose š
I'll have to go dig in Leiningen to understand why tho', unless you can explain?
@seancorfield -- what do you use instead of lein; is there some better tooling I should be aware of, are are you hardcore old-schooling it?
I switched from Leiningen to Boot back in 2015 and then to the (new at the time) Clojure CLI / deps.edn
in 2018.
We have 100,000 lines of Clojure at work that we manage with clojure
and deps.edn
and a handful of simple tools.
I think the big picture explanation is that in order to implement the lein options that require start up code in the target vm, they decided to put all the code in a single external file. init-ns
is the most frequently used of those options (and the one that most frequently leads to obfuscated errors, as it's pulling in your own code but obfuscating the source of the error)
This? https://github.com/technomancy/leiningen/blob/master/src/leiningen/repl.clj#L147 š
hihi all š What's the equivalent of this in clojure using :gen-class
?
public class HandlerCloudFront implements RequestHandler<CloudFrontEvent, String>{
Since RequestHandler
is an interface, you could just reify
it, depending on what you're trying to do.