diff --git a/README.md b/README.md index 2759648..f6f24b0 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ However, for *interactive* use, especially for new users, the necessity of the ` ## Usage -The `SoftGlobalScope` module exports two functions `softscope` and `softscope_include_string`: +The `SoftGlobalScope` module exports two functions `softscope` and `softscope_include_string`, and a macro `@softscope`: You can transform the expression using `softscope(module, expression)` to automatically insert the necessary `global` keyword. For example, assuming that the module `Main` has a global variable `s` (as above), you can do: ```jl @@ -77,8 +77,20 @@ julia> softscope(Main, :(for i = 1:10 global s += i end) ``` -You can then execute the statement with `eval`. Alternatively, you can execute an entire sequence of statements -using "soft" global scoping rules via `softscope_include_string(module, string, filename="string")`: +You can then execute the statement with `eval`. Alternatively, you can decorate the expression with the `@softscope` macro: +```jl +julia> s = 0; + +julia> @softscope for i = 1:10 + s += i + end + +julia> s +55 +``` +This macro should only be used in the global scope (e.g., via the REPL); using this macro within a function is likely to lead to unintended consequences. + +You can execute an entire sequence of statements using "soft" global scoping rules via `softscope_include_string(module, string, filename="string")`: ```jl julia> softscope_include_string(Main, """ s = 0 diff --git a/src/SoftGlobalScope.jl b/src/SoftGlobalScope.jl index 9749223..ed43f6f 100644 --- a/src/SoftGlobalScope.jl +++ b/src/SoftGlobalScope.jl @@ -26,8 +26,23 @@ julia> softscope(Main, :(for i = 1:10 global s += i end) ``` -You can then execute the statement with `eval`. Alternatively, you can execute an entire sequence of statements -using "soft" global scoping rules via `softscope_include_string`: +You can then execute the statement with `eval`. Alternatively, you can decorate +the expression with the `@softscope` macro: +```jl +julia> s = 0; + +julia> @softscope for i = 1:10 + s += i + end + +julia> s +55 +``` +This macro should only be used in the global scope (e.g., via the REPL); using +this macro within a function is likely to lead to unintended consequences. + +You can execute an entire sequence of statements using "soft" global scoping +rules via `softscope_include_string`: ```jl julia> softscope_include_string(Main, \"\"\" s = 0 @@ -44,7 +59,7 @@ On Julia 0.6, `softscope` is the identity and `softscope_include_string` is equi `include_string`, since the `global` keyword is not needed there. """ module SoftGlobalScope -export softscope, softscope_include_string +export softscope, softscope_include_string, @softscope if VERSION < v"0.7.0-DEV.2308" # before julia#19324 we don't need to change the ast softscope(m::Module, ast) = ast @@ -128,6 +143,33 @@ scoping rules for the global variables defined in `m`, returning the new express """ softscope +if VERSION < v"0.7.0-DEV.481" # the version that __module__ was introduced + macro softscope(ast) + esc(softscope(current_module(), ast)) + end +else + macro softscope(ast) + esc(softscope(__module__, ast)) + end +end + +""" + @softscope(expr) + +Apply "soft" scoping rules to the argument of the macro. For example +```jl +julia> s = 0; + +julia> @softscope for i = 1:10 + s += i + end + +julia> s +55 +``` +""" +:(@softscope) + """ softscope_include_string(m::Module, code::AbstractString, filename::AbstractString="string") diff --git a/test/runtests.jl b/test/runtests.jl index ba089a8..6aa659c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -55,3 +55,9 @@ end @test softscope_include_string(TestMod, "for i=1:10; a += 1; end; a") == 10 @test softscope_include_string(TestMod, "aa=0; for i=1:10; aa += i; end; aa") == 55 end + +@testset "softscope_macro" begin + Core.eval(TestMod, :(global a = 0 ; using SoftGlobalScope)) + @test Core.eval(TestMod, :(@softscope (for i=1:10; a += 1; end; a))) == 10 + @test Core.eval(TestMod, :(@softscope (amacro=0; for i=1:10; amacro += i; end; amacro))) == 55 +end