From 909c7f3505ef4fe7c7aec83ac58af18eb5536f1b Mon Sep 17 00:00:00 2001 From: Ronan Arraes Jardim Chagas Date: Mon, 22 Feb 2021 04:42:07 -0300 Subject: [PATCH] Add support to multiple property pairs in sprint (#39381) * Add support to multiple property pairs in sprint Sometimes it is required to pass multiple properties to `IOContext` in `sprint`. For example, if we want to print with `:compact` and `:limit` set to true. Currently, the only possible way to do this is creating an `IOContext` using a dummy `IOBuffer` with those parameters. Hence, this commit allows to pass a vector of pairs `:key=>value` to `context` keyword of `sprint` so that we can easily set multiple properties. This is not a breaking change, and no performance regression was identified when using the previous function signatures. * Add compat annotation to sprint * Update base/strings/io.jl Co-authored-by: Rafael Fourquet * Update sprint docstring * Update NEWS.md * Move NEWS.md entry to the correct place Co-authored-by: Rafael Fourquet --- NEWS.md | 1 + base/strings/io.jl | 23 +++++++++++++++-------- test/strings/io.jl | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index e626b7a276197..4f9c315659ae5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -38,6 +38,7 @@ New library functions New library features -------------------- +* The optional keyword argument `context` of `sprint` can now be set to a tuple of `:key => value` pairs to specify multiple attributes. ([#39381]) Standard library changes ------------------------ diff --git a/base/strings/io.jl b/base/strings/io.jl index 30ffe03354604..6003a6d503b90 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -79,14 +79,19 @@ println(io::IO, xs...) = print(io, xs..., "\n") Call the given function with an I/O stream and the supplied extra arguments. Everything written to this I/O stream is returned as a string. -`context` can be either an [`IOContext`](@ref) whose properties will be used, -or a `Pair` specifying a property and its value. `sizehint` suggests the capacity -of the buffer (in bytes). +`context` can be an [`IOContext`](@ref) whose properties will be used, a `Pair` +specifying a property and its value, or a tuple of `Pair` specifying multiple +properties and their values. `sizehint` suggests the capacity of the buffer (in +bytes). -The optional keyword argument `context` can be set to `:key=>value` pair -or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O -stream passed to `f`. The optional `sizehint` is a suggested size (in bytes) -to allocate for the buffer used to write the string. +The optional keyword argument `context` can be set to a `:key=>value` pair, a +tuple of `:key=>value` pairs, or an `IO` or [`IOContext`](@ref) object whose +attributes are used for the I/O stream passed to `f`. The optional `sizehint` +is a suggested size (in bytes) to allocate for the buffer used to write the +string. + +!!! compat "Julia 1.7" + Passing a tuple to keyword `context` requires Julia 1.7 or later. # Examples ```jldoctest @@ -99,7 +104,9 @@ julia> sprint(showerror, BoundsError([1], 100)) """ function sprint(f::Function, args...; context=nothing, sizehint::Integer=0) s = IOBuffer(sizehint=sizehint) - if context !== nothing + if context isa Tuple + f(IOContext(s, context...), args...) + elseif context !== nothing f(IOContext(s, context), args...) else f(s, args...) diff --git a/test/strings/io.jl b/test/strings/io.jl index 0ebb16bd42e60..91ad83b24e328 100644 --- a/test/strings/io.jl +++ b/test/strings/io.jl @@ -187,6 +187,38 @@ join(myio, "", "", 1) @test_throws ArgumentError unescape_string(IOBuffer(), string('\\',"N")) @test_throws ArgumentError unescape_string(IOBuffer(), string('\\',"m")) end + +@testset "sprint with context" begin + function f(io::IO) + println(io, "compact => ", get(io, :compact, false)) + println(io, "limit => ", get(io, :limit, false)) + end + + str = sprint(f) + @test str == """ + compact => false + limit => false + """ + + str = sprint(f, context = :compact => true) + @test str == """ + compact => true + limit => false + """ + + str = sprint(f, context = (:compact => true, :limit => true)) + @test str == """ + compact => true + limit => true + """ + + str = sprint(f, context = IOContext(stdout, :compact => true, :limit => true)) + @test str == """ + compact => true + limit => true + """ +end + @testset "#11659" begin # The indentation code was not correctly counting tab stops @test Base.indentation(" \t") == (8, true)