#clojure logs

2016-05-01

12:20jonathanjhmm, what the heck does this mean in the grand scheme of things: java.lang.ClassNotFoundException: clojure.java.shell, compiling:(documint/pdf.clj:53:10)
12:21jonathanjthis only seems to happen when trying to build the uberjar
12:22jonathanji'm calling (clojure.java.shell/sh ,,,)
12:22jonathanjdo i need to (require) it first or something weird?
12:23justin_smithjonathanj: there's nothing weird here - no namespace is available that somebody hasn't required
12:23justin_smithjonathanj: and best practice is of course to require it in each ns where you use it (even though you could technically use it if anyone has required it if you use the full name)
12:24jonathanjokay, i guess that makes sense i just never paid attention when doing stuff like clojure.core/something or clojure.string/something but i guess something probably does require those already
12:25justin_smithright, in a bare repl not even clojure.string or clojure.set are available
12:25justin_smiththough clojure.core is the one exception - without that you couldn't even require :)
12:25jonathanjis there a linter (or such) that could have caught this?
12:25justin_smithyes, eastwood
12:25justin_smithget it? linter eastwood
12:26justin_smithhaha
12:26justin_smithI've tried quite a few, ://github.com/jonase/eastwood
12:26justin_smitherr, bad paste
12:26justin_smithhttps://github.com/jonase/eastwood
12:29jonathanjthanks
12:29justin_smitheven "lein check" might catch that (but might not)
12:29jonathanjyeah, in retrospect it's kind of obvious that this wouldn't have worked but i guess lein or boot must've been requiring it already so it didn't break in development
12:30justin_smithlein check just turns on reflection warnings then compiles every clj file
12:30jonathanjwhat's bad about reflection?
12:31jonathanj(lein check emits a ton of warnings for me)
12:31justin_smithjonathanj: makes code 100-1000x slower
12:31jonathanjmmm
12:31justin_smith(well, maybe only 10x slower sometimes, but it's pretty bad for perf)
12:32jonathanjgood to know
12:33_maddyhow do I get just the keys from a map?
12:33justin_smith_maddy: you're gonna laugh
12:33justin_smith,(keys {:a 0 :b 1})
12:33_maddyno
12:33clojurebot(:a :b)
12:34justin_smithOK, you don't have to laugh
12:34_maddythanks, seems to do the trick
12:35kwladyka_maddy keep always open http://clojure.org/api/cheatsheet - it is really treasure for knowledge
12:35_maddynow lets say I have a map {}, I need to "add" stuff to it, which I guess means to make a new one, but then the map-function returns something else, so do I always need to do (into {} ?
12:35justin_smithor use a function that knows how to return a hash-map, sure
12:36justin_smith(eg. reduce-kv)
12:36kwladyka_maddy try to use this cheatsheet, really, in long term condition you will be happy with that. Just read all function in map section
12:37_maddykwladyka: thanks, bookmarked it
12:37kwladyka_maddy you will discover many interesting things
12:37justin_smith,(reduce-kv (fn [m k v] (assoc m k (inc v))) {} {:a 0 :b 2 :c 42})
12:37clojurebot{:a 1, :b 3, :c 43}
12:37justin_smithmatt_d: for third party libs, there is also specter
12:37justin_smitherr
12:38justin_smith_maddy: ^
12:40_maddyjustin_smith: I am adding a new key though, not altering the old ones, is that different?
12:40luma,(assoc {:foo 1} :bar 2)
12:40clojurebot{:foo 1, :bar 2}
12:40justin_smith_maddy: shouldn't be - as long as the info to add keys is somewhere in the input
12:41justin_smith_maddy: since you mentioned mapping I thought you were traversing the hash-map
12:41justin_smith(which is what reduce-kv is designed for)
12:41_maddynot traversing really, just adding a key
12:41justin_smithoh, then yeah, just assoc is all you need
12:42justin_smithassoc is var-args too
12:42justin_smith,(assoc {:a 0} :b 1 :c 2)
12:42clojurebot{:a 0, :b 1, :c 2}
12:47kwladykais it possible to write in schema https://github.com/plumatic/schema map has to have :id or :code or both?
12:48kwladykaor maybe i am using not the right tool?
12:48justin_smithkwladyka: you mean it needs one of the two, and can optionally have one of the others?
12:48kwladykai want prepare schema for data tapes and also required data
12:49kwladykajustin_smith {:id 1 :code "fsadfasd"} or {:id 1} or {:code "fdsfdsafads"}
12:49_maddythe problem is that I have a two-dimensional map, I need to add something to the inner maps (can't really understand how reduce-kv works)
12:49kwladykaperhaps i should use bouncer and schema together
12:50justin_smith(s/conditional :id {:id Number Keyword s/Any} :code {:code String Keyword s/Any})
12:50_maddyI know how normal reduce works
12:51justin_smith_maddy: reduce-kv is just like reduce, except it is optimized for hash-maps, and hands you the key and value as separate args
12:51justin_smith_maddy: maybe you can just use update-in or assoc-in ?
12:51justin_smithalso, reduce is a lot more flexible than people take it for at first glance (as is reduce-kv)
12:52_maddyyeah, I usually think of reduce as reducing a collection to single value
12:52justin_smith_maddy: a hash-map is a single value :)
12:52_maddysure
12:52justin_smiththanks to easy to use collections, a reduce can build up any structure you like
12:53_maddybut building up stuff feels contradictory to the name
12:53justin_smithyeah, I like the function, but the name (which is very historical) can be misleading
12:53kwladykajustin_smith the intention is not readable here but it should work
12:54justin_smithkwladyka: there could be a more idiomatic way to express it...
12:54justin_smithbut the semantics are right at least
12:54justin_smithor should be close to it
12:54kwladykai guess i will need some variants also, when X is present i also need Y and Z. Always complete. Not sure yet.
12:54justin_smithkwladyka: you could us s/conditional and then use functions that determine if a given variant is present
12:55justin_smithkwladyka: best option is stop using so many variant things!
12:55kwladykanot really sure what will be the end of requirements :) I am trying to write some schema for data like order, client, product, address to be consistent in whole system
12:56justin_smithkwladyka: one thing I like about regular schemas is that in the repl you can pprint them to remind yourself what the data here should look like
12:56kwladykajustin_smith i read about that, it should be helpful
12:57kwladykaanyway did you hear about some ready data schema for things like i describe?
12:57kwladykamaybe somebody did this work?
12:57kwladykaeven in table in english which i can rewrite to clojure
12:57kwladykait is hard work to design right schema
12:57justin_smithI have no idea... a library of common off the shelf schemas could be interesting
12:58justin_smithkwladyka: recently I did a massive refactor that would likely have been impossible without prismatic/schema - I captured the values the functions were getting from clients, then I wrote the strictest schemas I could that passed all those values, then wrote my new functions against those schemas
12:59justin_smithso much easier than trial and error when the data gets complex
12:59justin_smithand more accurate as documentation than any comments could be
13:00kwladykaschema looks cool, i think it will be very useful tool
13:01kwladykaespecially for REST API
13:03justin_smithkwladyka: you might be interested in ring-swagger for this https://github.com/metosin/ring-swagger
13:03kwladykajustin_smith cool thx
13:08jonathanjso how do i fix reflection warnings for code that is something like: (defn [reason] (if (instance? Exception reason) a b))?
13:09alex-weejis there an os.path.join equivalent in clojure?
13:09justin_smithjonathanj: that's a tricky one
13:09justin_smithalex-weej: what is os.path.join
13:09jonathanjit joins several OS path components together with the OS-specific separator
13:10alex-weejand also deals with segments starting with a / so jumping back to the root
13:10kwladykajonathanj http://clojure.wladyka.eu/posts-output/2015-08-24-how-to-improve-algorithm-speed.html#avoid_reflections
13:10alex-weejos.path.join(“foo”, “bar”, “/baz”) == “/baz”
13:10alex-weejassuming pathsep is /
13:11_maddyok, I am not getting it, lets say I have map of maps: { "A" { :key 1 } }, how do I add new key/value to the inner maps? And by calculating that, I need the key of the inner map
13:11kwladykajonathanj and there you have ready solution https://www.refheap.com/8bff42793e9abbeb9af803b23
13:12kwladykato not throw an exception if you don't have class loaded
13:12kwladykathis one is hard one to solve :)
13:14justin_smith,(java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "quux"])) ; alex-weej this is ugly, but it works
13:14clojurebot#object[sun.nio.fs.UnixPath 0xfe5389 "foo/bar/baz/quux"]
13:15justin_smithif you call str on it you get the path as a string
13:15justin_smithalex-weej: https://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html
13:15jonathanjkwladyka: that's not what the code does
13:16alex-weejis there some project to wrap java APIs in more clojure-friendly terms btw?
13:16kwladykajonathanj ?
13:16jonathanjkwladyka: the code does a if the object is an instance of an exception and b if it's not an instance of exception
13:16alex-weejwould be cool to collect some of the more “obvious” bindings
13:16justin_smithalex-weej: there are N+1 projects
13:16jonathanjkwladyka: whether the class is loaded or not is not really important, unless i'm missing something
13:16justin_smithalex-weej: clojure is a java library, it's all accessible, and sometimes people want to add a friendly layer on top
13:16kwladykajonathanj ok maybe i mentioned about that unnecessary
13:17kwladykajonathanj did you look on http://clojure.wladyka.eu/posts-output/2015-08-24-how-to-improve-algorithm-speed.html#avoid_reflections ?
13:17alex-weejjustin_smith: sure, i’m just wondering if i can pull-request a library of wrappers for things like java.nio.file
13:17jonathanjkwladyka: not yet
13:17alex-weejthis doesn’t work anyway, user=> (str (java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "/quux"])))
13:17alex-weej"foo/bar/baz/quux"
13:18kwladykajonathanj it should explain how to solve your problem
13:19shiranaihito,(str (java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "/quux"])))
13:19clojurebot"foo/bar/baz/quux"
13:19shiranaihitowhat's wrong with that? :)
13:19justin_smithalso, that's super easy to wrap in a vararg string function
13:20bacon198`alex-weej: a good number of projects are trying to making the java libraries more friendly
13:20jonathanjkwladyka: i don't actually understand how it solves my problem
13:20bacon198`which is great, because you get tried and tested libraries being wrapped nicely
13:20jonathanjkwladyka: the problem is that i cannot provide a type hint to a value that has a dynamic type
13:20shiranaihitobacon198` i sure hope they're not wrapping some goddamn commons-turdnuggets from 1998 or something
13:20alex-weejIn [2]: os.path.join("foo", "bar", "/baz")
13:20alex-weejOut[2]: '/baz'
13:21shiranaihitoah.. Python :P
13:21jonathanji think i'm going to have to change the calling code to convert Exception so that i don't need the test
13:21shiranaihitoalex-weej what do you mean with that though? does python just ignore the first two elements? is that what you want?
13:22TimMcalex-weej: I believe that reducing over the segments with the File constructor does what you want, if no one has mentioned that...
13:22justin_smithTimMc: not with the example he gave
13:23TimMcHmm, lemme find the code of mine that does this...
13:24TimMcAh, yeah, I see I ran into that problem as well.
13:25TimMchttps://gist.github.com/timmc/de9251eb5343bcc72ef20347ef24026c
13:25TimMcNeeds cleanup, since I wrote it quite a while ago. :-)
13:25justin_smithTimMc: yeah, line 6 should be 3 lines, but it's not super bad
13:26kwladykajonathanj maybe i miss something but what you pasted here doesn't throw reflection wartning
13:26kwladykajonathanj are you sure where is the source of this warning?
13:26TimMcjustin_smith: I also don't need to capture f2, I can just use it and discard it in the conditional.
13:26kwladyka(defn foo [x] (instance? Exception foo)) is really free of this warning
13:27kwladykai mean (defn foo [x] (instance? Exception x))
13:28justin_smithkwladyka: I was skeptical so I double checked, you're right
13:28kwladykajonathanj so i pasted you my article to help you find the right place which makes this warnings
13:29shiranaihitoalex-weej or you can join some strings and give them to File
13:29shiranaihito,(str (java.io.File. (clojure.string/join "/" ["foo" "bar" "baz"])))
13:29clojurebot"foo/bar/baz"
13:30kwladykajustin_smith i checked that too twice :)
13:30justin_smithshiranaihito: fails on alex-weej 's example though
13:30alex-weejdoesn’t work when one of the segments is an absolute path e.g. my example
13:30shiranaihitook
13:30shiranaihito,(str (java.io.File. "/foo" (clojure.string/join "/" ["bar" "baz"])))
13:30clojurebot"/foo/bar/baz"
13:31justin_smiththat isn't any better
13:32shiranaihitowell it does start with an absolute part :P
13:33shiranaihitoif one of the elements denotes an absolute path, it probably goes in first anyway
13:38justin_smithalso, platforms are allowed to use separators other than "/"
13:40TEttingerJ:☃Users☃Justin☃Code☃
13:41shiranaihitojustin_smith and that means my little snippet was bad? :P
13:41justin_smithshiranaihito: it's a second way it doesn't address the initial question
13:42justin_smithwhich explicitly mentioned using the system's native separator
13:42shiranaihitochill :)
13:42kwladykashiranaihito i believe i saw some ready solution for that in the past.... maybe
13:43shiranaihito,(str (java.io.File. (str java.io.File.separator "foo") (clojure.string/join java.io.File.separator ["bar" "baz"])))
13:43kwladykabut it can be my imagination
13:43clojurebot#error {\n :cause "java.io.File.separator"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.io.File.separator, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "java.io.File.separator"\n :at [java.net.URLClassLoader$1 run "URLClassLoade...
13:43shiranaihitoalright.. something like that anyway :P
13:43shiranaihitokwladyka solution for what? the file path stuff?
13:43justin_smith,java.io.File/separator
13:43clojurebot"/"
13:43shiranaihitoyeah, just realized
13:44kwladykashiranaihito some library to do that or Java function.... i don't really remember. Some solution to make the right path
13:44shiranaihitoyeah, it's not that complicated
13:44shiranaihitoi figured joining strings and then just handing them to File would be "neater"
13:44shiranaihitoor simpler (etc whatevs) than reducing with Files
13:45kwladykai believe anyway you miss many not obviously things, like for example different systems
13:45kwladykapath in the windows for example can looks like c:/foo/bar
13:45shiranaihitosure, but that's what further development is for :p
13:45shiranaihitowe're just swapping snippets to help people
13:50_maddymy god, after all this work I have a data structure which looks really cumbersome..
13:54alex-weejis there some popular or built in library for running subprocesses and dealing with their events (e.g. stdin/stderr output, process exit) via an event loop or something?
13:56shiranaihitoalex-weej: Java *kind of* has support for that
13:56shiranaihitolook at ProcessBuilder for example
13:56justin_smiththere's ProcessBuilder and also conch which wraps ProcessBuilder / Process
13:56shiranaihitobut for whatever it's worth, i couldn't get communicating with subprocesses to work when i tried
13:57justin_smithshiranaihito: each Process object has two inputstreams and an outputstream
13:57shiranaihitoyeah
13:57shiranaihitoas far as i know, i was using it right.. not 100% sure ofc
13:58justin_smithI've done it before, it worked fine
13:58shiranaihitobut something was wrong when trying to do input/output with processes
13:59alex-weejconch looks interesting thanks - wondering if i should try to shoehorn something into core.async
14:00alex-weeji want to have a bunch of subprocesses running at any one time and just select on their events
14:04justin_smithalex-weej: you could have regular threads that glock on read from the inputStream of the processes
14:05justin_smithalex-weej: don't do that in go blocks, go blocks are not for blocking operations
14:05alex-weejone per process?
14:05justin_smithyeah, and a single go block reading the results they put on the channel
14:05alex-weejsounds simple enough - is it actually reasonable straightforward to start threads in clojure?
14:06kwladykaalex-weej what exactly do you want to achieve? maybe you want just share state?
14:06alex-weeji just want to run a set of subprocesses and then multiplex their events in a loop
14:07alex-weejevents are like - ready for read on stderr, ready for read on stdout, ready for write on stdin, process terminated with exit code N
14:08justin_smithalex-weej: shiranaihito: simple repl example of i/o with a process in the repl (in a real example you would read to a byte-array, not read a byte at a time, of course)
14:08justin_smithhttps://gist.github.com/noisesmith/f2ca73a0a6b0e5d686487c6084196a97
14:08alex-weejif this was low level linux i would fork and exec and do some fd sharing, and just epoll the fds without the use of any threads
14:08justin_smithalex-weej: the api doesn'
14:08justin_smitht expose "ready for" anything, sadly
14:09justin_smithwhich is why I mentioned threads doing blocking reads/writes
14:10shiranaihitojustin_smith thanks :) i think my main problem was taking stuff from one process and handing it into another, but i just scrapped what i was doing and went with Python instead
14:10shiranaihito.. and Python did exactly what i wanted with like a couple of lines of code :)
14:11justin_smithshiranaihito: the biggest gotcha is needing to do the .flush method iirc
14:11shiranaihitoi'm pretty sure i flushed stuff too.. i've used Java for a long time
14:12justin_smiththe problem with system stuff in java is it is committed to the lowest common denominator, and there are some really low targets it had to hit in the past (Win9x etc.)
14:12justin_smithshiranaihito: oh, OK
14:12justin_smithshiranaihito: I built a crazy system that piped the contents of a 16 channel sound card to 16 separate programs in clojure - which was amazing and also a pain in the ass
14:12justin_smithbut it worked!
14:12shiranaihitobasically i was trying to: start a process, feed it input, wait for it to complete (working on the input), and then hoping to take out whatever it produced.. and hand it off to another process
14:13justin_smithshiranaihito: see, the people who wrote the software spec assumed there was a "read one channel of a sound card" api - which of course doesn't exist anywhere
14:13shiranaihitowow, sounds hard-core
14:13justin_smithI didn't really grok core.async until I completed that project :)
14:13shiranaihito:)
14:13shiranaihitoi haven't even tried using it yet
14:14jonathanjcan i add a type hint to a parameter inline?
14:14jonathanj`(.someMethod obj ^long value)` for example
14:15justin_smithalex-weej: a lot of the stuff you are trying to do is easier in pixie, which is still kind of experimental, but it's a clojure implemented using rpython's compiler (but there is no python available at runtime mind you)
14:15shiranaihito"inline"?
14:15justin_smithjonathanj: yeah, that should work
14:15kwladykajonathanj why not in the definition of function?
14:16kwladykai mean in the parameters
14:16jonathanjkwladyka: because it's just a minor intermediate result
14:18kwladykajonathanj i guess more readable it will be when you use ^long somewhere when this result comes, i don't know what you use, let or something
14:22_maddyhow do I configure cider repl so that I have to use ns in front of functions (I want to have functions of same name in 2 files)
14:23kwladyka_maddy just use namespaces when call this functions
14:24kwladykafoo/f and bar/f
14:24hodwikIf I want to send a header param as part of a post with clojure-http, do I just make a map {:headers {:API_KEY
14:24hodwik"APIKEY"}}
14:24hodwikand send that as part of the post?
14:28alex-weejis there a common idiom or builtin for combining let with if? e.g. (let-if [x y] then else) -> (let [x y] (if x then else)) - to avoid repeating x
14:29ridcully_hodwik: that's how it works in clj-http. did you mean this or the clojure-http-client lib?
14:30hodwik@ridcully sorry, that's what I meant
14:33jonathanjthe type hints from protocols are disregarded in defrecord implementations?
14:33kwladykaalex-weej if-let still you don't try use cheatsheet, just click there ctrl+f in your browser
14:34hiredmanthey don't exist
14:35hiredmane.g. you can attach metadata to the parameters in a protocol, but it doesn't do anything
14:35alex-weejkwladyka: i see it’s spelled if-let, that makes more sense actually!
14:35alex-weejthanks
14:36hodwikCould anyone with clj-http experience tell me why this: http://pastebin.com/8nwSeqVA is spitting out:Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to [B, compiling:(stfr_bot/core.clj:74:1)
14:36hodwikthe variables are all def'd before that section
14:38ridcully_hodwik: i think it has to be :json there. also i doubt it will deal with the json conversion anyway
14:40ridcully_hodwik: something like this: https://github.com/christoph-frick/rest-repl/blob/master/src/rest/public.clj#L56-L59
14:41TEttinger[B is that wacky stacktrace-speak for byte array
14:45justin_smith,(class (.getBytes "foo"))
14:45clojurebot[B
14:46hodwikridcully: Awesome! Thanks so much. I was trying to use Cheshire to encode my json, but just doing it with clj-http was much easier
14:49_maddyhow do I pass-through variable arguments to another function? I can create optional args with &, but they are set to nil (and sent as nil to the next func, which is a problem)
14:49justin_smith_maddy: if you use arity overloading instead of &, then it's much easier to provide defaults
14:50justin_smith,((fn foo ([] (foo
14:50clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
14:50justin_smitherr
14:50justin_smith,((fn foo ([] (foo "hi")) ([message] message)))
14:50clojurebot"hi"
14:51_maddyI could use arity overloading, but it looks like then I have to repeat the function body multiple times
14:51_maddywhich is not nice
14:51justin_smith_maddy: no, that's never needed
14:51justin_smith_maddy: look at my example, no repitition
14:52justin_smith,((fn f ([] (f 2)) ([x] (* x x x)))
14:52clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
14:52_maddyoh, but the problem is that I don't want to define defaults here, they are defined in the inner function which I am calling
14:52justin_smith,((fn f ([] (f 2)) ([x] (* x x x))))
14:52clojurebot8
14:52_maddywhere I already have arity overloading pattern
14:53_maddyI think I am too tired, have to continue on another day :)
14:53_maddyreally liking clojure now that I am slowly starting to understand it
16:05beakyi love clojure too
16:23jonathanjif i have a protocol method defined like (foo [this ^SomeObj x]) and i have the implementation (on defrecord, for example) like (foo [this ^SomeObj x]) then i get a compile error like: Can't find matching method: foo, leave off hints for auto match.
16:24jonathanjif i omit the type hint for the implementation then it compiles but `x` is not type hinted
16:29TimMcCould it be that you need to throw more type hints at it? I haven't worked with protocols recently, but I wonder if "this" or the return value need hinting (seems like overkill though).
16:33amalloyprotocol functions don't support type hinting anyway
16:44jonathanjhow do i unambiguously import two java classes with the same name?
16:44clojurebotexcusez-moi
16:47amalloythe same way you do it in java: only import one of them, and refer to the other fully-qualified
16:49jonathanji don't recall ever having to do this in java, so i wasn't aware if there was another way
16:49TimMcThere's another option, which is .importClass...
16:49jonathanjC# has some way to alias stuff, iinm
16:51TimMcIf you don't mind potentially messing up some automated tooling and IDEs, you can do (.importClass *ns* 'RLN foo.bar.ReallyLongName)
16:51TimMcstick that right after your ns block and say two Hail Marys
16:52jonathanjhaha, i'll just go with the fully qualified option
16:57TimMcI've done this once and never had a problem with it, just... you know, fair warning.
17:02jonathanjlike that guy who puts his hand into the crocodile's mouth and doesn't get bitten, then he calls his friends over to see his neat trik
17:08TimMcjonathanj: There are two risks: 1) It might go away (binary .importClass is not used anywhere I can see in 1.7.0), and 2) tools might expect all imports and requires to be parseable from the ns block.
17:08TimMcSo: Possibly annoying, but it's not like the program will behave incorrectly if it runs at all.
17:24fikgolwhy storm used maven instead of leiningen after 0.9 ?
17:25TEttingerfikgol: I might be thinking of a different storm
17:34TEttingerfikgol, ah https://github.com/apache/storm/pull/14
17:34TEttingerapparently their build process is complex
18:03vermiculusi've got an algorithm challenge if anyone fancies a crack at it
18:03vermiculusit's a recursive question involving maps
18:06TEttingerme crack
18:07vermiculusTEttinger: :)
18:07vermiculusSay you have a structure like {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}}
18:08vermiculusNotice that this is pretty much a tree of slugs
18:08vermiculusI'd like to get the structure {1 "/lovely" 2 "/lovely/lovelier" 3 "/lovely/loveliest" 4 "/cool"}
18:08justin_smithoh, nice, a graph
18:09vermiculus:-)
18:10justin_smithvermiculus: what would you want if something had :parent 3?
18:10justin_smithwhat if 5 had :parent 6 and 6 had :parent 5? what would print then?
18:10vermiculusjustin_smith: I'd say behavior is undefined in those cases.
18:10vermiculusProbably throw some sort of error.
18:11justin_smithso you have a representation that can do arbitrary graphs, but behavior is only defined for tree (directed and acyclic)
18:11vermiculusjustin_smith: correct
18:11vermiculusturning the starting structure into a tree is, of course, a valid approach
18:16TEttinger,(let [structure {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}}] (into {} (map (fn [[k {:keys [parent slug]}]] [k (str (get-in structure [parent :slug] "") "/" slug)]) structure))) ; not yet ready
18:16clojurebot{1 "/lovely", 2 "lovely/lovelier", 3 "lovely/loveliest", 4 "/cool"}
18:17TEttingerthis only handles one level, which is the first problem
18:17TEttingerthe lesser problem is not getting the opening / right
18:18justin_smith(get-in structure [parent :slug] "/")
18:18justin_smithshoud work!
18:19justin_smithoh, wait
18:19justin_smithnever mind, your thing is good, you just need to make it recursive
18:34vermiculusI have a solution now, but it's pretty ugly :)
18:35vermiculusIt's also a little cheat-y IMHO
18:35vermiculushttps://gist.github.com/vermiculus/c8a531a86a0a65cdb9af4a466ed0721f
18:38vermiculus,(defn get-topic-children [topics topic-id] (map first (filter #(= topic-id (:parent (second %))) topics)))
18:38clojurebot#'sandbox/get-topic-children
18:39vermiculus,(defn get-routes [topics topic-id & [slug-so-far]] (let [children (get-topic-children topics topic-id) newslug (if (= topic-id :root) "" (str slug-so-far "/" (:slug (get topics topic-id))))] (if children (into (if (= topic-id :root) {} {topic-id newslug}) (map (fn [child-id] (if child-id (get-routes topics child-id newslug))) children)) {topic-id newslug})))
18:39clojurebot#'sandbox/get-routes
18:39vermiculus,(get-routes {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}} :root)
18:39clojurebot{1 "/lovely", 2 "/lovely/lovelier", 3 "/lovely/loveliest", 4 "/cool"}
19:03vermiculusTEttinger: Feel free to ping me on twitter if you find a cleaner solution :-) (same username: @vermiculus)
20:02asdf12z_(defroutes app (GET "/ws" request (ws-handler request))) can someone explain to me how does "request" work here? this is compojure
20:02asdf12z_how is request even defined?
20:02asdf12z_like how is it possible to pass `GET` the result of (ws-handler request) when request isn't defined yet?
20:03asdf12z_i'm guessing its part of the macro magic
20:03justin_smithasdf12z_: defroutes is a macro, and it's binding the client's request object to the symbol 'request
20:03justin_smithasdf12z_: in normal clojure macros, request would be in a vector (eg let or defn)
20:04justin_smithI guess they decided compojure does not need a vector, because your handler is guaranteed to receive exactly one argument? not sure
20:05asdf12z_i guess i'm just confused as to how the code is evaluated and executed, so everything in defroutes doesn't actually eval yet, it's all fed in, and the macro then fills in for all the argument stuff like request
20:05asdf12z_is that about right?
20:05justin_smithwell macros are allowed to do anything they want to their input - take it as is, evaluate it in the lexical environment, whatever
20:06justin_smithmacroexpand might be informative here
20:08asdf12z_ok thanks justin_smith