Fork me on GitHub
#beginners
<
2019-05-20
>
Drew Verlee00:05:23

Another awesomeness of clojure, the code is so condensed you dont have to use a code block thing in anki thats likely to break at some point.

tommctighe03:05:44

My app uses Luminus, Selmer, and HugSQL. Users submit a form of checkboxes to filter a list of items. I want the checkboxes to be “sticky” -- to remain checked after the form is submitted and the page is re-loaded, so the user can see which boxes they checked. The checkboxes are added to the page dynamically, “select interests from events”, so the checkboxes’ names are created at run-time. In PHP there's a well-known way to do this.

penryu05:05:45

@mctighe.tom One could do this by storing the checkbox state in a session variable, and restore that state on page load.

penryu05:05:45

Actually, on a quick look, it appears it's even less "magic" than that. Where php has:

<input type="checkbox" <?php echo $checked ?> ...>
you should be able to add something like this to your selmer template:
<input type="checkbox" {{checked}} ...>
where the checked variable in both cases has the value "checked" or the empty string "".

tommctighe17:05:43

Thanks @UGPM7GTKJ -- since in my case the checkbox field's name is not static but composed on the fly, I can't see a way to do this inside a Selmer template -- I would need to look up the value in the session map with a variable key, not a static key. I'll look at other templating options

penryu17:05:23

That could be even simpler. Emit the checked attribute (or don’t) whenever the element is composed. Perhaps an example of the corresponding PHP code could help.

tommctighe17:05:25

The checkbox fields start with a database select statement. They're rolled out, however many there might be, using a Selmer for loop, and named dynamically: interest1, interest2... Later the user checks a few boxes and submits the form. The form's k/v pairs are stored in a params map. Selmer doesn't mix Clojure code and markup, so I don't see a way to look up each checkbox's name in the params map, it requires a variable. If I knew each checkbox's name in advance, it would be possible.

penryu20:05:14

The PHP samples all leave out some of the logic, but in just about all cases: • all available values (eg, sports) are known at loop/emit time • the checkbox value (eg, the sport it represents) is known at loop/emit time • the checkbox state (whether it’s checked or not) is known at loop/emit time • the HTML element is emitted manually So it doesn’t seem all that magical or even elegant to me. Only well-documented in Q&A fora. I have not used selmer, but it seems doable within the template provided you have the available sports as vector (or set) interests and the user’s selected sports (as set) user-interests:

{% for interest in interests %}
<input type="checkbox" name="interests"
       id="interest_{{forloop.counter}}" value="{{interest.name}}"
       {{interest.checked}}>{{interest.name}}
{% endfor %}
where interests is a vector generated:
(defn render-interests [interests users-interests]
  (letfn [(f [interest]
            {:name interest
              :checked (if (contains? user-interests interest) "checked" "")})]
    (sel/render-file "interests.html" {:interests (map f interests)})))

penryu20:05:05

I’m sure someone has a more elegant syntax, or can take advantage of Selmer features that I’m not familiar with. But it’s fully doable without manually writing anything out.

tommctighe04:05:42

Thanks a lot @UGPM7GTKJ -- I looked into this approach earlier and thought it was a dead end, but your reply got me to take a second look, and I got it working

👍 4
pwalsh05:05:03

Hi. First time importing a Java package into a Clojure project, and I can't import a 3rd party library installed with lein. I am using this package https://github.com/googleapis/google-auth-library-java/blob/6698b3f6b5ab6017e28f68971406ca765807e169/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java#L32 and this class https://github.com/googleapis/google-auth-library-java/blob/6698b3f6b5ab6017e28f68971406ca765807e169/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java#L87 My project.clj

(defproject warehouse "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url ""}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [clj-http "3.10.0"]
                 [com.google.auth/google-auth-library-oauth2-http "0.15.0"]]
  :main ^:skip-aot warehouse.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})
My namespace in warehouse/core.clj
(ns warehouse.core
  (:gen-class)
  (:require [clj-http.client :as client])
  (:import (com.google.auth.oauth2 ServiceAccountCredentials)))
Evaling the buffer with core.clj with Cider gives me
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:436).
com.google.auth.oauth2.ServiceAccountCredentials
I can import Java utils successfully, for example (:import java.util Date) I have run lein install to confirm that the auth library is installed.

penryu05:05:50

@pwalsh Was the CIDER session started before the deps were added/installed?

pwalsh05:05:39

yes! Thanks 😉

😊 4
dangercoder08:05:14

If I want to use aws beanstalk, would it be wisest to use http-kit? I am currently using immutant with sente for websockets, haven't deployed it yet though.

dangercoder08:05:30

since beanstalk uses apache tomcat. (http-kit?)

Tomasz Rojek11:05:17

My request looks like this:

(client/post ""
               {:debug true}
               {:basic-auth ["api" "key-432432432432"]}
               {:form-params
                {:from ""
                 :to ""
                 :subject "Test"
                 :text "..."}})

art13:05:31

(client/post ""
               {:debug true
                :basic-auth ["api" "key-432432432432"]
                :form-params {
                 :from ""
                 :to ""
                 :subject "Test"
                 :text "..."}})

Tomasz Rojek13:05:39

I deleted message because it was related to mailgun not to clojure itself.

Chris Reyes13:05:05

Hi all, I have a defrecord statement in one namespace and I’m trying to extend-protocol with that record type in another namespace. I keep getting a ClassNotFoundException though. How am I supposed to import/require/reference the record type? I’ve tried: - (ns foo (:require [my-project.other :as other])) (extend-protocol MyProtocol other/MyRecord) - (ns foo (:require [my-project.other :as other])) (extend-protocol MyProtocol other.MyRecord) - (ns foo (:require [my-project.other])) (extend-protocol MyProtocol my-project.other/MyRecord) - (ns foo (:require [my-project.other])) (extend-protocol MyProtocol my-project.other.MyRecord) - (ns foo (:import my-project.other.MyRecord) (extend-protocol MyProtocol my-project.other.MyRecord) - (ns foo (:require [my-project.other]) (:import (my-project.other MyRecord)) (extend-protocol MyProtocol my-project.other.MyRecord) But none of those worked yet…

Chris Reyes13:05:39

Hmm, I might have figured it out. I tried using underscores in the import statement and in the references rather than hyphens (for the containing namespace)

Chris Reyes13:05:20

Yep, that was it. Final answer for me was:

(ns my-project.something
  (:require [my-project.other])
  (:import my_project.other.MyRecord))
;...
(extend-protocol MyProtocol
  my_project.other.MyRecord
  ;...

Ivan Koz14:05:37

is there a more interesting way to write such predicate? #(or (= 2 %) (= 5 %))

Ivan Koz14:05:35

damn i knew it, ty

Francisco14:05:36

Hello! Is someone here experienced with Etaoin? I know most of it is actions but in its documentation it doesn't provide a way to handle drop downs (for example, mouse hovering to open one of the dropdowns menus and then click it), or actions that are outside the scope of the documentation, I am new to clojure btw

borkdude15:05:07

@fmaldonado yeah, I use etaoin. I’m not sure if I have used dropdowns.

Francisco15:05:19

hey @borkdude, thanks for answering, has there been a test case in which you had to use something out of the scope of etaoin? is for references and knowledge, mostly

borkdude15:05:24

the code of etaoin is in essence just firing HTTP requests at the webdriver REST API, so whenever there is a limitation, it’s not hard to figure out how to work around it

borkdude15:05:37

as long webdriver supports it

gklijs16:05:07

I guess the easiest is one click to open it and one to select it. Haven't used etaoin for this, but recently did with selenium which is about the same. If you can change the html it's often the easiest to set an id. You can also use the chrome deftools to get the query for an element right.

gklijs16:05:08

If you didn't know already there is also #etaoin for etaoin specific questions.

Francisco17:05:39

thank you both for your answers, my doubts are quite specific tbh because of the new enviroment i've been working on

Francisco17:05:48

and no, i didn't know about the channel, thanks

evocatus17:05:21

Can you please explain to me why this code raises "can only recur from tail position" ?

hiredman17:05:11

are you familiar with the concept of a tail call?

hiredman17:05:52

typically when compiling a function call the computer has to keep track of a return address to return to after computing the function. at certain locations in a program when there is a function call it turns out yo don't need to track the return address, those locations are often referred to as a tail call

hiredman17:05:45

a tail call is useful in that context because it can avoid the bookkeeping in a normal function call which means you can use them for constant space recursion

evocatus17:05:49

I know what is a tail call. I just don't see why this is not a tail position

hiredman17:05:40

it very obviously isn't a tail call because the "recur" call needs to return to the evaluation of (+ ... ...) to continue

👍 4
noisesmith17:05:20

it's not a tail call if there are any operations in its function that are left to be done after it returns

👍 4
hiredman17:05:20

more formally the continuation of the recur expression is not the same as the continuation of the whole function

Michael Stokley19:05:07

anyone familiar with core.logic.permuteo? would love to get an intuition about what it does

Michael Stokley19:05:42

i think i got it

Ian Fernandez20:05:52

hey guys, I have this line on Java:

private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalMemcacheServiceTestConfig());

Ian Fernandez20:05:07

how I transpile this to clojure interop?

noisesmith20:05:51

(let [helper (LocalServiceTestHelper. (LocalMemcacheServiceTestConfig.))] ...)

noisesmith20:05:58

or a def, depending on how it's being used

noisesmith20:05:36

most of the time "move every paren one word to the left" does most of the work

Ian Fernandez20:05:00

I wasn't using dot on

LocalMemcaceServiceTestConfig
call

eval-on-point23:05:42

I've seen a statement along these lines and am wondering if there is any reason to use the assert rather than just throwing an exception

hiredman23:05:07

throw is better

hiredman23:05:32

(I have written code that uses asserts like that from time to time, but it is a lazy habit)

hiredman23:05:58

asserts in theory are checks that can be turned off, there is some var you can set to turn them off, in which case the above code will be incorrect

hiredman23:05:40

(not that I have ever seen any clojure project built with them turned off)

eval-on-point23:05:59

Thank you! appreciate the help

noisesmith23:05:11

@mitchell_clojure another variation: (do (assert (not= u1 u2) "unsupported operation") q)

💎 4