Fork me on GitHub
#clojure
<
2016-11-18
>
manderson03:11:37

I have a namespace with a gen-class function in order to generate a single java class with a static method (something like this: https://gist.github.com/david-mcneil/435822#file-gen-class-ex-clj-L42-L47). I'm working on a library so I don't want to create an uberjar, but it appears that the only way to get this class in my jar is to add :aot for the namespace in the project.clj, which includes all of the dependencies and transitive dependencies as well. Is there any way to simply generate the one class? If not, is there a best practice for how to handle this?

Alex Miller (Clojure team)04:11:35

you could just write it in Java

Alex Miller (Clojure team)04:11:09

lein knows how to compile and include Java classes already

roelofw06:11:31

I have done almost all clojure koans. Can I better do a lot of 4clojure to practice more with clojure or can I try to make a small web app with for example luminus ?

seancorfield06:11:50

At this point @roelofw I'd recommend doing the 4clojure problems to practice more before you try tackling something like Luminus...

roelofw06:11:53

I was thinking about porting a ruby app to clojure with json reponses and maybe some sort of caching

seancorfield06:11:35

If you want a simple web app "framework", take a look at FW/1 which is what we use at work https://github.com/framework-one/fw1-clj (it's a small, convention-based wrapper for Ring, Compojure, and Selmer).

roelofw06:11:38

@seancorfield so first the 4clojure problems and then luminus ?

roelofw06:11:44

@seancorfield looks nice, First I have to find out how boot can be installed. Till now I only have worked with leiningen

seancorfield06:11:56

Boot is definitely worth learning.

roelofw07:11:03

also I do not know if cursive can work with boot

seancorfield07:11:23

Hmm, no idea. At work we switched from Leiningen to Boot about a year ago as we were finding Leiningen too limiting for the sort of build tasks we needed.

roelofw07:11:23

oke, I was thinking about a 2 page web app. where on the first page 10 paintings are seen and on the second page a detail page of a painting is seen

roelofw07:11:57

later on I could make pagination to the first page so multiple pages can be seen

roelofw07:11:25

the paintings come from a external api with json responses

seancorfield07:11:19

CIDER (and Emacs) has full support for Boot. I guess I'm a bit surprised other editors don't.

seancorfield07:11:05

I gather Cursive is somewhat held back by needing to support Java 6 since that's what IntelliJ inflicts on it, at least on Mac?

roelofw07:11:50

No idea, I have to ask the maintainer of cursive

seancorfield07:11:44

Colin is pretty responsive and Cursive is an impressive piece of tech. I know he's frustrated by having to maintain that level of backward compatibility.

seancorfield07:11:14

Still, if the only consideration is needing a project.clj file, you could create a new FW/1 project via the template and then convert build.boot to project.clj and stay with that 🙂

roelofw07:11:50

First trying to make the elementary and easy problems and then look for the web app . Sounds to me like a good plan

seancorfield07:11:53

(but, yes, you would need the boot.sh or boot script installed -- it's easier to set up than Leiningen to be honest)

roelofw07:11:36

for me it would be boot.exe because I work on Windows 10

roelofw07:11:53

@seancorfield thanks a lot for sharing info and make your reccomendation

seancorfield07:11:15

@roelofw I use Boot on Windows 10 (as well as Mac and Linux).

seancorfield07:11:48

I'd forgotten it was a .exe file -- usage is pretty seamless across all three platforms.

roelofw07:11:29

I must say that the first 14 problems of 4 clojure are dead simple

roelofw07:11:57

Can you recommend a json library so I can parse the json response to a clojure object

seancorfield07:11:14

Cheshire is the gold standard.

seancorfield07:11:44

FW/1 uses Cheshire automatically (I should have included that with Ring, Compojure, and Selmer above).

roelofw07:11:21

oke, I will look at FW/1 in a short time

roelofw07:11:49

First trying to do the elementary and easy problems of 4 clojure

roelofw07:11:45

@seancorfield thanks a lot for your time

roelofw08:11:53

@seancorfield there is no tutorial where a page is made with FW/1 ?

borkdude10:11:43

what is FW/1?

lboliveira11:11:35

Hi, I am trying to create a macro to declare a dynamic var. I am losing the ^:dynamic information and and I don’t know why. Any ideas?

(defmacro declare-dyn [name]
  `(declare ^:dynamic ~name))

(declare-dyn foo)

(binding [foo 42] foo)

CompilerException java.lang.IllegalStateException: Can't dynamically bind non-dynamic var: user/foo

moxaj11:11:33

@lboliveira try

(defmacro declare-dyn [name]
  `(declare ~(vary-meta name assoc :dynamic true)))

lboliveira11:11:41

@moxaj It worked! Thank you 😃

escherize11:11:56

How should I go about making a spec for a joda time? (such as created with (clj-time.core/now))?

escherize11:11:01

I guess... use satisfies? and spec/with-gen and build my own generator. But does one exist already?

mpenet13:11:41

@escherize you can use a large-integer* and use from-long: (fmap clj-time.coerce/from-long (large-integer* {:min start-epoch :max end-epoch}))

mpenet13:11:56

a minimal version would be (fmap clj-time.coerce/from-long large-integer), but you'll end up with some odd dates

Alex Miller (Clojure team)13:11:01

Another option in 1.9 would be to extend the joda instant to the new Inst protocol. If you do that, then inst? will work and the s/inst-in spec will work

Alex Miller (Clojure team)13:11:31

Date is covered this way and Java 8's Instant

mpenet13:11:07

sweet, I didn't know about inst?

manderson13:11:37

Thanks @alexmiller (re: my post on aot last night), as soon as I walked away from my computer I figured I should just write it in java. Just curious, though, is the fact that all of the clojure dependencies of the aot namespace are compiled just an artifact of how lein chooses to handle it or is that an implicit requirement in how gen-class works? Would it theoretically be possible to only compile the gen-class class?

manderson13:11:31

gotcha. thanks.

roelofw13:11:50

Does anyone know if Sublime Text or Atom can work with boot. So I can make a app with boot and do boot run without using a external terminal

spacepluk13:11:46

no assoc-in! for transients?

hugesandwich15:11:33

Is there anything in Clojure resembling Akka and actors yet but more CSP-oriented (distributed, long-running graphs of CSP channels, heavy on queues, backpressure, etc.)? I am aware of Quasar and Pulsar, but at that point I would just use Akka for various reasons. I also know about and use Onyx, but it's not a fit for some of my use-cases. I currently have some form of scale-out via Kafka consumers/producers, but this is only a piece of a larger solution.

si1415:11:54

how would you convert a string value to a keyword in a nested JSON coming from a server? I'm trying to use clojure.spec, but I'm somewhat confused if I should use a custom conformer. In Prismatic's Schema coercion is kinda obvious, but is it an intended use for clojure.spec?

si1415:11:01

So I did it like this; is it the correct/intended way?

Alex Miller (Clojure team)16:11:28

the general caveat is: be careful about your use of conformers, particularly in registered specs. You are making decisions for all future consumers of your specs and (like here) potentially throwing away information (there is no way to tell from the conformed value here whether you received a string or a keyword).

roelofw16:11:21

some boot expert here : when I do boot run I see this error message :

boot run
        clojure.lang.ExceptionInfo: No such task (run)
    data: {:file
           "C:\\Users\\rwobb\\AppData\\Local\\Temp\\boot.user3125771616484661687.clj",
           :line 7}
java.lang.IllegalArgumentException: No such task (run)
          boot.core/construct-tasks  core.clj:  905
                                ...
                 clojure.core/apply  core.clj:  630
                  boot.core/boot/fn  core.clj:  949
clojure.core/binding-conveyor-fn/fn  core.clj: 1916
                                ...  

roelofw16:11:26

My build.boot looks like this :

(def version "0.1.0-SNAPSHOT")

(task-options!
 aot {:namespace   #{'myfw1app.main}}
 pom {:project     'myfw1app
      :version     version
      :description "FIXME: write this!"}
 jar {:main        'myfw1app.main
      :file        (str "myfw1app-" version "-standalone.jar")})

(set-env! :resource-paths #{"src" "resources"}
          ;; the org.clojure/clojure dependency here only affects
          ;; what is bundled in the uberjar via the build task so
          ;; be careful if it is different to the version you have
          ;; configured for Boot!
          :dependencies   '[[org.clojure/clojure "RELEASE"]
                            [framework-one       "RELEASE"]
                                        ; comment this out if you don't want
                                        ; to use http-kit at all:
                            [http-kit            "RELEASE"]])

(deftask build []
  (comp (aot) (pom) (uber) (jar) (target :dir #{"target"})))

(deftask run
  [p port    PORT    int      "the port on which to run the application."
   c config  ARG=VAL {kw str} "the config map for the application."]
  (require '[myfw1app.main :as app])
  ((resolve 'app/start) port config))

(defn- generate-lein-project-file!

  [& {:keys [keep-project] :or {:keep-project true}}]

  (let [pfile (io/file "project.clj")

        pname (or (get-env :project) 'boot-project)

        pvers (or (get-env :version) "0.1.0-SNAPSHOT")

        prop #(when-let [x (get-env %2)] [%1 x])

        head (list* 'defproject pname pvers

               (concat

                 (prop :url :url)

                 (prop :license :license)

                 (prop :description :description)
 

roelofw16:11:44

the last two I added because I want to work with cursive and boot

hwk17:11:23

alright, I've decided it's high time I learn how to use css. So my goal is to (1) use a css 'pocketbook' (2) work through all the tedious examples, and (3) do everything directly in clojure, instead of writing actual *.css file. On the cljs side, I'm using figwheel + devcards -- what clojure css library should I use to have everything work together nicely?

blkt17:11:43

could anyone give a simple explanation of why boot is so cool nowadays?

blkt17:11:58

it seems ant, or (even worse) setuptools to me

npeckman17:11:47

It allows you to write your tasks using clojure code instead of a DSL which is pretty cool. Task writing and composition is pretty easy with it.

blkt17:11:49

I see...

hwk17:11:38

is this one of those situations where "declarative is all nice and all that, but really doesn't match the problem domain" ?

dm317:11:51

delcarative is fine for simple things

dm317:11:07

ir breaks when you want to create abstractions

bfabry18:11:52

worth pointing out though that you usually need to get to a pretty hefty level of complexity in your build process before lein falls down

hwk18:11:35

as someone writing a forth based interpreter, clearly the solution is to embed a forth interpreter inside lein 🙂

noprompt18:11:01

forth is awesome.

noprompt18:11:14

concatentative programming ftw.

roelofw18:11:36

@seancorfield I have fw/1 with a standard template working

roelofw18:11:58

Any examples I can study for controllers and so on ?

si1419:11:01

@alexmiller I see, thank you!

lwhorton19:11:29

I’m having a misunderstanding about protocols and records when defining the entities for my system, and was hoping someone could clarify:

lwhorton19:11:51

Suppose I have two entities A and B that share common traits such as - they have names, unique ids, and perhaps a “status” that might be some map such as {:last-known “” :current- “”}. What I feel like doing (whether its idiomatic or not I’m sure) is defining a “statusable” protocol, and having separate defrecord A and B that implement statusable.

lwhorton19:11:24

But really that protocol isn’t much of a function, it’s more like a flag demarking “hey I have this object representing a status”.

lwhorton19:11:58

Is there a better way to defrecord a field that is a map, or a field that points to a map?

lwhorton19:11:10

Or by definition is a record only a collection of primitive values?

eraserhd19:11:27

@lwhorton You can have any value in a record field.

bfabry19:11:13

I think a protocol for statusable would be reasonable if you require the polymorphism

bfabry19:11:31

but if they both use the same key for their status information you don't require the polymorphism

eraserhd19:11:32

But also, don't shy away from maps. Using records is useful as a performance optimization or to implement existing protocols or Java Interfaces.

lwhorton19:11:13

Okay, great .. thanks both @bfast @eraserhd. It seems I’m thinking about protocols on the wrong level where a map will just work. Do you have an example @eraserhd of a defrecord with a complex type as a field? I cant find one anywhere

eraserhd19:11:15

Q: So, for like the fourth time recently, I've wanted something like defmulti/defmethod, except with multiple methods invoked for one multi invocation. I find it strange I've not heard of anyone doing this. Are there things?

eraserhd19:11:55

@lwhorton Here's a thing from rewrite-clj. "children" is a collection of other nodes. https://github.com/xsc/rewrite-clj/blob/master/src/rewrite_clj/node/forms.clj#L6

lwhorton19:11:13

muchas gracias

bfabry19:11:16

@eraserhd sounds sort of like observer pattern? I assume those methods are causing side-effects

eraserhd19:11:06

In this case, the results are combined with merge.

eraserhd19:11:30

In a previous case, I wanted to register transducers which could process things in any order.

eraserhd19:11:06

Can't remember the time before that.

bfabry19:11:01

mmmmm, I think the "deciding what to do with the results" bit fights against there being a general solution for that

eraserhd19:11:18

I don't mind writing the dispatch/combining code, but how to write the registration?

eraserhd19:11:34

Right now I kind of cheat and use a defmulti and manually call methods with (methods ...).

eraserhd19:11:44

Which works, and I don't have to worry about implementation concerns about namespaces and loading, but it's kind of awkward to throw away the dispatch key and all.

bfabry19:11:48

write a macro that registers the function somewhere?

eraserhd19:11:52

I'm wondering about, for example, atoms or volatiles, or using a defrecord with fields, and what kind of things we have to worry about wrt concurrency at namespace load.

bfabry19:11:58

(def listeners {})

(defmacro defn-listener [name key args & body]
   `(let [fn (defn ~name ~args ~@body)]
      (alter-var-root #'listeners #(...))))

bfabry19:11:01

something like that?

eraserhd20:11:01

yes. Is that a good practice, just using alter-var-root?

bfabry20:11:41

if you want to build this all up at compile time, and dispense with some boilerplate I think it seems reasonable. but I'm not going to make any claims to it being good practice ¯\(ツ)

bfabry20:11:59

you could also use a ref or an atom

hwk21:11:27

(fn [x] (if (vector? x) x (apply list x))) is there a builtin for this? "if a vector, in O(1) return itself; if a list, in O(n) create a vector"

tom21:11:19

@hwk Not sure how it behaves under the hood but might this work? http://clojuredocs.org/clojure.core/vec

hwk21:11:40

it has to be a vector, but then not satisfy some protocol

seancorfield21:11:02

@roelofw: there's a mini address book example in the repo you can look at (FYI I'm on vacation thru Sunday so I may not be around to answer questions much)

hwk22:11:48

Is there a more idiomatic way to implement this (sorta-cond) ? (defn pick-first [x lst] (loop [lst lst] (when (not-empty lst) (let [[k v] (first lst)] (if (k x) (v x) (recur (rest lst)))))))