Just joined to say what we've added an experimental automation workflow in our product, built on SCI. The ability to run the code against dummy data in the browser, and also against real data in the server, makes a really nice dev experience. Thank you @borkdude
Well, also joined to validate an assumption that I have - if I provide an allow list to the evaluation options, that means essentially a very very restricted environment. The code we'd be running would be untrusted so we want to really limit the available constructs to some basic conditionals and then env-provided functions.
I implemented a load-file for the SCI context. foo.ys loads bar.ys
But when I move both files into test/ directory, then test/foo.ys can't find bar.ys unless I specify test/bar.ys
What's the best way to make sure the loaded file path is relative to the caller?
Perhaps you can use sci/file (available as *file* inside of SCI programs)
Every var has also :file as metadata
(defn ys-load [file]
(let [file (io/file file)
ys-code (slurp file)
clj-code (ys/ys-compile ys-code)]
(sci/with-bindings
{sci/ns @sci/ns
sci/file (.getAbsolutePath file)}
(sci/eval-string* (sci-ctx) clj-code))))
I got that from the SCI readme
you could maybe make load-file a macro, this way it gets expanded while sci/file is still bound to the file you're processing
and then expand to something like load-file* as a function which then gets the absolute path
oh, you think the path is wrong?
I'll test that
what do you mean, the path is wrong?
The sci/file var is only bound during analysis
and macros are processed during analysis
function calls are too late
hope you get the picture
@ingy Here's a more full example (which I typed out in a REPL)
user=> (defmacro my-load-file [path] (let [current-file @sci/file] `(clojure.core/load-file* ~current-file ~path)))
#'user/my-load-file
user=> (defn load-file* [current-file path] [:do-your-thing current-file path])
#'user/load-file*
user=> (sci/binding [sci/file "user.clj"] (sci/eval-string "(defn foo [] (load-file \"dude.clj\")) (foo)" {:namespaces {'clojure.core {'load-file (sci/copy-var my-load-file nil) 'load-file* (sci/copy-var load-file* nil)}}}))
[:do-your-thing "user.clj" "dude.clj"]I did get the picture wrt binding time. And the load file path was indeed wrong for me.
What I don't get is what sci/file or *file* does.
To venture a guess, it affects how slurp works? or maybe how io/file works?
sci/file works exactly the same as *file* on the JVM
ok, but I don't know what *file* does
this one has more explanation: https://stackoverflow.com/questions/12692698/file-variable-not-working/12693068
I get *file* holds the current file path.
What I'm trying to suss out is if the file functions resolve relative paths relative to *file* or relative to the current directory.
never relative path
but I can figure it out...
?
but if you want to implement it like that, you can use the idea I posted above
which is not getting through I'm afraid
functions can't use the value of *file* since that var is only bound during compilation time
I'm saying if *file* is set to /tmp/foo/aaa.clj where does slurp think the "bbb.clj" would be?
so you have to use a macro if you want to capture the file during compilation time
slurp is a function and it never uses *file*
in general JVM Clojure never uses the concept of "load something relative to this file"
everything is based on classpath or current working directory, mostly classpath idea is central though
ok so I need to do that math myself, after getting the starting point right
but this doesn't prevent you from making your own load-file which does use the relative file idea, but then it has to be a macro
like I explained above, so maybe read it again :)
I fully understand the macro binding thing
ok
*file* is just some compile time thing. it is used to set the :file value on var metadata, which is probably the main thing
I gotta run to the airport, but I think I have what I need now. Thanks!
👍
have a good flight!