Fork me on GitHub
#beginners
<
2018-01-17
>
hawari05:01:57

Changing to with-redefs also doesn't seem to work either

(deftest test-web-auth
  (testing "sign-up successful"
    (with-redefs [#'project.service.auth/sign-up (fn [cred] mock-created-user)]
      (let [request-body {:name "John Doe" :email ""}
            response (app (mock/request :post "/signup" sign-up-payload))]
        (is (= (:status response) 201))
        (is (= (:body response) mock-created-user))))))

seancorfield05:01:56

@hawari.rahman17 The most likely issue is the way you've defined app I think -- can you share that part of your code?

justinlee06:01:19

What does the #object[o] mean in this output: #js {:NativeTypes #js {:FILE __NATIVE_FILE__, :URL __NATIVE_URL__, :TEXT __NATIVE_TEXT__}, :getEmptyImage #object[n], :default #object[o]} My best guess is that it is a reader conditional, but I don’t see anything that follows that form.

hawari06:01:02

I don't remember what I did but now the test not only calls the original function, it also throws a ClassCastException on the with-redefs line: java.lang.Boolean cannot be cast to clojure.lang.IFn

seancorfield06:01:55

@hawari.rahman17 What I think is happening here is that the routes is compiling to the original function before you get a chance to redefine it for the mock. Use #' on the functions there to compile Var references to provide a level of indirection.

seancorfield06:01:05

Also, since you're passing the whole request, you can simplify how you declare the routes as well... (POST "/signup" [] #'auth/signup)

seancorfield06:01:54

You might also want to use #'app-routes instead of app-routes in the definition of app so that you can update the routes and have those changes take effect without having to stop and restart your entire web app.

seancorfield06:01:29

Then (with-redefs [project.service.auth/signup (fn [req] ...)] ...) should work (no #' here).

hawari06:01:04

Do you mean in the project.web.handler ns? All right, I'll try it.

hawari06:01:57

So basically the app should looks like this, @seancorfield?

(def app
  (-> #'app-routes
      #'wrap-exception-handling
      wrap-json-response
      (wrap-json-body {:keywords? true})
      (wrap-defaults api-defaults)))

seancorfield06:01:28

Yeah, using a Var -- #' -- means that you can redefine (or mock) the function and the changes will be picked up, because the Var introduces a layer of indirection.

seancorfield06:01:49

Did you also make the change I suggested in the routes themselves, to use Vars as well?

hawari06:01:46

I did, but do you think we need to change the auth routes as well?

(defn sign-up
  [request]
  (let [{credential :body} request
        result (#'auth/sign-up credential)]
    (cond
      (contains? result :error) (process-error result)
      :else {:status 201 :body result})))

seancorfield06:01:36

No, not inside that function. Just inside the app-routes definition

hawari06:01:56

I did, but still there's no luck

seancorfield06:01:12

Show us how your defroutes looks now...

hawari06:01:32

(defroutes app-routes
  (POST "/signup" [] (#'auth/sign-up request))
  (POST "/signin" request (auth/sign-in request))

  ...

  (route/not-found {:error "Path not found"}))

seancorfield06:01:06

(POST "/signup" [] #'auth/sign-up)

hawari06:01:51

Okay, but it still doesn't work

seancorfield06:01:18

Then I don't know what to suggest. What I'm suggesting works.

Michael Stokley06:01:06

can partial be used with a second or third argument, but without the first?

hawari06:01:50

Does with-redefs expect a var or a symbol @seancorfield?

seancorfield06:01:50

@michael740 No, partial sets things up so the last arguments can be omitted. You need an anonymous function to omit other arguments.

hawari07:01:08

Might be I'm using with-redefs incorrectly in the tests

seancorfield07:01:31

Symbols -- as I indicated above.

Michael Stokley07:01:34

@seancorfield the purpose of that anonymous function would be to rearrange the arguments?

seancorfield07:01:57

@michael740 Yes, #(some-fn % other args)

seancorfield07:01:21

@michael740 At work we have a flip function modeled after Haskell that allows us to omit the first argument since it's fairly common: (flip some-fn other args)

Michael Stokley07:01:57

i like seeing if haskell has these functions, too. gives me a sense of whether a given function or technique is proper to functional programming or lisps

hawari07:01:59

@seancorfield, you're going to kill me for this, I was testing from inside my emacs, with cider already jacked in. It seems that it doesn't reload my code properly. After running the test with lein test it works now.

hawari07:01:12

I'm terribly sorry

seancorfield07:01:27

@hawari.rahman17 No problem. Glad you got it working! It's hard to debug people's code remotely 🙂

seancorfield07:01:12

@michael740 Yeah. It's also interesting when an idiom doesn't cross language boundaries -- for example Haskell leans on monads heavily but they're fairly rare in Clojure.

hawari07:01:29

Thank you, I really appreciate your help @seancorfield

seancorfield07:01:18

@hawari.rahman17 Sometimes a REPL will get in a bad state, esp. if you're trying to redefine functions so just closing and restarting the REPL can help. I've found, since I switched to Component for everything, that has really helped since I no longer have to restart the REPL as often, just stop & restart the main app component.

seancorfield07:01:26

The other thing is running both the web app and the tests in the same REPL -- which also can make life a lot easier (although you have to remember that if you do HTTP requests to the app from your tests, they're executing in different threads).

hawari07:01:24

Alright @seancorfield, guess I need to refine my workflow then

seancorfield07:01:23

Developing a fluid workflow centered around the REPL is a key part of being productive with Clojure, but it takes time and experimentation, and it really depends on your tools.

seancorfield07:01:59

I highly recommend Stu Halloway's talk on REPL-Driven Development that he gave to the Chicago Clojure group in mid-2017.

fmind07:01:46

@seancorfield thank's for the talk

fmind07:01:26

Just a crazy idea, do you think it would be possible to debug someone remotely with nrepl ?

fmind07:01:56

that would me a major improvement compared to our current workflow with pastebin and stack overflow

seancorfield07:01:30

Link to that talk to save folks using Bing/Google: https://vimeo.com/channels/1116889/223309989

seancorfield07:01:32

@fmind It's definitely possible, but screen sharing (via any number of services) is probably easier than trying to do it all via a REPL.

seancorfield07:01:17

I no longer use nREPL -- I use Atom/ProtoREPL locally which doesn't rely on nREPL and in our apps we use Socket REPLs if we need them.

fmind07:01:13

@seancorfield indeed, it seems more practical. I'm always intrigued by the workflow that could be developed with dynamic languages

fmind07:01:26

like recently, with the release of dynadoc https://github.com/oakes/Dynadoc

fmind07:01:23

I have this impression that toolings for dynamic languages have not been explored to their full potential

seancorfield07:01:02

Yup, agreed. We have over a dozen separate web apps and it's easy to fire up a REPL, keep it open for days, and stop/start any number of the web apps, and their test suites, and work interactively, evaluating code as you write it, running a test -- or all tests in a namespace -- easily and repeatedly, evolving your code and tests as you go.

seancorfield08:01:20

That is the first time I've watched one of Zach's videos -- he's hilarious! Love that video!

pny11:01:14

I wanna run integration test within one connection, and wrap each test in transaction. https://github.com/pn-y/hsp/blob/master/test/clj/hsp/application_test.clj#L7 It was not so hard to do it within unit tests, but with fully started app i'm totally lost. How could i inject connection with transaction to already started system? I've tried different ways, but didn't succeed https://github.com/pn-y/hsp/blob/master/test/clj/hsp/test_helpers.clj#L42

gmercer11:01:01

@seancorfield check out Zach's conference talks for an informative good laugh

joelv14:01:43

hello everyone, I'm running to an issue where lein uberjar or lein with-profiles uberjar compile :all where it just hangs. Is there away to run lein uberjar that prints out more info like --verbose or something?

pny14:01:33

@joelv try DEBUG=true lein uberjar

joelv15:01:44

didn't really give much more info:grimacing:

joelv15:01:11

has anyone run into issues with lein uberjar getting stuck? lein compile works.....

reborg15:01:38

@joelv any chance you can do a thread dump? jcmd <pid-of-lein-uberjar> Thread.print > td.txt

joelv15:01:03

let me try

bronsa15:01:24

or just C-\ on the terminal where the process is running

Michael Stokley17:01:45

imperatively, i can use a loop to repeatedly apply a function to, e. g. a list. what's a good functional or stateless alternative?

CMS17:01:40

reduce is appropriate

edwaraco17:01:19

Hi. I'm building one test case and I need to check if one function that runs in background is invoked. Currently I'm doing something like:

(defn do-something-1 [a b c]
  ;; dosemthing)

(defn do-something-2 [a]
  (let [b 1 c 2]
    (send-off (agent  a) b c)))
And my test case is:
(deftest test-do-something-2
  (let [invoked? (promise)]
    (with-redefs [do-something-1 (fn [a b c]
                                    (is (= a 3))
                                    (is (= b 1))
                                    (is (= c 2))
                                    (deliver invoked? true))]
      (do-something-2 3)
      (is (true? (deref invoked? 5 false)))))
It works whether do-something-1 function is invoked in less 5 millisecond. Who can give me other suggestions? Thanks!

CMS17:01:19

if I understand your question correctly

Michael Stokley17:01:40

suppose i want to double a number n times. reduce acts on a collection, right?

CMS17:01:58

aah, I see

Michael Stokley17:01:03

i think i want loop recur

Michael Stokley17:01:24

and pass along the output each iteration

Prakash17:01:52

u can also check iterate

admay17:01:06

doseq and dotimes as well

CMS17:01:01

you can use reduce for that, for instance: (defn doubler [start, doubles] (reduce (fn [total i] (* total 2)) start (range doubles)))

Michael Stokley17:01:33

is reduce using the (range doubles) for anything other than a stop condition?

CMS17:01:10

nope, pcb's suggestion of iterate is probably better in this case

CMS17:01:23

but the reduce pattern works if you're doing something with a side effect

clojuregeek17:01:44

Looking for suggestions on parsing XML with clojure? anything more friendly than https://clojure.github.io/clojure/clojure.xml-api.html ?

alexmiller17:01:03

have you tried https://github.com/clojure/data.xml ? I’ve used it for a variety of things and have usually found it to be pretty serviceable.

alexmiller17:01:28

these days I’m using the 0.2.0 alphas

clojuregeek17:01:50

Ok thanks, i'll check it out 🙂

jcburley17:01:28

I just wrote up this function, which is handy for some playing-around I'm doing:

(defn map-neighbors
  "Applies predicate to every pair of neighbors in the sequence, returning a lazy sequence of the results."
  [pred s]
  (map-indexed
   #(pred (nth s %1) %2)
   (rest s)))
E.g.:
app.core> my-p
;; => [2 4 6 8 5 3 4]
app.core> (map-neighbors list my-p)
;; => ((2 4) (4 6) (6 8) (8 5) (5 3) (3 4))
app.core>
I was unable to find something like this already in existence. Is there an easier/better way?

noisesmith17:01:27

(map pred s (rest s))

jcburley17:01:07

Wow, of course, thanks! I haven't used multi-collection arguments to map yet.

noisesmith17:01:16

also pred is an odd name here, f would be idiomatic

jcburley17:01:38

Oh, okay. I prefer f or fn, but often see pred in the online docs.

noisesmith17:01:57

pred is specifically for things that return true or false

jcburley17:01:09

Okay, makes sense, thanks!

jcburley18:01:09

(I still tend to look for functions, rather than ways to apply existing functions in flexible ways, to solve problems in Clojure...presumably that's a tendency among many who, like I, have decades of experience writing in imperative languages when learning functional programming?)

seancorfield18:01:48

@james-clojure Yes, I think so. It takes a while to get into the mindset of thinking about problems as a composition of small functions.

noisesmith18:01:26

yes - I found that the exercises at http://4clojure.com (and looking at the answers from more experienced users) helped me get a better grasp of how to use clojure’s built in stuff

seancorfield18:01:29

☝️:skin-tone-2: Definitely good advice! 4clojure was extremely valuable when I was learning. Haven't looked at it in years now so I tend to forget...

noisesmith18:01:54

one of these weekends I’ll hit 100% of the exercises there heh

seancorfield18:01:34

Hahaha... I got to 100% and kept on top of that in the early days... I don't know that I'd ever find the time to get back to 100% now 🙂

jcburley18:01:14

This is so helpful! How does 4clojure compare to adventofcode?

frenata18:01:30

4clojure is on the order of individual functions, whereas AOC is solving more complex problems

noisesmith18:01:37

I get the impression that 4clojure is much more streamlined for using clojure

noisesmith18:01:53

@andrew354 for advanced problems it is closer to AOC stuff - graph theory and such

noisesmith18:01:06

the elementary stuff does focus basic builtins though

frenata18:01:21

I see, haven't gotten there yet.

noisesmith18:01:35

the last one I solved was calculating edit distance of strings

frenata18:01:06

AOC has a more "practical" feel too, where some realish business problem is described and you are free to approach it as you like

Michael Stokley19:01:45

my sense is that AoC is implicitly geared towards imperative programming

Michael Stokley19:01:06

would be curious to know if anyone else thinks so too

Michael Stokley19:01:53

why can't i map Integer. against a list?

Michael Stokley19:01:13

(Integer. "10") works fine

Michael Stokley19:01:45

seems it's not quite a function?

dpsutton19:01:46

from what i've heard its a method and methods are not first class objects on the jvm

sundarj19:01:52

yeah, java interop stuff is special

sundarj19:01:21

you can do (map #(Integer. %) coll) however

Michael Stokley19:01:42

would you recommend read-string instead?

noisesmith19:01:35

no, read-string is way too powerful for this

noisesmith19:01:23

among other issues, read-string allows executing arbitrary code

=> (read-string "#=(+ 1 1)")
2

noisesmith19:01:03

but even clojure.edn/read-string (which doesn’t have that issue) is still much more general than you need. If you know you want an Integer from a string, use Integer/parseInt, if the input could be anything that the Integer constructor accepts, use (Integer. foo)

noisesmith19:01:38

also seriously consider using Long rather than Integer in general - the same methods are there, but almost everywhere clojure prefers Longs

frenata19:01:52

Should probably use #(Integer/valueOf %) , which will cache values rather than forcing new memory allocation

Michael Stokley19:01:25

i was seeing a lot of different answers on SO

noisesmith19:01:25

@freneta the caching isn’t from valueOf, it’s part of the implementation of Long / Integer themselves in the vm

=> (identical? (Long/valueOf "1000") (Long/valueOf "1000"))
false

noisesmith19:01:29

oh wait I see what you mean, by using the constructor you bypass that caching

frenata19:01:15

Yeah. It may only be -128 > 127 though

frenata19:01:44

> This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

noisesmith19:01:51

right, valueOf and parseInt / parseLong each use that cache

noisesmith19:01:20

also you can mutate values in that cache via reflection and cause really crazymaking bugs haha

frenata19:01:15

I would've eventually hit that issue with trying to treat Integer. as first class, so thanks @michael740 for making me figure it out ahead of time. 🙂

Kara21:01:21

I'm following along some code someone else has written (clojurescript) and I noticed that they seem to be using ! at the end of some of their definitions: (declare action!), (defn register-component! ... ) Is this a common convention and does it mean something? I can't seem to find docs for it. 😕

donaldball21:01:22

Some people use a trailing bang to indicate a fn with side effects. Others use it to indicate a fn that may throw exceptions you want to handle, though that’s less common I think.

Kara21:01:09

Ah, thank you good to know. I'm still at the stage of trying to parse actual syntax from convention I'm afraid. -_-

noisesmith21:01:12

clojure has no suffix syntaxes, and very few prefix syntaxes

noisesmith21:01:54

most prefixes are # followed by something, except @ , ', ` (and of course I forgot a few others but they are all in the “weird characters” link)

admay21:01:45

As far as naming your own functions, a pattern that has stuck pretty well ( I think ) is to name side-affecting functions with a bang (!) at the end, binary functions (true or false) with a question mark (?) at the end, and functions that might throw an error with a double bang (!!) suffix. This is by no means a community standard though, just what made/makes sense to me

Kara21:01:41

Thanks again @noisesmith and @admay I actually found some guidelines for the ! pattern in that documentation: https://clojure.org/guides/weird_characters#__code_symbol_code_unsafe_operations 🙂

jcburley22:01:38

Isn't # a significant suffix to designate gensym's within macro bodies? I've actually used it (after seeing other code use it), but hadn't remembered it from reading "The Joy of Clojure" last summer/fall....

jcburley22:01:22

(Ah, yes, that's mentioned on that website -- I see it now.)

noisesmith22:01:38

yeah, I forgot that one (sub-syntax of `)

dpsutton22:01:33

very beginner question for spec

(s/def ::title string?)
(s/def ::title-info (s/keys :req-un [::title]))
(s/def ::rows (s/coll-of ::title-info))
wanting to spec [{:title "title"} {:title "another-title"}] this works:
(s/conform (s/coll-of ::title-info) [{:title "bob"}])
[{:title "bob"}]
but not
(s/conform ::rows [{:title "bob"}])
:cljs.spec.alpha/invalid

dpsutton22:01:32

and ::rows is (s/coll-of ::title-info). am i missing something fundamental?

Michael Stokley22:01:07

anyone use cider // clojure layer spacemacs? what's a good way to wipe my repl clean and restart it?

dpsutton22:01:34

@michael740 , will bring up a menu in the repl. there's refresh and restart

dpsutton22:01:46

restart won't bring up a cljs repl unfortunately though

alexmiller22:01:25

@dpsutton that works in Clojure and should also work in ClojureScript if it doesn’t

dpsutton22:01:42

it started working. i think i had some stale definitions lingering

alexmiller22:01:47

(also, fyi there is #clojure-spec which I watch more closely than here)

dpsutton22:01:56

this felt a little too beginner for there

dpsutton22:01:57

but thanks!

alexmiller22:01:02

totally fine there

dpsutton22:01:11

will do. i'm finally learning it. thanks alex