diff --git a/README.md b/README.md index 221184579878e..1f6572b7f9d66 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ Currently, the `@compat` macro supports the following syntaxes: * `@compat Union{args...}` - `Union(args...)` on 0.3. [#11432](https://github.com/JuliaLang/julia/pull/11432) +* `@compat withenv(f, "a" => a, "b" => b...)` on 0.3. + ## Type Aliases * `typealias AbstractString String` - `String` has been renamed to `AbstractString` [#8872](https://github.com/JuliaLang/julia/pull/8872) @@ -99,6 +101,8 @@ Currently, the `@compat` macro supports the following syntaxes: * `isapprox(A, B)` for arrays ([JuliaLang/julia#12472](https://github.com/JuliaLang/julia/pull/12472)), and synonyms `≈` ([U+2248](http://www.fileformat.info/info/unicode/char/2248/index.htm), LaTeX `\approx`) and `≉` ([U+2249](http://www.fileformat.info/info/unicode/char/2249/index.htm), LaTeX `\napprox`) for `isapprox` and `!isapprox`, respectively. +* `withenv` can be used in julia 0.3 (see [the 0.4 docs](http://docs.julialang.org/en/release-0.4/stdlib/base/#Base.withenv)). Note that you must prepend calls to `withenv` with `@compat` if you'd like to use it with the `=>` syntax. + ## Renamed functions * `itrunc`, `iround`, `iceil`, `ifloor` are now accessed via `trunc(T, x)`, etc. ([#9133](https://github.com/JuliaLang/julia/pull/9133)). Truncated conversions between integer types are now `n % T` ([#8646](https://github.com/JuliaLang/julia/issues/8646)). diff --git a/src/Compat.jl b/src/Compat.jl index 32fdc0ea6d6d7..b9a8bbd77bb8e 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -279,6 +279,17 @@ function rewrite_split(ex, f) end end +# rewrites all subexpressions of the form `a => b` to `(a, b)` +function rewrite_pairs_to_tuples!(expr::Expr) + if expr.head == :(=>) + expr.head = :tuple + end + for subexpr in expr.args + isa(subexpr, Expr) && rewrite_pairs_to_tuples!(subexpr) + end + return expr +end + if VERSION < v"0.4.0-dev+707" macro inline(ex) esc(ex) @@ -395,6 +406,8 @@ function _compat(ex::Expr) else ex = Expr(:call, :Array, f.args[2], ex.args[2:end]...) end + elseif VERSION < v"0.4.0-dev+4389" && f == :withenv + rewrite_pairs_to_tuples!(ex) end elseif ex.head == :curly f = ex.args[1] @@ -690,6 +703,26 @@ if VERSION < v"0.4.0-dev+3837" const OutOfMemoryError = MemoryError end + +if VERSION < v"0.4.0-dev+4389" + export withenv + # temporarily set and then restore an environment value + function withenv(f::Function, keyvals...) + old = Dict{typeof(first(first(keyvals))),Any}() + for (key,val) in keyvals + old[key] = get(ENV, key, nothing) + val !== nothing ? (ENV[key]=val) : Base._unsetenv(key) + end + try f() + finally + for (key,val) in old + val !== nothing ? (ENV[key]=val) : Base._unsetenv(key) + end + end + end + withenv(f::Function) = f() # handle empty keyvals case; see #10853 +end + import Base: remotecall, remotecall_fetch, remotecall_wait, remote_do if VERSION < v"0.5.0-dev+431" for f in (:remotecall, :remotecall_fetch, :remotecall_wait, :remote_do) diff --git a/test/runtests.jl b/test/runtests.jl index 5ae97c42568d5..2c584385893d2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -551,3 +551,9 @@ Base.remote_do(() -> true, 1) # Doesn't return anything so cannot be `@test`ed b # JuliaLang/julia#14338 @test supertype(Int) == Signed + +# withenv +@test "1234" == @compat withenv(() -> ENV["_TESTVAR"], "_TESTVAR" => 1234) +@test "1234" == @compat withenv("_TESTVAR" => 1234) do + return ENV["_TESTVAR"] +end