dundalek/closh

Confusing interpretation of shell vs ClojureScript

Opened this issue · 3 comments

Sometimes, the interpretation of which should we run becomes confused. For instance:

; Will try to find a file named "temp" in current dir:
>> (let [temp "/tmp"] (sh-str ls temp))

; Will list files in /tmp directory:
>> (let [temp "/tmp"] (sh-str ls (identity temp)))

>> (def home "/home/somewhere")
>> home
No command 'home' found, did you mean:
 Command 'tome' from package 'tome' (multiverse)
 Command 'hime' from package 'hime' (universe)

I can see only two possibilities here: first, to force sh-str and friends to receive Clojure structures- we would, of course, be forced to write (sh-str ls "/my/dir") all the time, but it would probably be less confusing - or we could implement a #clj reader macro (no idea on how to do it with in ClojureScript) so that it'll always interpret ClojureScript forms (and the code above would be re-written like this):

>> (let [temp "/tmp"] (sh-str ls #clj temp))

>> (def home "/home/somewhere")
>> #clj home

What do you think?

Good question, sh-str is actually a macro so the behavior you posted is expected. You don't need to quote ls but then you get temp as a symbol. To fit better into examples you provided we could create a helper function. To list the contents of /tmp you could run (you will get value of temp but you need to quote ls):

(let [temp "/tmp"] (shx-str 'ls temp))

You can put this to your ~/.closhrc to get the behavior above:

(defn shx-str [cmd & args]
  (-> (closh.core/shx (str cmd) args)
    (closh.core/process-output)
    (clojure.string/trim)))

I am not sure about the naming though, so I am hesitant to put it into core.

As for the second part that behavior is intentional. You don't want clojure variables implicitly override your commands. One example of all, I use Atom editor which runs with the atom command. However, atom is also a clojure function. So if we expanded the value, I would get garbage instead of running my editor:

>> atom
#object[Function]

So if you would like to get the variable value you can use parentheses form to drop into clojure mode:

>> (def home "/home/somewhere")
#'cljs.user/home
>> (str home)
"/home/somewhere"
>> (identity home)
"/home/somewhere"

If you want to explicitly override specific commands to get the behavior you would expect you can use aliases:

>> (defalias home "/home/somewhere")
>> home
/home/somewhere: command not found

Does it make sense?

Yes, it does seems.

Normally, in Clojure-land, macros call functions with * appended, so the canonical way would be to call it sh-str*, but I too am not too confident about the code...

j-cr commented

For vars you can use:

$ (def ls 42)
#'user/ls 
$ #'ls
#'user/ls
$ @#'ls
42