This expression eval(Meta.parse("begin $(code)\nend"))
would eval Julia code with include
resolved relative to the file eval...
is defined in.
How to change it so that it would use another directory? Something like
eval(Meta.parse("begin $(code)\nend"), resolve_include_relative_to=somepath)
Or, if that's not possible - relative to current directory (like REPL)?
UPDATE
Possible solution - replacing relative paths with absolute
function fix_include(code::String, relative_path::String)::String
code = replace(code, r"include\(\"\./(.*?)\"\)" => s"include(\"__relative_path__/\1\")")
code = replace(code, r"__relative_path__" => relative_path)
code
end
eval(Meta.parse("begin $(fix_include(code, relative_path))\nend")
Use case:
I'm evaluating snippets of string code, sometimes they contain include
statement with relative paths and they resolved against wrong path. I want to explicitly specify tell it what path should be used for resolution. Or at the very least always use the current directory '.', not the directory where the file with the eval(xxx)
line defined ./lib/runner.jl
.
This function should do the trick (include
is relative to the path in task-local storage, as kinda indicated by the docstring):
function eval_at(code; path = "none", mod = Main)
tls = task_local_storage()
hassource = haskey(tls, :SOURCE_PATH)
hassource && (path′ = tls[:SOURCE_PATH])
# setting this is enough for `include` to be correct
tls[:SOURCE_PATH] = path
try
# let's use the three-arg `include_string` here to make sure `@__FILE__`
# etc resolve correctly
return include_string(mod, code, path)
finally
hassource ?
(tls[:SOURCE_PATH] = path′) :
delete!(tls, :SOURCE_PATH)
end
end
Example usage:
julia> pwd()
"/home/pfitzseb/Documents"
julia> isfile("test.jl")
false
julia> include("test.jl")
ERROR: could not open file /home/pfitzseb/Documents/test.jl
julia> eval_at("""include("test.jl")""", path = "/home/pfitzseb/foo.jl")
Main.LogT
julia> eval_at("""@__FILE__""", path = "/home/pfitzseb/foo.jl")
"/home/pfitzseb/foo.jl"
It is not clear what exactly you want to do but for "do something in a folder" situations usually cd() do ... end
syntax works great.
code = quote
cd("c:/temp") do
println("do something in $(pwd())")
#do something more
end
end
And now use it
julia> eval(code)
do something in c:\temp
Depending in your scenario you might consider using macros to manipulate code blocks that do something in a directory. Below is a simple example not offering more functionality than cd ... do ... end
statement but of course it can be extended:
macro doinfolder(folder, what)
isa(what, Expr) || error("what needs to be some expression")
quote
cd($folder) do
$what
#other useful code injections can occur here...
end
end
end
And now use it
julia> @doinfolder "C:\\temp" pwd()
"C:\\temp"
Will also work with more complex code structures
julia> @doinfolder "C:\\temp" begin
pwd()
end
"C:\\temp"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With