Fork me on GitHub
#clojure
<
2019-04-15
>
adam00:04:24

Any idea how I can achieve this in Compojure:

(def app
  (-> (wrap-defaults (get-app-routes handler) site-defaults)
I want to define the routes based on the hostname. The problem of course is handler above is not defined.

Mno00:04:33

I beleive you’re missing a closing parens or 2

Mno00:04:35

but other than that, what is get-app-routes?

adam00:04:31

I am not missing parens. I just omitted some middleware. get-app-routes looks like this for now:

(defn get-app-routes [handler]
  (defroutes app-routes
    (GET "/" [] "Hello")))

Mno00:04:31

you don’t seem to use the handler, do you need to do something odd and dynamic?

adam00:04:40

The idea is to return different app-routes based on the hostname that I can get from the handler request object

Mno00:04:51

aaaaahh.. I see..

Mno00:04:16

I can’t think of any clear solution for this since I don’t understand the case very well. My last bit of advice is you might be able to get away with just using routes instead of defroutes because it doesn’t seem like you’ll use app-routes directly anyway.

Mno00:04:25

maybe middleware might be the way, maybe just a conditional in the routes themselves. 😅 sorry I can’t be more useful, hope someone else can help.

adam00:04:09

Thanks, I guess I'll keep trying.

hipster coder03:04:42

I finished my results of comparing Clojure, C, Python/Jython/Cython, Ruby/Jruby for the nth term of Fibonacci.

ido10:04:49

Hi, I have a simple TTL cache built around an (atom {}) the logic that gets a value either finds an entry or gets a new one if the entry was missing or already expired (the loading of the entry involves a short Redis IO op). Dead simple. Now, I want to improve it and make it thread-safe. It is not not entirely thread safe because 2 threads can find a missing/expired entry and trigger a load (redis call) simultaneously. How would you recommend locking the IO per key? 1. (locking cache-key ...) comes to mind but is not so the Clojure way (also, I’ll have to maintain an additional map of locks) 2. maintaining a map of entry as ‘loading’ refs where every load from DB is a transaction on the corresponding ref. This also sounds overly complex. Any more inspirations?

rutledgepaulv12:04:53

core.cache has composable caches and the ability to define a custom cache. I wonder if you implemented a custom cache that uses redis to back it and then composed it with the built-in ttl cache if that would give what you want https://github.com/clojure/core.cache/wiki/Extending

ido03:04:35

@rutledgepaulv I wonder where are you aiming at. The core.cache implementation does not ensure that a fetch for a single key is called once. on the contrary:

(defn get-data [key]
  (cache/lookup (swap! cache-store
                       #(if (cache/has? % key)
                          (cache/hit % key)
                          (cache/miss % key (retrieve-data key))))
                key))
assumes that retrieve-data can be called multiple times since if multiple threads race on the missing key branch than the atom implementation will trigger a retry for the ‘loosing’ thread. Since the eviction policy I implemented is very naive (and that is quite okay for me), what I am looking for is just to ensure that retrieve-data is ensured to be called once per TTL expiry and not more. This is since I want to protect my DB against a flood of requests once the TTL of many object expires. @seancorfield maybe you have some ideas?

seancorfield04:04:24

@ido Check through the open issues on the repo: there's discussion of exactly that issue and an example of how to ensure retrieve-data is only called exactly once.

ido04:04:07

@seancorfield no issues on that github page: https://github.com/clojure/core.cache what m i missing?

ido04:04:40

I think that the issues are not open. is there an open jira sute for those?

seancorfield04:04:46

Right. I have a notebook with ideas about how to make higher-level usage of the caches easier. There are some gotchas with TTL as well because lookup can cause cache expiry so the simple, obvious usage can return nil -- which cache.memoize has to deal with.

abdullahibra11:04:29

Hello guys, is it possible to overwrite the functionality of default protected java method from clojure?

mping11:04:33

Hi guys, what do you use for queuing? Ideally redis-based?

mping11:04:42

I was checking farmhand but it's a bit buggy

ido11:04:07

@mping out of process queuing?

ido11:04:59

if you are looking at redis libraries i would recommend carmine

abdullahibra11:04:30

clojure.lang.PersistentQueue/EMPTY

ido11:04:53

that’s in-process ^

mping12:04:05

@ido carmine looks great, but I would need some kind of ui to check the data, as well as retries and such

mping12:04:13

I'm looking for something like sidekiq

martinklepsch13:04:22

is there a nicer way to write this:

(defmacro define-multiple [things]
  (into []
        (for [[k v] things]
          `(def ~(symbol (name k)) ~v))))

(define-multiple {:a 3 :b 2})

mloughlin14:04:27

(defmacro defmany 
  [definitions]
  `(do ~@(for [[k v] definitions]
           `(def ~(symbol (name k)) ~v))))

mloughlin14:04:42

something like that maybe ?

mloughlin14:04:32

for returns a list of forms, e.g. ((def a 1) (def b 2)), so using ~@ splices the outer set of parens away

mloughlin14:04:32

(macroexpand-1 '(defmany {:a 1 :b 1}))
=> (do (def a 1) (def b 1))

Alex Miller (Clojure team)13:04:52

I don't think that's doing what you want

Alex Miller (Clojure team)14:04:33

usually if you're emitting multiple top-level things, it's best to wrap it in a do

adam18:04:21

Is there a way in a Ring web app to get the hostname before defining Ring's handler?

noisesmith19:04:49

if the result of (clojure.java.shell/sh "hostname") is correct, that would be one way to get it

noisesmith19:04:11

you could also ensure that it's set in the environment or passed as an arg to -main

hiredman19:04:42

the server-name that you get in a ring request is from the value of the client sent Host header, and not your hostname

adam19:04:37

Yeah, I want to determine the subdomain the request is coming from before creating Ring's handler

hiredman19:04:46

basically "this is who the client thinks you are"

hiredman19:04:56

so without a client, you can't have that

adam19:04:13

It's for a SaaS system using subdomain but the company offers multiple products. For that reason, I need to set a different set of routes based on the subdomain.

adam19:04:29

I thought I could get it to work like this: (as-> handler x (wrap-defaults (get-routes x) site-defaults) but it turned out the routes are parsed on the startup only.

hiredman19:04:26

It doesn't matter what it is for though, right? You are asking to get the value of the host header, which is sent by clients each request, and can vary, before a request has been sent, which is impossible

hiredman19:04:46

What routing library are you using? Most of them can route base on the host header

adam19:04:06

I tried Compojure and bidi

adam19:04:55

bidi has subdomain facilities but they need to be hardcoded

hiredman19:04:16

You will have to hard code them

adam19:04:37

There are hundred if not thousands of them

adam19:04:09

I will need to ping the DB to see which app to use for the provided subdomain before creating the routes

hiredman19:04:37

You'll need you create a handler, which takes a request, hits the DB, looks up base on the host header, then generates the routes and applies them to the request

adam20:04:00

I got it to work based on the tips you provided. Thanks 🙂

hiredman19:04:16

Basically stop def'ing routes as global(which is terrible any way), because you need to parameterize them

hiredman19:04:28

Def'ing routes as a global value (as seen in lots of docs and tutorials) means 1. Parameterizing your routes doesn't work 2. Your handlers have to globals too

adam19:04:27

When can I define them if not globally? That's all I saw in the docs like you mentioned.

adam19:04:47

Any bits of code I can refer to?

hiredman19:04:52

Use routes instead of defroutes

adam19:04:32

Ok, I will give that a try. Thanks.

Nico20:04:07

when should I use partial rather than the #(func arg1 arg2 %) syntax?

Nico20:04:34

that's the thing, I use the #() syntax all the time, and I'm not sure where I should use partial instead

dpsutton20:04:40

I think people prefer to read the anonymous function version rather than the partial. but partial isn't out of place i don't think

Nico20:04:45

#() looks cleaner to me

dpsutton20:04:09

there is no should. I think someone mentioned that had the anonymous version been around earlier in Clojure's life partial might not have been made

Noah Bogart20:04:18

partial is nice cuz it very plainly says, "i'm returning a function that is just waiting on final input"

Noah Bogart20:04:43

#() to me says, "this is an anonymous function" and requires a different kind of parsing

Noah Bogart20:04:09

partial feels like clojure's version of currying

Alex Miller (Clojure team)20:04:14

My advice would be, don't use partial

👍 4
Noah Bogart20:04:25

oh? well, okay then!

Alex Miller (Clojure team)20:04:09

which is not to say that people don't, and it's fine that they do, but #() is imo the Clojure way to do this

Alex Miller (Clojure team)20:04:11

just my own opinion and it's ok for others to have their own preferences :)

Noah Bogart20:04:31

What feels more "Clojure" to you about #()?

dpsutton20:04:40

one thing a partial obscures the remaining calling convention whereas #(func %1 :foo %2) is clear that it expects two more args. Also, if you refactor the signature of the function partial might no longer be up to the task leading to needless churn in a diff. For instance, (defn foo [a b c]) you can use (partial foo a b) but if you change the signature to (defn foo [a c b]) you can no longer partial this application and you would have to switch to #(foo a % b) instead of just changing the position of the % and the b

seancorfield20:04:53

Also #(func 1 2 %) compiles to a function directly whereas (partial func 1 2) compiles to a call (to partial) that returns a function. The performance difference is tiny -- I'm mentioning this more to highlight there is a runtime element to partial whereas the anonymous function is a compile-time expression.

bronsa21:04:32

to add on this, partial also causes the stacktrace to point at partial$fn<whatever> instead of making acustom class, which can make debugging way harder

seancorfield20:04:53

(I'm one of those folks who still tends to use partial but I admit that I'm moving away from it...)

dpsutton20:04:51

it has an elegance to me sometimes but i'm moving away from it as well.

bronsa21:04:20

partial also captures the var value instead of the var, so it can lead to surprising behavior when using dynamic vars for example

g21:04:29

a poll: should you ever use a macro if you can use a function?

bronsa21:04:04

user=> (def ^:dynamic *a*)
#'user/*a*
user=> (def f (partial + *a*))
#'user/f
user=> (def g #(+ *a* %))
#'user/g
user=> (binding [*a* 1] (g 1))
2
user=> (binding [*a* 1] (f 1))
Execution error (ClassCastException) at user$eval164/invokeStatic (REPL:1).
clojure.lang.Var$Unbound cannot be cast to java.lang.Number

bronsa21:04:54

@gtzogana if it's convinent, yes, but you should also have the function version for when you want to use it in a higher-order context, or when the value needs to be resolved at runtime

dpsutton21:04:35

what's the best reaction for "that's a good point i hadn't considered. thanks"

8
🤯 4
💡 4
bronsa21:04:47

e.g. clojure has with-binding and with-binding*

bronsa21:04:51

one is a macro on top of the function

bronsa21:04:04

sometimes you need to use the function version when the binding map is built at runtime

bronsa21:04:19

but often it's not and the macro version is just less verbose to use

g21:04:41

hmm, ok

vemv21:04:19

Interesting points in favor of #(). Normally I favor partial because #(% ...) looks like someone swearing in a comic book But yeah looks like I should switch

Nico21:04:02

if I have a lazy repeat in clojure, can I turn it into a lazy vector I can use with assoc?

ghadi21:04:38

vectors are not lazy -- they have a fixed length

Nico21:04:43

is there an equivalent of assoc that can be done on a lazy seq?

dpsutton21:04:19

what are you trying to achieve. often its best to take a step back and figure out if there's a better way

Nico21:04:40

I'm trying to create a brainf**k interpreter, as an exercise. This is for the tape.

dpsutton21:04:18

you could use map-indexed and something like

(let [index 3]
 (map-indexed (fn [i x]
                (if (= i index) :replaced-value x))
              (range 6)))
(0 1 2 :replaced-value 4 5)

hiredman21:04:08

a map is a better model for the tape

dpsutton21:04:49

if you can drop your lazy requirement, which you probably can?

hiredman21:04:17

the lazy requirement is nonsensical

Nico21:04:32

I don't really see how a map makes a better tape model than a vector when the tape is a sequence?

dpsutton21:04:48

your current woe would be solved

hiredman21:04:49

a map allows for a sparse representation

Nico21:04:00

the lazy thing was because I thought doing a lazy tape was elegent and solves the bf interpreter problem of running out of tape

hiredman21:04:21

e.g. with a map you can assoc a value in for 1e3 without needing a value in the map for everything between 0 and that

Nico21:04:46

that actually makes more sense

aryyya21:04:06

Can you help me understand the difference between these two forms of generating a lazy sequence?

(defn evens-v1
  ([]
   (evens-v1 2))
  ([n]
   (lazy-seq (cons n (evens-v1 (+ n 2))))))
(defn evens-v2
  ([]
   (evens-v2 2))
  ([n]
   (cons n (lazy-seq (evens-v2 (+ n 2))))))
As far as I can tell, these both behave identically. Their return types are LazySeq.

hiredman21:04:07

the boundary of laziness is lazy-seq, so you would say evens-v1 is slightly more lazy and evens-v2 is slightly more eager

hiredman21:04:40

so with evens-v1, when you call it returns a lazy seq, and when you call first or rest on it, the body of the lazy-seq call is executed and cached, and first or rest is called on it

hiredman21:04:42

with even-v2 when you call it, it cons's n on to the unforced lazy seq constructed by lazy-seq and returns that

hiredman21:04:08

the type of a lazy seq doesn't change, regardless of if it has been forced or not

aryyya21:04:41

Ok, so the difference is basically negligible but version 1 is truly lazy since v2 starts creating that sequence (albeit a single element of it) when you call it even before it is realized.

hiredman21:04:33

correct, the difference in this case is negligible, but it can be larger, it depends on the amount of computing required to construct that initial element

aryyya21:04:54

Thanks for the explanation!

hiredman21:04:48

I am not sure I have come across a case where it mattered a lot, but in general I try and hoist lazy-seq calls up as high as possible so they wrap as much of the function body as possible

aryyya21:04:05

That makes sense.

ag22:04:51

can someone help me with a bit complex regex/replace problem. I need anything that matches to be wrapped one way, anything that doesn’t match the other way, e.g.: if given string like: “Donec vitae dolor color or sotamayor” I want to highlight everything that matches “or”, basically I want it to become something like:

[:span "Donec vitae dol"
 [:span.h "or"] [:span "col"] [:span.h "or"] [:span " "] [:span.h "or"] [:span "sotamay"] [:span.h "or"]

ag22:04:41

matching part is relatively easy… but I can’t figure out how to replace things that do not match

noisesmith22:04:47

@ag I'd be inclined to use the .find .end methods, each returns a numeric index you can use with subs

noisesmith22:04:25

and then use cons and recursive calls (maybe with lazy-seq even)

noisesmith22:04:22

take string, call .find get a start index, call .end get end index, cons two strings, then self-call

ag22:04:13

hmm… but why can’t it be two pass string/replace?

noisesmith22:04:46

string/replace could be possible, but I think the self-call cons approach is easier to think about

ag22:04:17

so like if I want for example wrap anything that doesn’t match “or” and place it between “^” and “$”… :

(clojure.string/replace
 "Donec vitae dolor color sotamayor"
 #"(?!or)"
 #(str "^" %1 "$"))
except it’s not working as I would like it to ;(

dpsutton22:04:29

(let [states {\o {:string :o}
              \O {:string :o}
              \r {:o :or}
              \R {:o :or}}]
  (reduce (fn [[acc [state buffer or-buffer]] c]
            (let [new-state (get-in states [c state] :string)]
              (case new-state
                :string [acc [:string (str buffer or-buffer c) ""]]
                :o      [acc [:o buffer (str c)]]
                :or     [(conj acc buffer (str or-buffer c)) [:string "" ""]])))
          [[] [:string ""]]
          "Donec vitae dolor color or sotamayor"))

[["Donec vitae dol" "or" " col" "or" " " "or" " sotamay" "or"]
 [:string "" ""]]

hiredman22:04:44

I am not sure regex syntax is flexible enough for what you want

hiredman22:04:06

but a regex is a kind of finite state automata, and automat is a more flexible way to construct those

hiredman22:04:30

I am no regex wiz, but I think your issue is, regex is a character by character scan, and you are trying to say, chunk things in to groups that are not this two character sequence

hiredman22:04:01

but a regex would only match the character sequence at a time, so even if it did work, you would get lots of two character slices

hiredman22:04:00

which is actually almost what you get with your ^$ example

noisesmith22:04:54

egret.run=> (re-split-seq "Donec vitae dolor color or sotamayor" #"or" (fn [x] [:span.h x]) (fn [x] [:span x]))
([:span "Donec vitae dol"] [:span.h "or"] [:span " col"] [:span.h "or"] [:span " "] [:span.h "or"] [:span " sotamay"] [:span.h "or"] [:span ""])

noisesmith22:04:05

imperfect, but it's a start

noisesmith22:04:50

(defn re-split-seq
  ([s re marked unmarked]
   (let [matcher (re-matcher re s)]
     (re-split-seq s re marked unmarked matcher 0)))
  ([s re marked unmarked matcher unmatched]
   (let [found? (.find matcher)
         start (when found? (.start matcher))
         end (when found? (.end matcher))]
     (if found?
       (cons (unmarked  (subs s unmatched start))
             (cons (marked (subs s start end))
                   (re-split-seq s re marked unmarked matcher end)))
       (list (unmarked (subs s unmatched)))))))

hiredman22:04:01

(or use java.util.Scanner)

ag22:04:53

I need it to work in Clojurescript (preferably)

hiredman22:04:06

use automat

noisesmith22:04:57

in js you'd want .search (returns index of start of match) and .lastIndex

noisesmith22:04:49

and you'd use a RegExp instead of matcher (I assume in cljs #"" is already a RegExp)

ag22:04:00

sorry guys… I got dragged into fixing an issue in an RC. Thank you all for your suggestions, I will try them! :spock-hand: @noisesmith @hiredman @dpsutton

ido03:04:35
replied to a thread:Hi, I have a simple TTL cache built around an `(atom {})` the logic that gets a value either finds an entry or gets a new one if the entry was missing or already expired (the loading of the entry involves a short Redis IO op). Dead simple. Now, I want to improve it and make it thread-safe. It is not _not entirely_ thread safe because 2 threads can find a missing/expired entry and trigger a load (redis call) simultaneously. How would you recommend locking the IO per key? 1. `(locking cache-key ...)` comes to mind but is not so the Clojure way (also, I’ll have to maintain an additional map of locks) 2. maintaining a map of entry as ‘loading’ `ref`s where every load from DB is a transaction on the corresponding ref. This also sounds overly complex. Any more inspirations?

@rutledgepaulv I wonder where are you aiming at. The core.cache implementation does not ensure that a fetch for a single key is called once. on the contrary:

(defn get-data [key]
  (cache/lookup (swap! cache-store
                       #(if (cache/has? % key)
                          (cache/hit % key)
                          (cache/miss % key (retrieve-data key))))
                key))
assumes that retrieve-data can be called multiple times since if multiple threads race on the missing key branch than the atom implementation will trigger a retry for the ‘loosing’ thread. Since the eviction policy I implemented is very naive (and that is quite okay for me), what I am looking for is just to ensure that retrieve-data is ensured to be called once per TTL expiry and not more. This is since I want to protect my DB against a flood of requests once the TTL of many object expires. @seancorfield maybe you have some ideas?