This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-27
Channels
- # aws (3)
- # aws-lambda (8)
- # bangalore-clj (1)
- # beginners (155)
- # boot (13)
- # cider (88)
- # cljs-dev (3)
- # cljsrn (9)
- # clojure (120)
- # clojure-india (1)
- # clojure-italy (2)
- # clojure-norway (1)
- # clojure-romania (2)
- # clojure-russia (41)
- # clojure-spec (4)
- # clojure-uk (34)
- # clojurescript (68)
- # core-logic (16)
- # cursive (11)
- # data-science (9)
- # datomic (19)
- # dirac (6)
- # duct (20)
- # emacs (7)
- # events (2)
- # figwheel (4)
- # fulcro (12)
- # graphql (1)
- # hoplon (68)
- # klipse (1)
- # leiningen (7)
- # lumo (11)
- # off-topic (9)
- # onyx (114)
- # pedestal (4)
- # protorepl (15)
- # re-frame (60)
- # reagent (3)
- # ring (18)
- # shadow-cljs (15)
- # spacemacs (82)
How do i represent a jodaTime object in my code for a test? If i just put the #object...
i get an error about a tag literal reader.
put another way, if i eval the code and use the output in my test then i get an error. #object[org.joda.time.DateTime 0x2b69f59 "0085-04-07T00:00:00.000Z"]
isn't something i can read back into the repl.
@drewverlee Are you wanting to use joda time directly or are you using clj-time?
I'm just calling functions in the clj-time namespace. i haven't had to do more then that to get the functionality i want.
That's all I've ever needed too - I'm away from the computer, but I think you can use the isequal method and compare your object against another that your test creates. Is that along the lines of what you wanted?
oh, yea. that makes perfect sense
This is what i get for trying to work while half asleep.
If you're using the before and after comparisons, one is inclusive and one is exclusive - it totally messes me up if I forget. Good to see you on here too, it was fun hanging out at he conj!
Likewise š
@drewverlee I'm one of the clj-time maintainers so let me know if there are specific questions I can help with...
(at work we're in the process of migrating to clojure.java-time
which is a nice, thin wrapper around Java Time introduced in Java 8)
Whatās the most straight forward way to print whatever is coming in or out of a function? or in between forms?
Say I just want to know whats passing in between somewhere as quickly and with as less modifications to de code as possible
I.e. Whatās the output of edn/read-string in the following snippet?
(def app-schema
(-> "src/get_it_right/schema.edn"
slurp
edn/read-string
(attach-resolvers {:get-product get-product
:get-products get-products
:get-product-price-history get-product-price-history
:scrape-products scrape-products
:signin signin
:signup signup
:signout signout
:request-password-reset request-password-reset
:reset-password reset-password})
schema/compile))
But also whathever the one function returns here:
(defn signup
[_ctx {:keys [email password]} _val]
(one pool (user/create-user
{:email email
:password password})))
For the first one I guess I could do:
slurp
edn/read-string
(doto prn)
....
But what if I want to print the value along with a label to stdout? like "look here: " val
(doto (#(prn "here: " %)))
is no longer as succint
Is there anything closer to elixirās inspect (https://hexdocs.pm/elixir/IO.html#inspect/2) in the standard library?
I.e. Take a value, print it to stdout with an optional label and return that same value unchanged?
Something like:
slurp
edn/read-string
( inspect "here:") -- Takes the output of edn/read-string, prints it to stdout after "here: " and passes it along.
I just went through the trouble of setting up sayid out of frustration
VERY impressed, best debugging experience Iāve had in my life.
is there a way I can extract source information from data passed into a macro and use it to provide helpful error messages pointing at the offending expression?
See for example https://stackoverflow.com/questions/30812123/clojure-how-do-i-get-the-file-line-number-on-which-a-map-was-defined
if the solution is a macro, you need the compiler for it
maybe Iām misreading that
hey again guys !
finally Iāve setup my application to use components ( thanks @noisesmith )
removed the lein-ring and runnin gmy application from REPL (go)
after I call (go)
my components boots up and the web-server as well ( web-server is one compoent ) and blocks my REPL ( waiting for request)
how you guys normally does ? create a new system without web-server for the REPL ?
typically Iād put the web server process in a future, and attach that future to the component
@oliv depending on which server you are using, there is likely an optional argument to run in the background
but more generally, if a component needs something to continue running, attaching a future to the component (then making sure it exits and cleans up when stopped) is the thing to do
sounds interesting the future approach ( pretty sure I have to study a little more to be able execute with future )
and how is your workflow, every time you change the source code you (stop) / (start) the components again ?
future is pretty easy - change (f)
to (future (f))
- the biggest gotcha is that if it throws, you donāt see the error until something tries to dereference the future
run-jetty
definitely has an option for running in the background (run-jetty ... :join? false)
https://ring-clojure.github.io/ring/ring.adapter.jetty.html
some code doesnāt require a stop/start but that cycle should be short enough that it doesnāt matter much
Cool, so regarding the star / stop cycle, supposing I'm changing some function on my handler , eventually I will want to restart the server to test my fix
Do you do it manually or something else is listening for changes and restart the components to you ?
either can happen, but thereās nothing doing that automatically by default - I restart by hand after reloading my code
also, a common trick is to pass the var for your handler to the server process, rather than the handler function itself - this ensures that the var is freshly looked up and dereferenced each time it is called. But this is incompatible with clojure.tools.namespace/refresh which deletes vars from namespaces and makes new ones
Releasing my repl , thank you for your time , let me know if you have any place for donation :)
I'm using the refresh , I confess I did not understand very well the var for your handler ...
#'handler
is the var that contains handler
if you call it, it calls handler after looking it up
if you call (run-jetty handler ā¦) it looks up handler once, and then jetty just uses that
if you call (run-jetty #āhandler ā¦) it uses the var, which means it looks up the current value every time, which means it sees the new definition if you redefine it
@oliv perhaps this helps
(ins)user=> (defn do-foo [] :old-value)
#'user/do-foo
(ins)user=> (defn capture [f] (fn [] (f)))
#'user/capture
(ins)user=> (def f1 (capture do-foo))
#'user/f1
(ins)user=> (def f2 (capture #'do-foo))
#'user/f2
(ins)user=> (f1)
:old-value
(ins)user=> (f2)
:old-value
(ins)user=> (defn do-foo [] :new-value)
#'user/do-foo
(ins)user=> (f1)
:old-value
(ins)user=> (f2)
:new-value
the difference between capturing do-foo
vs. #'do-foo
Hello all, I am trying to get Leiningen
set up on Fedora and I am having issues. Have been following the install instructions and they don't seem to be working for me. Could someone please help me? If Leiningen
was on rpm
this would be much easier as well, but it doesn't seem to be.
Whatās the problem?
I am having issues running the script. Do I save the script with lein.sh
, or simply lein
?
lein
is the shell script - it installs everything else
Easiest if you save the script as lein
I usually save mine to ~/bin/lein
also you need to set it to be executable
thatās a weird place to put it - /bin is typically for system level stuff
Ok, you might have some permissions issues if you put it there.
Itās better in ~/bin
, then you donāt have to use sudo for updates and such
https://leiningen.org/
on their page they suggest a place like ~/bin
which is drastically different from /bin
most idiomatic on a *nix system would be to put it in /usr/local/bin or an individual userās ~/bin/
but of course you have to have ~/bin
in your PATH
sadly on OSX there are system level tools that mess with /usr/local/bin which is totally wrong - but no such problem on fedora
@adamfranzen Yes, ~/bin
means you make a bin
directory in your home dir.
and thereās also some setup you need to do to make sure your $PATH contains ~/bin
it belongs to root
only the package manager should be putting things there or removing things from it
that's why it's not a great place to put something there. it's very near and dear to your system
right, you shouldnāt be doing that
Thatās good because you donāt want to do that
You need the tilde in front of the /bin
mv ~/Downloads/lein ~/bin
~/bin is a shell syntax that expands to $HOME/bin/
that may have sounded condescending and i really don't mean it that way. but feel free to ask about a command before you run it if you like
~bin mv ~/Downloads/lein ~/bin
mv: cannot stat '/home/afran/Downloads/lein': No such file or directory
mkdir ~/bin
Oh wait, it canāt find your downloaded file
it probably downloaded as lein.sh or leiningen or something
you can use ls to see what is in ~/Downloads
Hi, Iām using https://github.com/ring-clojure/ring, the request headers are lowercase, but thatās okey, but seems like the response are lowercase as well, is there anyway to change that? a middleware or something?
Iāve used ring for years and this has never been a problem - what specifically is going wrong?
if nothing else you can explicitly return a hash-map {:headers {.. ...} :status ... :body ...}
it should merge any headers under that key into the response
I do that
(defn- handler [request]
(let [response (rfour/request (slurp (:body request))
(settings [:rabbitmq :exchange :topic])
(path->rk (request :uri))
:headers (merge {"w-path" (path-rstrip (request :uri))
"w-method" (string/upper-case (name (request :request-method)))
"w-query" (request :query-string)
"w-segments-length" (-> (request :uri) (path-strip) (path-segments) (count))}
(-> (request :uri) (path-strip) (path-segments) (request-segments))
(-> (request :headers) (request-headers))))]
(println (response-headers (@response :headers)))
{:status (response-status request @response)
:headers (response-headers (@response :headers))
:body (apply str (map char (@response :body)))}))
The print
{Content-Type application/json}
The response at postman
content-length ā76
content-type āapplication/json
date āFri, 27 Oct 2017 19:04:53 GMT
server āJetty(9.2.21.v20170120)
There are some clientes (at least in Brazil) who is very boring about those kind of things
> Each header field consists of a case-insensitive field name followed > by a colon (":"), optional leading whitespace, the field value, and > optional trailing whitespace.
#'handler` is the var that contains `handler`
if you call it, it calls handler after looking it up
if you call (run-jetty handler ā¦) it looks up handler once, and then jetty just uses that
if you call (run-jetty #'handler ā¦) it uses the var, which means it looks up the current value every time, which means it sees the new definition if you redefine it
@noisesmith thank you again , mind blowing !!!
I thought handler
was the symbol which points to the Var #'handler
which points to the value ( the function )right - but the question is when (how often) that lookup is done
handler is looked up once (if provided as an arument) or every time (if compiled into a form)
#āhandler is looked up every time, period
one requirement of my system is to be able to trace the request among multiple requests. to accomplish that Iām tracing all the requests that comes in, every endpoints is checking if there is something in the header X-Tracing-Id , otherwise must create one. All the logs into my system must be logged with the traceId on it.
to do that tracing part, Iām creating one middleware (defn tracing [handler] ā¦ ) that will be responsible for get or create the tracing id. after that Iām assoc
into the request.
(defn tracing [{:keys [headers]}]
(update-in headers [:x-tracing-id]
(fnil identity (.toString (java.util.UUID/randomUUID)))))
(defn mw-tracing [handler]
(fn [request]
(handler (tracing request)))
that is fine, works great ! my request will be assoced with the tracing-id or a new one.
what really bother me is the coupling that Iām building. the request map is containing everything I need, and all my functions are receiving that huge map
right now I have
* my components ( :db, :aws-clients, :rabbit-mq-client, :redis-client ) ( should the log be a component ? )
* my tracing id
* logged user ( if is a logged user or anonymous )
and the list will grow and grow
My service layer - or handler layer
is receiving the request and destructuring what needs , is the correct way to build clojure systems ?
how you guys are building your systems ?Remember that Clojure favors open data -- so having keys in a map that a particular function ignores is fine. Each function can just destructure the keys it cares about out of the incoming map. If it calls downstream functions that need the map, pass the whole map (so lower-level dependencies can extract whatever they need from the map without intermediate functions caring about those things).
Since the map is immutable and persistent, it's not like you're copying it as you pass it around so there's no performance or memory overhead by having it contain more things (beyond the once-per-request needing to add those things into the request).
I see ! @seancorfield, regarding the log + tracing, how would you handle that ? my logging is a singleton ( clojure.tools.logging ), should I downstream to all my functions the x-tracing-id and use it on my (log/info ā¦) calls ?
I might consider having your tracing middleware create a new key for the tracing id rather than inserting one into the headers map
maybe something like
(defn tracing [{:keys [headers] :as req}]
(assoc req
:tracing-id (if (contains? headers :x-tracing-id)
(:x-tracing-id headers)
(.toString (java.util.UUID/randomUUID)))))
the reasons being 1) middleware or request handlers that want to generically do something with headers will now have a header field that wasnāt part of the actual request
(headers :x-tracing-id (UUID/randomUUID)
can replace that if
2) if at some point you want to figure out tracing ids some other way, you can do that transparently
for eg, you want to use headers when someone is logged in, but maybe use GET parameters for testing or something
although, depending on how much your system grows, it may not actually ever matter
@noisesmith, would that create a UUID, regardless of whether you need it?
yes - but thatās relatively cheap
also, using namespaced keywords sounds like a neat idea, but I havenāt tried it
about a 10th of an ms
so, we have the request assoced with :x-tracing-id , all my functions ( business logic ) must receive somehow the x-tracing-id because we must logged it. is that the way you build your system ?
if you have an id but it might be brand new, it might make sense to both have the effective id (there whether itās new or not) and a boolean indicating whether the request had one coming in
Is it considered good practice to catch an exception in a low-level namespace (e.g. Catch unique constraint exception in db namespace) and rethrow it as a custom domain exception (e.g. username-already-taken) that your route handlers can understand and present to the user?
exception/failure is always a recurrent problem to me, no matter language Iām working on. what I like to do is capture the exception on lower level and always returns one āobjectā that represents the operation Etiher success or Failure. The caller must check if the operation performed properly or not
Iām using dire: https://github.com/MichaelDrogalis/dire to avoid having try-catch blocks all over and also avoid having to check for success/failure of multiple operations
So I would register a handler for my db query function that would catch the PGSQLException and retrow it as a custom exception
my route-handler would have another handler that catches the custom exception and returns a useful error-map to the client
Re: creating the UUID each time, there's always (or (headers "x-tracing-id") (java.util.UUID/randomUUID))
-- and if I'm not mistaken, aren't Ring headers keyed as strings, not keywords?
@oliv the problem with this is there is no general way to prevent all throws, so introducing something other than try/catch means you have two systems to deal with
the only way to have one consistent system for handling failures is to use try/catch and throw
Where you have "expected exceptions" (oh, that there is such a thing!), then it's reasonable to catch them locally and turn them into something else -- but if they're expected then that should flow into regular error handling that you expect to provide to your end users.
Where you have "unexpected exceptions" (where they are truly exceptional) then letting them propagate and logging them at the top level with a "Sorry, an unexpected problem occurred with your request!" end user message is reasonable.
With databases, we've gotten used to relying on constraint violations throwing exceptions when those are often expected failures, not truly exceptions.
It's like throwing an exception on end of file -- of course there's going to be an end of file: that's not exceptional! Hitting EOF before reading a complete/valid form... OK, that might be considered exceptional depending on who controls the file format. (user-supplied, definitely should be expected; system-generated, yeah, throw an exception).
@noisesmith you are right. for that cases I have a global middleware to handle uncaught exceptions. so how you do then ? where are you handling the exceptions ? you have specific handlers for your exceptions ?
my experience with co-workers trying to provide some other systems for handling exceptional but recoverable conditions is that we end up with a multiplicity of success / failure tracking subsystems and the diversity makes it easy to mishandle them, with problems including failing to abort on error states (resulting in garbage or data corruption), hiding of failures so that only downstream symptoms are visible (which makes debugging harder)
Yes! āļø:skin-tone-2:
The two places to catch an exception are: 1) right at the source if you can do something useful about it 2) right at the top level where you can log it and apologize.
(note: the "source" is defined by module or system boundaries in reality so it moves around a bit)
Iāve literally seen: a) letās handle this error state by logging an error then moving on b) Iām tired of all this noise in the logs Iām removing the error logging clause c) something is wrong we have no idea what there are no symptoms other than the task failing or returning garbage - when you see the sequence all in one place itās comical, but as an interaction between code authors itās an easy state to end up in
also, on some level the correlation between misbehaviors and exception handling is kind of like the correlation between hospitals and mortality - itās the nature of the thing that a lot of things going wrong are going to interact with your exception handling system, this doesnāt mean the exception handling is at fault
So I should catch the constraint exceptions that are related to my buisness logic at/near-to my query executor function (i.e. duplicate email/username) and let other exceptions unexpected exeptions bubble up to be logged?
That is probably closest to the approach I generally take, yes, @juanjo.lenero