(reduce (fn [xs i] (conj xs i)) () (range 6))
always use an initial value. otherwise reduce uses the first value of the collection for the accumulator
Everyday I learn new things from reading #beginners
If you do a get request it works correctly though?
yep
Very odd, don't think I can guess an answer
I'm guessing the indentation is wrong? I think you need to give create-default-handler
as the second parameter to ring-handler
perhaps?
@lasse.maatta apologies for the late reply. Yes, it was in the wrong position
create-resource-handler
too
(def handler
(reitit/routes
(reitit/create-resource-handler
{:path "/resources/"})
(reitit/ring-handler
(reitit/router routes)
(reitit/create-default-handler
{:not-found
(constantly (response/not-found "404 - Not Found"))
:method-not-allowed
(constantly (response/method-not-allowed "405 - Method not allowed"))
:not-acceptable
(constantly (response/not-acceptable "406 - Not acceptable"))}))))
this way it works, thanks 👍
wrt. https://github.com/metosin/reitit/blob/master/doc/ring/default_handler.md
Hi, I want to pass the PersistentVector to Clojure as a parameter when I invoke it from Java. How to do that?
PersistentVector fiedls = PersistentVector.create(Keyword.intern(null, "d"));
mergeSelect.invoke(m, fiedls);
(defn ms [m fields]
(println (-> m (merge-select fields) sql/format)))
Thank you first, But I wonder why cannot use class of Clojure in Java? And I saw some project using it directly.
As a concrete class, it’s considered part of Clojure’s internals
the official Java API for invoking Clojure is the clojure.java.api.Clojure class. https://clojure.github.io/clojure/javadoc/clojure/java/api/Clojure.html
Thank you again.
Can macro be recursive?
made another version https://github.com/reflechant/binary-pow/blob/main/src/binary_pow/core.clj
yes
(defmacro rec-example [n]
(when (not= n 0)
`(do ~n (rec-example ~(dec n)))))
as an examplethanks!
Look what I did:
(defn square [x]
(* x x))
(defmacro pow [x n]
(cond (zero? n) 1
(even? n) `(square (pow ~x ~(/ n 2)))
:else `(* ~x (pow ~x ~(dec n)))))
it's Newton-Raphson fast exponentiation
but why macro?
looks good btw
classic algorithm is not tail-recursive and I couldn't write a tail-recursive version for some time
but it's possible
but I think a more elegant way would be to generate a sequence (lazy?) of numbers to multiply and then just reduce *
no, actually it needs to be some kind of a stack to have logarithmic number of multiplications
basically we square x and then optionally multiply once by x
@gr.evocatus The caveat to your macro version is that it will work only with numbers. For example, the following will fail:
(def x 2)
(def n 7)
(pow x n) ;; will blow up
Here's the same thing as a function, and a macro on top optimising some very simple cases:
(defn pow-fn [x n]
(loop [base x
prod 1
exp n]
(if (zero? exp)
prod
(recur
(* base base)
(if (even? exp)
prod
(* prod base))
(quot exp 2)))))
(defmacro pow [x n]
(cond (zero? n) 1
(= x 1) 1
(zero? n) 0
(= n 1) x
(= n 2) `(let [x# ~x] (* x# x#))
:else `(pow-fn ~x ~n)))
This way, if the base or the exponent is 0 or 1 (the literal), evaluation happens at compile time. Similarly, if the exponent is the literal 2, then it macroexpands into a multiplication (with let
used so that any side effects only happen once).
For example, check out (macroexpand '(pow 3 2))
Great! But I believe you mistyped in the macro. Third line in cond form should be (zero? x) 0
Oops! Good catch.
Hello 🙂. Following the “Living Clojure” I’ve ran into another issue that I’m unable to resolve. I am setting up clojurescript in my project and I was asked to run lein trampoline cljsbuild repl-rhino
in my project root. It downloaded bunch of things and then failed when trying to build (I suppose?)
Exception in thread "main" Syntax error compiling at (cljsbuild/repl/rhino.clj:1:1).
.....
Caused by: java.io.FileNotFoundException: Could not locate cljs/repl/rhino__init.class, cljs/repl/rhino.clj or cljs/repl/rhino.cljc on classpath.
does rhino have to be added as one of dependencies/plugins? My deps look like that
:dependencies [[org.clojure/clojure "1.10.0"]
[compojure "1.6.1"]
[ring/ring-defaults "0.3.2"]
[ring/ring-json "0.5.0"]
[org.clojure/clojurescript "1.10.764"]]
Sorry, I haven’t noticed your answer. Thanks for looking into my problem!
If I have something like
(vector (* 2 (range 1 100)))
Will the calculation of this will be done in parallel? I don't know how to pose the question. I want want to know, if I have to put in special measures to make clojure use the full potential of my machine with multiple threads, cores and cpus?I am getting some strange error from compojure, must be something silly. Here is my code:
(defn splash []
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello from Heroku"})
(defroutes app []
(GET "/" [] splash)
(ANY "*" []
(route/not-found (slurp (io/resource "404.html")))))
(defn -main [& [port]]
; (setup-state)
(let [port (Integer. (or port (env :port) 5000))]
(jetty/run-jetty (site #'app) {:port port :join? false})))
And output from terminal:
➜ clojure-getting-started git:(main) ✗ lein run
2021-01-18 13:51:54.389:INFO::main: Logging initialized @3562ms to org.eclipse.jetty.util.log.StdErrLog
2021-01-18 13:51:54.802:INFO:oejs.Server:main: jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 11.0.7+10
2021-01-18 13:51:54.865:INFO:oejs.AbstractConnector:main: Started ServerConnector@6432fa28{HTTP/1.1,[http/1.1]}{0.0.0.0:5000}
2021-01-18 13:51:54.865:INFO:oejs.Server:main: Started @4039ms
2021-01-18 13:52:05.203:WARN:oejs.HttpChannel:qtp197080602-17: /
java.lang.IllegalArgumentException: Key must be integer
at clojure.lang.APersistentVector.invoke(APersistentVector.java:294)
at compojure.core$routing$fn__2329.invoke(core.clj:185)
at clojure.core$some.invokeStatic(core.clj:2701)
at clojure.core$some.invoke(core.clj:2692)
Do not kmow if this is the right channel but if there is here a exercism mentor can he/she look at my bob challenge . I almost wait for a week for mentoring
Hello everyone! I'm new here. Could anyone recommend any tutorial on how to publish a VERY simple web service on any cheap server using Clojure. F.E.. I have done one locally using Ring and some other libraries and I can return json as a response (this one https://github.com/anan44/it-starts-with-clojure). So it works in local server, but I want to apply it globally. Basically I just want expose a simple API (no need for Database or such). I am very uneducated in web-programming and Clojure (I'm a mathematician), so my questions might not even make any sense (please don't get frustrated), but I do have some decent experience in coding OOP-languages generally.
Thanks a lot!! Yeah I am going to use Azure App Service later, but maybe the manual steps will help me to understand some of the magic of web-development.
I tried to deploy a very simple Api to Heroku, but the heroku instructions used compojure, and the tutorial I followed did not. I ran into lot's of difficulties. Currently the app crashes, and the stack trace shows the problem. There seems to be a syntax error in ring/util/servlet.clj:1:1 if I understand correctly. However I have not touched or even found the ring source code, so how can there be a syntax error? Is it likely that I am missing a depency? Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8 2021-01-24T12:54:12.831812+00:00 app[web.1]: Syntax error (ClassNotFoundException) compiling at (ring/util/servlet.clj:1:1). 2021-01-24T12:54:12.831836+00:00 app[web.1]: javax.servlet.AsyncContext
(ns mutable-app.web
`(:require`
`[ring.adapter.jetty :as jetty]`
`[environ.core :refer [env]]`
`[ring.middleware.params :as params]`
`[reitit.ring.middleware.muuntaja :as muuntaja]`
`[muuntaja.core :as m]`
`[reitit.ring.coercion :as coercion]`
`[reitit.ring :as ring]`
`[endpoints]))`
(def app
`(ring/ring-handler`
`(ring/router`
`[endpoints/math-routes]`
`{:data {:muuntaja m/instance`
`:middleware [params/wrap-params`
`muuntaja/format-middleware`
`coercion/coerce-exceptions-middleware`
`coercion/coerce-request-middleware`
`coercion/coerce-response-middleware]}})`
`(ring/create-default-handler)))`
(defn -main [& [port]]
`(let [port (Integer. (or port (env :port) 5000))]`
`(jetty/run-jetty #'app {:port port`
`:join? false})))`
(ns endpoints (:require [ring.util.http-response :as response]))
(def addition ["/addition" {:get (fn [request]
`(let [params (:query-params request)`
`x (Long/parseLong (get params "x"))`
`y (Long/parseLong (get params "y"))]`
`(response/ok {:total (+ x y)})))}])`
(def math-routes
`["/math"`
`addition])`
And the project file
(defproject mutable-app "1.0.0-SNAPSHOT"
`:description "FIXME: write description"`
`:url "http://mutable-app.herokuapp.com"`
`:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"`
`:url "https://www.eclipse.org/legal/epl-2.0/"}`
`:dependencies [[org.clojure/clojure "1.10.1"]`
`[ring "1.8.1"]`
`[metosin/reitit "0.4.2"]`
`[metosin/ring-http-response "0.9.1"]`
`[ring/ring-jetty-adapter "1.2.2"]`
`[ring/ring-devel "1.2.2"]`
`[environ "0.5.0"]]`
`:min-lein-version "2.0.0"`
`:plugins [[environ/environ.lein "0.2.1"]]`
`:uberjar-name "mutable-app-standalone.jar"`
`:profiles {`
`:production {:env {:production true}`
`:uberjar {:aot :all}}})`
And finally the procfile: web: java $JVM_OPTS -cp target/mutable-app-standalone.jar clojure.main -m mutable-app.web
There might be something bad with the dependencies - like version conflicts.
You can use lein deps :tree
to investigate that.
Also please include the whole stacktrace - you only pasted a very small portion of it.
Slack tip: Use tripe backticks for longer code blocks:
<your code here>
Heroku seems to be a good place to start.
The typical advice is to "build an uberjar" and "run it wherever you like". You can just spin up a virtual machine at any provider like AWS, Digital Ocean, Hetzner (quite limited but cheaper) - but it depends on what kind of project this is. Does it have to be always available? Is it just for you and/or friends or something more serious?
fairly certain it’s not done in parallel/concurrently
If you mean map
, then no, it will be applied sequentially:
(map #(do (print %) (* 2 %)) (range 1 10))
;; 123456789
;; => (2 4 6 8 10 12 14 16 18)
For simple cases of parallelization you could use pmap
ohhh today I was reminded of the existence of pmap
I suppose if you want to do truly concurrent stuff you could take a look at: https://clojure.org/about/concurrent_programming or Rich’s http://2.hr talk on the matter: https://www.youtube.com/watch?v=nDAfZK8m5_8
maybe even core.async, manifold, Java threads, etc… but that’s a bit overkill
you could also check out #code-reviews
Don’t call that - you should consider PV to be Clojure internals. Either use Clojure.read() to read a literal vector or obtain the vector function with Clojure.var() and .invoke() it.
Hi guys, i'm struggling to get out from this problem i have: I am trying to write a function to get from:
(let [data ([{:id 1 :client-data [{:tag "client data here"}]}
{:id 1 :document-data [{:tag "docs all around"}]}
{:id 1 :document-data [{:tag "docs here"}]}
{:id 1 :document-data [{:tag "docs there"}]}]
[{:id 2 :client-data [{:tag "client2 data here"}]}
{:id 2 :document-data [{:tag "docs2 all around"}]}
{:id 2 :document-data [{:tag "docs2 here"}]}
{:id 2 :document-data [{:tag "docs2 there"}]}])]
...........
)
a new set of data like this form:
{
{:client-data [{:tag "client data here"}]
:document-data [[{:tag "docs all around"}]
[{:tag "docs here"}]
[{:tag "docs there"}]]
{:client-data [{:tag "client2 data here"}]
:document-data [[{:tag "docs2 all around"}]
[{:tag "docs2 here"}]
[{:tag "docs2 there"}]]
}
Thanks@qmstuart hi, can u please write again your solutio, i would like to try it. Thanks
I realised after it was putting rogue nils in
Oh. Ok
(->> (apply concat data)
(group-by :id)
(mapv (fn [[_ x]]
{:client-data (:client-data (first x))
:document-data (->> (map (fn [i] (:document-data i)) x) (remove nil?))})))
It is just for learning purposes. I have built an uberjar, but the parts "run it wherever you want" and "spin up a virtual machine" are something, that I don't understand. Also in my current code I have specified a port for the server. I have no idea, what effect this has if I just "insert" the uberjar to some other environment than my own laptop. By the way. How do you paste code neatly here. I've seen others do it.
I don't expect anyone to answer all these questions, and was hoping there would be some tutorial project you could point me to.
Not a complete solution (+ should the result really be a map?), but something hopefully helpful:
(->>
[{:id 1 :client-data [{:tag "client data here"}]}
{:id 1 :document-data [{:tag "docs all around"}]}
{:id 1 :document-data [{:tag "docs here"}]}
{:id 1 :document-data [{:tag "docs there"}]}]
(map #(select-keys % [:client-data :document-data]))
(apply merge-with vector))
;; => {:client-data [{:tag "client data here"}],
;; :document-data
;; [[[{:tag "docs all around"}] [{:tag "docs here"}]] [{:tag "docs there"}]]}
You can make that last bit a little cleaner: (->> x (map :document-data) (remove nil?))
All tutorials that I have found which say "from start to the end - complete etc..." usually miss this part. I have found this "real" deployment -part somewhere else, but they have used some Visual Studio -machinery which basically hides the magic and prevent the understanding (although later on I would use them). I have written an application with VS-code and run it with Leiningen right now. It runs locally. Now I just want to make it so, that I can send the http-requests from the internet. I do believe "complete web-application" -tutorials should always include this part.
I'm sure there must be a way to do this with merge?
Thanks guys, i’ll check it when i’ll get back home
(def app
(ring/ring-handler
(ring/router
[endpoints/math-routes]
{:data {:muuntaja m/instance
:middleware [params/wrap-params
muuntaja/format-middleware
coercion/coerce-exceptions-middleware
coercion/coerce-request-middleware
coercion/coerce-response-middleware]}})
(ring/create-default-handler)))
(defonce running-server (atom nil))
(defn start
[]
(when (nil? @running-server)
(reset! running-server (jetty/run-jetty #'app {:port 3000
:join? false})))
(println "Server running in port 3000"))
merge-with is probably much more suited for this, but I’m a bit too lazy atm to draw up some code
This is the essential part. If I just build an uberjar, and "place it" to f.e. Azure App Service with some Azure -instructions, should it be ready to go then?
see above -- iianm something like (map (partial apply merge-with vector))
on grouped map values here should be close to what OP wanted
:thumbsup:
anyone who can give me a hint how I can make palingdrome checker that works for this case (true? (__ [:foo :bar :foo]))
is the thing equal to it in reverse?
I thought so but with this code #(= (clojure.string/join (reverse %) %)))
it fails
user> (defn palindrome? [thing] (= thing (reverse thing)))
#'user/palindrome?
user> (true? (palindrome? [:foo :bar :foo]))
true
Is that what you are looking for?string join operates on strings not lists; why do you need joining anyway? compare collections! https://clojure.org/guides/equality
nope, that one fails on a string
lets say I have "racecar"
when I reverse it , I get a collection of characters
and those two are not the same
https://clojuredocs.org/clojure.core/seq ponder on this thing
so I thought joining them will solve it , but not
ponder ?
tip: make the string a list not the list a string
oke, time to experiment more
(defn palindrome? [thing] (cond
(string? thing) (= (clojure.string/reverse thing) thing)
(seq? thing) (= (reverse thing) thing)
:else false))
One way. Probably not the best way.hi everyone 🙂
what does ^
mean in ^{key: "value"}
?
can be a lot shorter
#(= (reverse %) (seq %))
@claudius.nicolae @eamonn.sullivanThe ^
indicates that the map that follows is metadata that is associated with the thing that follows, where the thing that follows is usually a collection or symbol.
You can see read some more about it here if you wish: https://clojure.org/guides/weird_characters#_and_metadata
the rest of that page has lots of good description of other special syntax characters in Clojure
something similar:
(let [data '([{:id 1 :client-data [{:tag "client data here"}]}
{:id 1 :document-data [{:tag "docs all around"}]}
{:id 1 :document-data [{:tag "docs here"}]}
{:id 1 :document-data [{:tag "docs there"}]}]
[{:id 2 :client-data [{:tag "client2 data here"}]}
{:id 2 :document-data [{:tag "docs2 all around"}]}
{:id 2 :document-data [{:tag "docs2 here"}]}
{:id 2 :document-data [{:tag "docs2 there"}]}])]
(map
#(do {:client-data (some :client-data %)
:document-data (keep :document-data %)})
data))
I was mainly interested in knowing how much concurrency is applied automatically behind the scenes
Thanks for the link, I'll take a look
I don't think concurrency/parallelization can be applied behind the scenes as long as we allow for functions with side effects. Unless of course we never want determinism guarantees 🙂 But even then, I'd be surprised if performance would not soon become a problem in behind-the-scenes-auto-parallelized computations (but happy to be shown otherwise)..
@qmstuart @dstephens thank you guys for your time, Daniel's solution works better
Yes, you should.
THe cloud offerings are vastly different.
One way is to:
1. register an account at AWS / Digital Ocean / Hetzner / whatever
2. Create a machine from a template (e.g. Ubuntu version x.y)
3. SSH into the machine
4. Build your uberjar
5. Copy the uberjar to the machine
6. Run it via java -jar my-uberjar.jar
7. Make sure to expose the port on the instance firewall (e.g. AWS uses "Security groups" for that)
8. Check if you can access it
This is of course a lot of manual work so for anything more serious you want to improve and consider other offerings. One option is to have Azure App Service where you can define a dockerfile to run your service (it can be a really simple wrapper around the uberjar)
Hi! I'd like to know what's the best practice when using a library that is not an explicit dependency but transitive of an already declared dep. Should I make it explicit adding it to the list of dependencies?
For example, taoensso.timbre
depends on taoensso.encore
. I'd like to use taoensso.encore/filter-kvs
on my project. I did clj -Stree
to list the dependency tree. Now to make the dependency explicit I added taoensso.encore
to the list of :exclusions
of timbre and then added taoensso.encore
in a new line. I used to do this on leiningen, but I'm not completely sure this translates 1 to 1 to clj deps. Hope I'm not missing something here 😅
It is better to explicitly declare all dependencies. For example taoensso.timbre
might remove taoensso.encore
from provided dependencies without changing its API. And your application suddenly will stop working. and this will nether be a case if your explicitly depend on it.
in clj cli top-level dependencies takes precedence over transitive one (if the version is higher). so you probably don’t need exclusions either. Only in rare cases when you need top-level dependency to have lower version than the one comming with another lib
Declare all deps that you explicitly use. Don’t declare deps that you don’t explicitly use (let them be selected as transitive deps).
That should be the general practice
The most common reason to diverge from that is if you are resolving a conflict between versions when the same transitive dep is included multiple times (either by declaring a top level dep/version or by using exclusions)
Is my assumption correct that the textual representation of keywords gets compiled away, which could have positive implications on performance over using strings in some cases?
no, a keyword is always backed by a string
The Clojure/Java implementation does store the string representing a keyword at most once for each keyword, whereas many strings with the same sequence of characters have no such guarantee (i.e. they might all be different JVM objects in memory for strings)
when keywords are compared, are the underlying strings compared for equality (and therefore each character in turn compared i guess) or is there a faster compare?
Clojure/Java uses reference (i.e. pointer) equality between keywords, identical?
. I think ClojureScript is different, but don't know the details.
When Clojure/Java reads a keyword, there is a hash lookup on the text of the keyword to see if there is already a keyword object with the same string, part of the process called 'interning', which guarantees that there is at most one JVM object for each keyword.
ok. so it would be the case that keywords could have positive implications on performance over using strings in some cases?
yes
yep
ah, your "no" was about the textual representation of keywords compiled away, not about the possibility of some positive performance gains
Thank you @andy.fingerhut, @bronsa and @dpsutton.
related (ClojureScript): https://ask.clojure.org/index.php/8539/why-are-keywords-not-cached-and-interned-in-clojurescript
Thank you so much both 😀, that's what I suspected but wanted to be sure. In this other case you mention Alex, is there any tool to check if there's such a conflict? Or will I get a warning from the cli? Or I need to keep an eye on the output of clj -Stree
each time I add a new library?
You won’t get any error or warning from the cli - it has no way to tell whether there is an issue and will generally just pick the newest version of the library. You might encounter issues at runtime if a newer version of a lib breaks backwards compatibility
In the Clojure community there is a culture of minimizing such changes so this is relatively uncommon
this seems kotlin related. does this have any tie to Clojure?
Ahh, alright. Yess, I think I only had trouble once with dependencies. Just realized https://github.com/SevereOverfl0w/vizns can help me here, it shows non-declared transitive deps as red nodes. I'll take a peep to that now. Thanks!!
I have similar condition in my script
(and (nil? cond1) (nil? cond2) (nil? cond3) )
can this be shortened ?
lets consider we have n number of nil? condition
(every? nil? [cond1 cond2 cond3])
this might change the semantics if you rely on short circuiting and side effects
oh nevermind. every
should be fine
are you saying every doesn't short circuit?
was thinking there might be some laziness underneath so it might run into chunking issues but just read the source
how laziness causes here?
use truthiness to your advantage (and cond1 cond2 cond3)
it doesn't. i was completely mistaken
it is more like (and (not cond1) (not cond2) (not cond3))
assuming you are fine treating nil
and false
the same, which can then be (not (or cond1 cond2 cond3))
Lesson learned there’s quite a few ways to do things. 😅
is there somewhere a example how to send data to a template with ring and compojure ?
so as I understand you all well. I do not have to make a seperate template but it is also a method ?
the "template" is a clojure data structure, you can use standard clojure functions to construct that data structure and include the items you need to display
this example might help:
$ clj -Sdeps '{:deps {hiccup/hiccup {:mvn/version "1.0.5"}}}'
Clojure 1.10.1
(ins)user=> (require '[hiccup.core :as hic])
nil
(ins)user=> (hic/html [:img {:src "foo.png"}])
"<img src=\"foo.png\" />"
(ins)user=> (def images ["foo.png" "bar.png" "baz.png"])
#'user/images
(ins)user=> (hic/html [:div (for [img images] [:img {:source img}])])
"<div><img source=\"foo.png\" /><img source=\"bar.png\" /><img source=\"baz.png\" /></div>"
(ins)user=> (hic/html [:html [:body [:div (for [img images] [:img {:source img}])]]])
"<html><body><div><img source=\"foo.png\" /><img source=\"bar.png\" /><img source=\"baz.png\" /></div></body></html>"
oke im used to that template are seperate files in a seperate directory
but that seems to be not needed here
right "template" is a more abstract concept here haha - using a file is one convention for templating, but eg. format
is documented to take a "template string" as an argument
if you prefer a separate template file, you can actually do this with hiccup, with an edn file (plus a function to fill in your input...) but it's often simpler and clearer to do inline definitions of data structures
oke, time to experiment
and later to see how I can add css to the mix
Right now I have a big css file that does things and I use there before and after filters
that works just fine with hiccup (you can add the style names in the {} attribute maps of the elements, and use a [:style "..."]
or [:link {:rel "stylesheet" :href "/foo.css"} ...]
or whatever to include the css in the page
and of course you can put string html snippets inside a hiccup if that's easier
oke, one small step at the time
first experiment till I have the html I want
yeah - the hiccup rules are very simple once you get used to them, and it's easy to test any helpers with string comparison
as everything in clojure 😛
ideally :D
was joking
but clojure is al totally other beast then the languages I worked with
have you seen the "simple vs. easy" talk? in many ways clojure is simpler than mainstream options, but less easy
nope,I did not see that talk
it's an enjoyable talk, and might help you understand clojure's design
oke will do that
an html template?
neither ring nor compojure offer templates, so you need to pick a templating library implementation, the answer will depend on which one you use
hiccup has the advantage that the whole thing is vanilla clojure data until you compile to html, selmer has the advantage of being a normal templating language
yep, and im thinking of using hiccup first
later maybe use one of the react one
Hiccup is simple and popular, other, more advanced libraries are using its syntax or depending on it
https://github.com/weavejester/hiccup the README should be enough to get you started
a similar dichotomy exists with honeysql and hugsql
one defines sql as clojure data-structures and the other is a nice abstraction over templating sql
regarding react: you'll likely find it much easier to start with server side rendering, cljs and react wrappers add a lot of new weirdness beyond what you are working with now
I very much agree with this!
I know that is why I said that maybe later I will do that
I will again google to find a answer
What im trying to do is to display data I fetched from a external api
I linked to the hiccup readme, it uses the same syntax as the popular react frontends, and it includes multiple examples
I will and had take a look at it but could not find what im looking foor
Hi everybody. Hope you are happy and having a smooth day. I was wondering just now... Is there a way I can "screen scrape" content that is loaded by javascript? If I retrieve the HTML of the page it does not have the info I want on it [yet]. Is there a way to programmatically scrape a page after the javascript loads?
Is there a reason that you can’t use Puppeteer or Selenium ? https://pptr.dev/ https://www.selenium.dev/
could you describe what you are looking for? when I look at it that's the first thing I see, it's a function that takes a data structure and returns html
your "templating" is done by filling in the data in the data structure (a normal function does that, you don't need anything special)
this library uses a normal web browser as a tool for that task https://github.com/igrishaev/etaoin
I don't know of something that is just java/clojure that would reliably fill in the html in a compatible way
interesting! it seems like I just have to invoke "render" on the html somehow...
one option I have used in the past (with python+beautifulsoup) is geckodriver to fetch and render the page and then grab/interact with the DOM. https://github.com/mozilla/geckodriver
Right on. Well I might be able to use some python thing to scrape and then clojure to render later...
right - the problem is that frontend devs are not targetting the html spec (which some clojure lib might implement), they are targetting specific browsers
Ah, right.
@agile-cactus yeah etaoin uses geckodriver, but it also works with chrome
There is also something called PhantomJS ...
really the ideal thing is to be able to drive the exact renderer / browser that the web app dev is targetting
The last few days I make a method called get-data
that fetches some data from a external api.
Now I try to find a way to send the output of that method to hiccup so I can display it
or that hiccup can ask for that data
@sova it exists but is no longer maintained, and I assume no web app dev is ensuring their code works with phantomjs
hiccup takes one kind of data: a clojure dta structure
In simple terms: hiccup is not an object, its just a data structure. If you put in symbols they get evaluated just normally
in order to use it, you fill in your data into that structure first
mmm right on.
Well, cool! Looks like etaoin is the ticket.
thx
there are a few examples in this repo: https://github.com/yokolet/hiccup-samples/blob/master/src/hiccup_templating/views/contents.clj#L20 - in the linked function you pass in a "label", and it returns html data that uses that label
that's the general pattern - it's very simple IMHO
oke, I will sleep about it, I now have a collection of collections that holds the data
maybe im overthinking things
to expand an example from the README:
user=> (html [:span {:class "foo"} "bar"])
"<span class=\"foo\">bar</span>"
(defn foo-span
[txt]
[:span {:class "foo} text])
(html (foo-span "bar"))
hiccup is simpler than most people expect, since it just expects you to use standard clojure features to do anything interesting
I deserialize a json response from a webserver, but I end up with way more data than I need. After deserialzing I end up with a collection of maps, is their a way to get rid of most fields I don't care about?
(map (fn [{:keys [EndPoint, InstanceName, DatabaseName, DaysSinceLastBackup, LastDataBackupStartDate, DataSizeGb, RecoveryModelDescription, LogSizeGb, StateDescription]}]
{:EndPoint EndPoint :InstanceName InstanceName ,,,,,} response)
?
Or shoudl I just ignore the fields I don't care rather than creating a map with the fields I do care about?
There is about 61 fields or so and I only care about 10 or so.oke
so I can write a function that calls the function that outputs this :
clj꞉paintings.core꞉>
({:object-number "SK-A-4830"
:width 175
:height 136
:url
"<http://lh3.googleusercontent.com/i9rZKO23qEyRg9TE5VN5_v4AAzwqPdFZunfhpfxV7llT1mk593mMhS3gmQW8_HpA0FmqfVLcDuXXf0UonINGwGxp1JY=s0>"}
{:object-number "SK-A-1451"
:width 186
:height 127
:url
"<http://lh3.googleusercontent.com/QomBqMQhWieJvwxIBGEq8oS7gJkwv3XesSktJqJOkwui6NU_0UIniYoTDzl6aByGrKS4SVg0nwIGr9OgGEA91WooJF8=s0>"}
{:object-number "SK-A-1505"
:width 127
:height 198
:url
"<http://lh3.googleusercontent.com/PCRHxBNtKpz9lDX_9VAHAOKE5tYwNLl75e2E1Fas2KAXWI3afrE-r4EWmtlz3Vk8xNptPPxqTzE9MvCzs9KneTnNK3uu=s0>"}
{:object-number "SK-A-3841"
:width 191
:height 143
:url
"<http://lh3.googleusercontent.com/yTYAzH_q-M6GxEnaCeeQC6e1pbm6XwUDO5XDtUmYlanAtAoF6hxUdhbGyIO6L9dCKHLwae1lEHAuMuveaIi4LuEt0g=s0>"}
{:object-number "SK-A-2963"
:width 145
:height 184
:url
"<http://lh3.googleusercontent.com/zn02IemnhpAqcCMKmNkxPBVGM9CvROqaSVbpSkMfTv-DheNPS6KiLszq5totiyShZX5Tl92gbydlmOYhxkeWAusJKg=s0>"}
{:object-number "SK-A-135"
:width 144
:height 169
:url
"<http://lh3.googleusercontent.com/QDhLN0_5UUhlmn9jC1LNFcYzbXYKea5LjZNuo4-33HWbRP_wm5H_5QYZr5a-Gsaeri8mKFk4D49uRIju12p-9ET06TQ=s0>"}
{:object-number "SK-A-2099"
:width 145
:height 179
:url
"<http://lh3.googleusercontent.com/pHfJFrggTcDq2cLxQxgnnxR151IChSk6k8Q1pbXWunqRg6avfCdjo4LjfmnMd8QVCxqTkvb-qu_bJxkmRJVytmDR8DQ=s0>"}
{:object-number "SK-A-1796"
:width 202
:height 113
:url
"<http://lh3.googleusercontent.com/sbCWPXJFQ0-fgMkmBILH--QpyKU4xcXGfRHRjcuCHt_UHC7ZwhE_83-l_hJ_DIhMwVVJiU7PixtArU4gb6VuRAN7pVc=s0>"}
{:object-number "SK-C-2"
:width 136
:height 56
:url
"<http://lh3.googleusercontent.com/gjsM0sJclVJ8rkta7ppoGI63RmNdSZAvbkXLKd7T1xFXE5WzPoQGyi3Y0zQXXcBeMr0Q4kSCjghstIvGr_3Pl6SYag=s0>"}
{:object-number "SK-A-180"
:width 146
:height 179
:url
"<http://lh3.googleusercontent.com/dgdeRabPYriIi7v5R3fAk6cudxssTV_oEVaXz1zSo9UPlTcUPAJgZan9jhCfAPzjwtpDTb0v5vSja0uyrSR4LatmTw=s0>"})
clj꞉paintings.core꞉>
what I want to do is to display all images with a <img> tag
that's a lot of bindings to stick into one command line destructure
but for now GN
yeah, i know 😞
the same syntax works in let
it looks like you are just doing select-keys
(select-keys response [:EndPoint InstanceName ...])
- that vector can be a separate def
my concern is i have over a thousand maps being created, ancd each with 61 fields. WHen I want the thousand maps, but i only care about 10 of the fields.
@qmstuart It's probably more idiomatic to just ignore the keys you don't care about -- unless you have a very specific context in which extra fields are not allowed (such as storing the hash map in a database).
I would recommend starting by writing the hiccup data manually (not created via a program) that produces what you want for one or two images.
Once you get that working, then you will know what "shape" of data structure you want to create via a function that works for N images on a page.
the result will probably look kind of like [:div (for [img ...] [:img ...]])
walk before you run
no, im not storing this stuff. Just processing it. I was thinking having large maps would be a performance issue maybe.
but it might be fine
well, if large maps turned into an issue, I'd use select-keys
(maybe with clojure.set/rename-keys
too...) upon acquiring the data, but @seancorfield is right that most of the time you can just ignore the keys you don't want
thanks, @noisesmith I wasn't aware of select keys
Map lookup for large maps with N key/value pairs is O(log N) in Clojure, where the base of the log is 32, not 2, and pretty decent on constant factors, too. I wouldn't worry about their performance, until and unless you actually do some benchmarking to determine where most of the time is spent in your code. Clojure maps aren't going to outperform custom-made maps tailored to particular situations, but they are usually close enough that they aren't the performance issue in your application.
maybe there's some fancy json parser that allows you to whitelist parts of the structure you want, but the complexity that introduces is worse than the cost of unused keys for 99.9999% of cases
There is a ton of pure functions though. In my naiv understanding these are pretty inviting to be run in parallel. Maybe I should spend more time on the basics, but it with cpus commonly offering dozens of threads and cores it seems like a waste when everything runs sequential
I know
@andy.fingerhut I’m going to include this in my “programming mantras” sheet that we use to teach introductory programming!
Ok, so this is a terrible function. How would I write it to accept a map with keys instead (if that is a better idea).
(defn save-create-order
[external-id service-company-id elevator-id
contract-id description status due-date
actual-start-time actual-end-time checklist-id]
(swap! orders conj (create-order
external-id service-company-id elevator-id
contract-id description status due-date
actual-start-time actual-end-time checklist-id)))
often when you have that many args to a function, it should take a map in the first place, by which I mean create-order
might need a smaller number of maps as args, and save-create-order
would not have to care about all the keys in those maps
or perhaps a small number of maps (eg. one for the customer data and one for product related data?)
but to literally answer the question: replace (defn save-create-order [external-id ... ] ...)
with (defn create-save-order [{:keys [external-id ...]}])
and pass a map that has the matching keys
I don't know if it adds much, but REPLs can make it much quicker to try out many tentative walking steps very quickly.
Rhino is deprecated, and has been removed in newer versions of ClojureScript
It was removed in version v1.10.738