Fork me on GitHub
#beginners
<
2019-06-08
>
johnjelinek03:06:37

how do I call a non-main static clojure method from the CLI?

johnjelinek03:06:45

code:

(ns clj.core
  (:gen-class
   :methods [^:static [handler [String com.amazonaws.services.lambda.runtime.Context] String]]))

(defn -main [& args]
  (println "Hello, World!"))

(defn -handler [s]
  (str "Hello " s "!"))

johnjelinek03:06:58

# java -cp target/clj.jar clojure.main -m clj.core

Hello, World!

johnjelinek04:06:22

# java -cp target/clj.jar clojure.main -m clj.core.handler

Exception in thread "main" java.io.FileNotFoundException: Could not locate clj/core/handler__init.class, clj/core/handler.clj or clj/core/handler.cljc on classpath.
        at clojure.lang.RT.load(RT.java:466)
        at clojure.lang.RT.load(RT.java:428)
        at clojure.core$load$fn__6824.invoke(core.clj:6126)
        at clojure.core$load.invokeStatic(core.clj:6125)
        at clojure.core$load.doInvoke(core.clj:6109)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.core$load_one.invokeStatic(core.clj:5908)
        at clojure.core$load_one.invoke(core.clj:5903)
        at clojure.core$load_lib$fn__6765.invoke(core.clj:5948)
        at clojure.core$load_lib.invokeStatic(core.clj:5947)
        at clojure.core$load_lib.doInvoke(core.clj:5928)
        at clojure.lang.RestFn.applyTo(RestFn.java:142)
        at clojure.core$apply.invokeStatic(core.clj:667)
        at clojure.core$load_libs.invokeStatic(core.clj:5985)
        at clojure.core$load_libs.doInvoke(core.clj:5969)
        at clojure.lang.RestFn.applyTo(RestFn.java:137)
        at clojure.core$apply.invokeStatic(core.clj:667)
        at clojure.core$require.invokeStatic(core.clj:6007)
        at clojure.main$main_opt.invokeStatic(main.clj:491)
        at clojure.main$main_opt.invoke(main.clj:487)
        at clojure.main$main.invokeStatic(main.clj:598)
        at clojure.main$main.doInvoke(main.clj:561)
        at clojure.lang.RestFn.applyTo(RestFn.java:137)
        at clojure.lang.Var.applyTo(Var.java:705)
        at clojure.main.main(main.java:37)

andy.fingerhut04:06:45

I believe you can call the -main function of any namespace you want with the "-m" or "--main" command line option, but not any other function.

andy.fingerhut04:06:58

If that is true, you are of course free to write a -main function that takes additional command line options, such as the name of a method to invoke, or some custom-to-your-application options or names that you write code to determine which method to call.

👍 4
johnjelinek04:06:53

I'm mostly trying to debug my problem trying to find the right handler for my aws lambda to execute in my uberjar

andy.fingerhut04:06:00

You can write code in your -main that takes a string from the command line and uses Java reflection APIs to look up a method by that name, and then call it. Not sure if that would help.

seancorfield05:06:14

At work, we have a namespace with a -main that takes the first argument as a fully-qualified function name and calls it.

seancorfield05:06:48

So we do java -cp my/uber.jar clojure.main -m ws.task/my-func

seancorfield05:06:37

And that will require ws.task and then resolve ws.task/my-func and call it.

seancorfield05:06:33

(since we're on 1.10+, we just use (requiring-resolve 'ws.task/my-func)

alexmiller12:06:29

You can combine ^^ with -e

seancorfield18:06:39

True. For the simple CLI case that would work. Our jobs function does component creation / startup and logging too.

Dave Goodchild15:06:16

hey all happy to be here

Dave Goodchild15:06:39

I'm tech lead for the content platform at The Economist in London and have just started diving into Clojure

deep-symmetry16:06:18

Ooh, as an avid reader of every issue, I am delighted to hear this!

Dave Goodchild18:06:00

Probably not for work unfortunately

Dave Goodchild15:06:42

love it so far

💯 48
phrsantos21:06:14

Hey there. I'm in the middle of a clojure project I will turn in for a hiring process, and am enjoying working with it so far. Quite challenging though!

phrsantos21:06:52

Question: how long should namespace files be? And the separation between them must be by responsibilities? I'm trying really hard not to apply OO into it, so as of right now I have a logic file with over 150 lines. Is that acceptable?

didibus21:06:33

Looks fine to me.

didibus21:06:08

Namespaces can get pretty long, and it's not a problem if they do. Though it helps to seperate the namespace in sections using comment as headers

didibus21:06:01

You don't separate them by responsibility in the same way you would an OO class. In that, it's not single responsibility principle

didibus21:06:44

It's more a way to organize your code into sub-sections.

didibus21:06:14

Just for the purpose of readability mostly. And sometimes to avoid name clashes with other namespaces.

didibus21:06:00

I tend to have one per component. If you are familiar with UML Component Diagrams, namespaces map pretty well with those.

didibus21:06:21

Or to put it another way. A Clojure namespace is more like a Java Package

didibus21:06:40

Everything you'd have put in a Package can go under a single namespace in Clojure.

phrsantos21:06:59

Does that mean every aspect of it? Right now I am working on a REST api for a "board game", or similar to that.

didibus21:06:46

Ya, like if a Java package would have had 10 classes all doing different things. That can all be one namsepace

phrsantos21:06:58

My logic.clj has, at the moment, functions to check if a movement is valid, apply that movement on a matrix structure, calculate new positions after movement, and all that.

phrsantos21:06:10

Oh ok. So going back to your suggestion about separating them using comments as headers, I could separate them into "validators" and etc?

mss21:06:24

just want to echo that nothing about what you’re saying sounds outside of the ordinary in clojure land. have had namespaces with hundreds of lines of code, and namespaces with just a few lines of code. it’s more about how you want to organize a sliver of your code for outside consumption

mss21:06:50

in an ns of mine I’ll usually have a core or few main functions and then keep all the utils specific to those functions in that namespace as well

mss21:06:08

sounds like that’s what you’re doing 🤷

thanks2 4
didibus21:06:14

Ya just something like

;;;; Board logic

(defn bla ...)
...

;;;; Player movement

(defn foo ...

;;;; State Validation

...

didibus21:06:16

So your namespaces would be maybe: core, gameplay, config, persistence.

didibus21:06:37

core can be the main entry and have all REST APIs.

didibus21:06:58

gameplay can have everything related to the game, board, players, movement, ai, etc

mss21:06:59

yeah that sounds like a fine way of organizing it. for better or for worse – and you’ll see this the more you tinker w clojure – there’s no one way to do things in clojure

mss21:06:29

means there’s no guidance and frameworks and you have to figure out how you specifically want to glue stuff together, but the flexibility that provides is very freeing

didibus21:06:05

persistence could have all code to storing states in a db and what not if you need that. And config could for shared globals like credentials, etc.

didibus21:06:38

But depending how big all that is. The whole thing could be in a single namespace.

didibus21:06:00

Namespaces can easily be a thousand line long.

phrsantos21:06:17

Hmm interesting. I've been trying to separate things as much as I can due to the OO background.

didibus21:06:51

The big difference is, in OO, the "unit" is the class. But in Clojure, it's the function.

👍 4
phrsantos21:06:53

But logic is still with many responsibilities, which seems ok from what you guys are saying. Makes me more confident haha.

didibus21:06:24

So namespaces are just to group somewhat related functions together in a place to easily find it and share them together

didibus21:06:07

Your functions are what will need to be single responsibility, try to have them pure, well factored, composable, etc.

didibus21:06:54

Ya, I wouldn't worry about it. Namespaces with multiple responsibilities is totally normal.

didibus21:06:14

I normally start with one namespace, build almost everything in it, and if I start to feel it is getting hard to find things in it, and the file is too big, I break parts out into their own namespaces. It's purely organizational. Like choosing a folder structure to organize your photos in 😋

phrsantos21:06:54

Cool! That clarifies it to me. Thanks a bunch!

phrsantos21:06:34

You mentioned having gameplay as a namespace. Is logic an acceptable name or is it just placeholder and I should change it?

didibus21:06:17

Ya, logic is fine. I mean, whatever you feel is intuitive for someone looking for what they're looking for 😋

👍 4
didibus21:06:28

I would just make sure you don't have too many namespaces honestly. For a small program, you wouldn't want to have more then 5, if more then 10 I'd worry you're trying to use them as if they are OO classes

didibus21:06:25

The only convention is the main namespace is often called core.

didibus21:06:37

Like company.bagamon.core and then other namespaces would be like company.bagamon.logic company.bagamon.utils, etc. As needed

phrsantos21:06:03

Oh great tip. I have about 6 now, something like core, service, controller, logic for the flow, and some helpers like matrix (I created a simple namespace with a create, get and set for that) and constants (for globals like size of grid).

didibus22:06:26

Ya, that seems totally fine to me

👍 4
phrsantos23:06:47

Thank you a lot.

seancorfield23:06:51

@UK73TQZ9P From our code base at work

Clojure build/config 50 files 1019 total loc
Clojure source 279 files 66902 total loc,
    3118 fns, 641 of which are private,
    422 vars, 29 macros, 60 atoms,
    580 specs, 21 function specs.
Clojure tests 308 files 19407 total loc,
    4 specs, 1 function specs.
So that's an average of 240 roughly for production code (less for test code -- but we have at least a "stub" test namespace for every source namespace to ensure it loads/compiles without error).

seancorfield23:06:43

A few of our namespaces are as much as 2,000 lines but those are very much outliers.

seancorfield23:06:07

Just checked, our longest is 2,017 lines. We have just 12 that are 1,000+.

phrsantos02:06:19

Haha great!! Looks like I am fine with a 200 line one.

alexmiller22:06:33

I usually get itchy when namespaces get to around 500 lines