From 34eeee35f1782cdec2707605846290e59376d2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helmut=20H=C3=A4nsel?= Date: Mon, 4 Mar 2024 23:07:27 +0100 Subject: [PATCH] export `@using` and add docstring --- src/Genie.jl | 1 + src/Loader.jl | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/Genie.jl b/src/Genie.jl index d07f10cdf..d23a8cd21 100755 --- a/src/Genie.jl +++ b/src/Genie.jl @@ -47,6 +47,7 @@ include("Logger.jl") export up, down @reexport using .Router +@reexport using .Loader const assets_config = Genie.Assets.assets_config diff --git a/src/Loader.jl b/src/Loader.jl index e94bf9a66..fe8c2e42e 100644 --- a/src/Loader.jl +++ b/src/Loader.jl @@ -13,6 +13,8 @@ using DotEnv const post_load_hooks = Function[] +export @using + ### PRIVATE ### @@ -341,4 +343,115 @@ function default_context(context::Union{Module,Nothing} = nothing) end end + +function expr_to_path(expr::Union{Expr, Symbol, String})::String + path = String[] + while expr isa Expr && expr.head == :call && expr.args[1] ∈ (:\, :/) + push!(path, String(expr.args[3])) + expr = expr.args[2] + end + push!(path, String(expr)) + return join(reverse(path), '/') +end + +function _findpackage(package::String) + orig_package = package + path, package = splitdir(package) + validpath = if path != "" + loadpath = copy(LOAD_PATH) + empty!(LOAD_PATH) + push!(LOAD_PATH, path) + true + else + false + end + + p = Base.find_package(package) + if p === nothing + if isdir(orig_package) + pushfirst!(LOAD_PATH, orig_package) + p = Base.find_package(package) + popfirst!(LOAD_PATH) + end + end + + if validpath + empty!(LOAD_PATH) + append!(LOAD_PATH, loadpath) + end + + p === nothing && return + path, package = splitdir(p) + package = splitext(package)[1] + + basedir, parentdir = splitdir(path) + # if it is a package structure use the parent directory of the package as LOAD_PATH + if parentdir == "src" && basename(basedir) == package + path = dirname(basedir) + end + + path, package +end + +""" + @using(package_path) + +macro to simplify loading of modules that are not located in the LOAD_PATH + +`package_path` can be +- a path to a directory containing a module file of the same name + e.g 'models/MyApp' to load 'models/MyApp/MyApp.jl' +- a path to a module (without extension '.jl') + e.g. 'models/MyApp' to load models/MyApp.jl' +- a path to a package directory containing a 'src' directory and module file therein + e.g. 'models/MyApp' to load 'models/MyApp/src/MyApp.jl' + +### Examples + +```julia +@using models/MyApp + +@using StippleDemos/Vue3/Calendars +``` +or explicitly +```julia +@using StippleDemos/Vue3/Calendars/Calendars +``` +Note, directories containing special characters like colon (`':'`) or space (`' '`) +need to be escaped by double quotes. +```julia +@using "C:/Program Files/Julia/models/Calendars" + +# or +@using "C:/Program Files"/Julia/models/Calendars +``` + +Caveat: Due to precompilation it is not possible to supply variables to the macro. +Calls need to supply explicit paths. +""" +macro _using(package) + package = expr_to_path(package) + fp = _findpackage(package) + if fp === nothing + @warn "package $package not found" + return nothing + end + path, package_name = fp + package_symbol = Symbol(package_name) + + quote + pushfirst!(LOAD_PATH, $path) + @debug "using $($package_name) (from '$($path)')" + try + using $package_symbol + catch + finally + popfirst!(LOAD_PATH) + end + nothing + end +end + +const var"@using" = var"@_using" + end \ No newline at end of file