Skip to content

Commit

Permalink
Add support to multiple property pairs in sprint (#39381)
Browse files Browse the repository at this point in the history
* 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 <fourquet.rafael@gmail.com>

* Update sprint docstring

* Update NEWS.md

* Move NEWS.md entry to the correct place

Co-authored-by: Rafael Fourquet <fourquet.rafael@gmail.com>
  • Loading branch information
ronisbr and rfourquet committed Feb 22, 2021
1 parent 10bea87 commit 909c7f3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 8 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------------------
Expand Down
23 changes: 15 additions & 8 deletions base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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...)
Expand Down
32 changes: 32 additions & 0 deletions test/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 909c7f3

Please sign in to comment.