diff --git a/Project.toml b/Project.toml index b0a94fd..81d1c5b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LookingGlass" uuid = "1fcbbee2-b350-4a01-aad8-439064dba09e" authors = ["Nathan Daly"] -version = "0.3.2" +version = "0.3.3" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" diff --git a/src/LookingGlass.jl b/src/LookingGlass.jl index 681e9d5..807ff79 100644 --- a/src/LookingGlass.jl +++ b/src/LookingGlass.jl @@ -145,27 +145,27 @@ By default, it skips Julia's `Base` and `Core` modules, but you can enable those NOTE: currently, `module_submodules(Main, recursive=true, base=true)` will trigger a StackOverflowError, since recursively listing submodules of `Core` or `Base` infinite loops. """ -module_submodules(m::Module; recursive=true, base=false) = +module_submodules(m::Module; recursive=true, base=false, kwargs...) = if recursive - _module_recursive_submodules(m, base=base, seen=Set{Module}()) + _module_recursive_submodules(m; base=base, seen=Set{Module}(), kwargs...) else - _module_direct_submodules(m, base=base) + _module_direct_submodules(m; base=base, kwargs...) end -function _module_recursive_submodules(m; base, seen) - submodules = _module_direct_submodules(m, base=base; seen=seen) +function _module_recursive_submodules(m; base, seen, kwargs...) + submodules = _module_direct_submodules(m; base=base, seen=seen, kwargs...) for m in submodules push!(seen, m) end modules = collect(Iterators.flatten( - [x, _module_recursive_submodules(x, base=base, seen=seen)...] + [x, _module_recursive_submodules(x; base=base, seen=seen, kwargs...)...] for x in submodules )) return modules end -_module_direct_submodules(m; base, seen) = +_module_direct_submodules(m; base, seen, kwargs...) = Module[submodule - for x in filter(x->name_is_submodule(m,x), names(m, all=true)) + for x in filter(x->name_is_submodule(m,x), names(m; all=true, kwargs...)) for submodule in (Core.eval(m, x),) # assign to temporary variable (comprehensions are weird) if submodule ∉ seen] @@ -219,8 +219,8 @@ argument to one of `constness=:const` or `constness=:nonconst`. To return only mutable globals or only immutable globals, set the `mutability=` keyword argument to one of `mutability=:mutable` or `mutability=:immutable`. """ -module_globals_names(m::Module; constness=:all, mutability=:all) = - [n for n in names(m, all=true) +module_globals_names(m::Module; constness=:all, mutability=:all, kwargs...) = + [n for n in names(m, all=true; kwargs...) if module_name_isglobal(m, n; constness=constness, mutability=mutability)] function module_name_isglobal(m::Module, n::Symbol; constness, mutability) @assert constness ∈ (:all, :const, :nonconst) @@ -248,9 +248,9 @@ module_globals(m::Module) = Dict(n => Core.eval(m, n) for n in module_globals_na Return a Dict mapping the fully qualified name to the value of all global variables in Module `m` and all its recursive submodules. """ -function module_recursive_globals(m::Module) +function module_recursive_globals(m::Module; kwargs...) return Dict((mod,n) => Core.eval(mod, n) - for (mod,names) in module_recursive_globals_names(m) + for (mod,names) in module_recursive_globals_names(m; kwargs...) for n in names ) end @@ -282,16 +282,18 @@ end Return a list of the names of all global variables for each submodule in Module `m`. Defaults to all globals, can toggle only const-globals or nonconst-globals via keyword args. -See [`module_recursive_globals`](@ref). +See Also: +- [`module_globals`](@ref) +- [`module_recursive_globals`](@ref) """ -module_recursive_globals_names(m::Module; constness=:all, mutability=:all) = +module_recursive_globals_names(m::Module; constness=:all, mutability=:all, kwargs...) = merge!( - Dict(m => module_globals_names(m, constness=constness, mutability=mutability)), + Dict(m => module_globals_names(m; constness=constness, mutability=mutability, kwargs...)), Dict( sm => names - for sm in module_submodules(m, recursive=true) - for names in (module_globals_names(sm; constness=constness, mutability=mutability),) - if !isempty(names) + for sm in module_submodules(m; recursive=true, kwargs...) + for names in (module_globals_names(sm; constness=constness, mutability=mutability, kwargs...),) + #if !isempty(names) )) """ diff --git a/test/LookingGlass.jl b/test/LookingGlass.jl index bf81902..06d2804 100644 --- a/test/LookingGlass.jl +++ b/test/LookingGlass.jl @@ -27,14 +27,22 @@ end @test length(first(LookingGlass.func_backedges(MF.foo))[2]) == 1 end +module Outer + const g_outer = 1 +end module MV gv = 2 const cv = 2 vec = [] + module A + const g_a = 1 + end module Inner i_x = 3 const i_c = 2 const i_vec = [2] + + import ...Outer end end @@ -42,13 +50,24 @@ end Dict( MV => sort([:gv, :cv, :vec]), MV.Inner => sort([:i_x, :i_c, :i_vec]), + MV.A => sort([:g_a]), ) @test LookingGlass.module_recursive_globals_names(MV, - constness=:const, mutability=:mutable) == + constness = :const, mutability = :mutable) == Dict( MV => sort([]), MV.Inner => sort([:i_vec]), + MV.A => sort([]), + ) + +@test LookingGlass.module_recursive_globals_names(MV, + constness = :const, imported = true) == + Dict( + MV => sort([:cv]), + MV.Inner => sort([:i_c, :i_vec]), + MV.A => sort([:g_a]), + Outer => sort([:g_outer]), # imported via MV.Inner ) @test LookingGlass.module_recursive_globals(MV) == @@ -59,4 +78,26 @@ end (MV.Inner, :i_x) => MV.Inner.i_x, (MV.Inner, :i_c) => MV.Inner.i_c, (MV.Inner, :i_vec) => MV.Inner.i_vec, + (MV.A, :g_a) => MV.A.g_a, + ) + +@test LookingGlass.module_recursive_globals(MV, imported=true) == + Dict( + (MV, :gv) => MV.gv, + (MV, :cv) => MV.cv, + (MV, :vec) => MV.vec, + (MV.Inner, :i_x) => MV.Inner.i_x, + (MV.Inner, :i_c) => MV.Inner.i_c, + (MV.Inner, :i_vec) => MV.Inner.i_vec, + (MV.A, :g_a) => MV.A.g_a, + (Outer, :g_outer) => MV.Inner.Outer.g_outer, # imported via MV.Inner + ) + +@test LookingGlass.module_recursive_globals(MV, imported=true, constness=:const) == + Dict( + (MV, :cv) => MV.cv, + (MV.Inner, :i_c) => MV.Inner.i_c, + (MV.Inner, :i_vec) => MV.Inner.i_vec, + (MV.A, :g_a) => MV.A.g_a, + (Outer, :g_outer) => MV.Inner.Outer.g_outer, # imported via MV.Inner )