Skip to content

Commit d2dafff

Browse files
committed
Allow for Complex and Rationals and user types
1 parent c3f7c7d commit d2dafff

File tree

5 files changed

+93
-7
lines changed

5 files changed

+93
-7
lines changed

src/fmt.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function DefaultSpec(c::AbstractChar, syms...; kwargs...)
2929
end
3030
end
3131

32-
const DEFAULT_FORMATTERS = Dict{DataType, DefaultSpec}()
32+
const DEFAULT_FORMATTERS = Dict{Type{T} where T, DefaultSpec}()
3333

3434
# adds a new default formatter for this type
3535
default_spec!(::Type{T}, c::AbstractChar) where {T} =
@@ -79,6 +79,9 @@ default_spec(::Type{<:AbstractString}) = DEFAULT_FORMATTERS[AbstractString]
7979
default_spec(::Type{<:AbstractChar}) = DEFAULT_FORMATTERS[AbstractChar]
8080
default_spec(::Type{<:AbstractIrrational}) = DEFAULT_FORMATTERS[AbstractIrrational]
8181
default_spec(::Type{<:Number}) = DEFAULT_FORMATTERS[Number]
82+
default_spec(::Complex{T} where T<:Integer) = DEFAULT_FORMATTERS[Complex{T} where T<:Integer]
83+
default_spec(::Complex{T} where T<:AbstractFloat) = DEFAULT_FORMATTERS[Complex{T} where T<:AbstractFloat]
84+
default_spec(::Complex{T} where T<:Rational) = DEFAULT_FORMATTERS[Complex{T} where T<:Rational]
8285

8386
default_spec(::Type{T}) where {T} =
8487
get(DEFAULT_FORMATTERS, T) do
@@ -189,7 +192,7 @@ function fmt end
189192
# TODO: do more caching to optimize repeated calls
190193

191194
# creates a new FormatSpec by overriding the defaults and passes it to pyfmt
192-
# note: adding kwargs is only appropriate for one-off formatting.
195+
# note: adding kwargs is only appropriate for one-off formatting.
193196
# normally it will be much faster to change the fmt_default formatting as needed
194197
function fmt(x; kwargs...)
195198
fspec = fmt_default(x)
@@ -220,9 +223,12 @@ end
220223
for (t, c) in [(Integer,'d'),
221224
(AbstractFloat,'f'),
222225
(AbstractChar,'c'),
223-
(AbstractString,'s')]
226+
(AbstractString,'s'),
227+
(Complex{T} where T<:Integer, 'd' ),
228+
(Complex{T} where T<:AbstractFloat, 'f' )]
224229
default_spec!(t, c)
225230
end
226231

227232
default_spec!(Number, 's', :right)
228233
default_spec!(AbstractIrrational, 's', :right)
234+
default_spec!(Complex{T} where T<:Rational, 's', :right)

src/fmtcore.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# core formatting functions
2+
export fmt_Number
23

34
### auxiliary functions
45

@@ -262,3 +263,40 @@ function _pfmt_specialf(out::IO, fs::FormatSpec, x::AbstractFloat)
262263
end
263264
end
264265

266+
function _pfmt_Number_f(out::IO, fs::FormatSpec, x::Number, _pf::Function)
267+
fsi = FormatSpec(fs, width = -1)
268+
f = x::AbstractFloat->begin
269+
io = IOBuffer()
270+
_pf(io, fsi, x)
271+
String(take!(io))
272+
end
273+
s = fmt_Number(x, f)
274+
_pfmt_s(out, fs, s)
275+
end
276+
277+
function _pfmt_Number_i(out::IO, fs::FormatSpec, x::Number, op::Op, _pf::Function) where {Op}
278+
fsi = FormatSpec(fs, width = -1)
279+
f = x::Integer->begin
280+
io = IOBuffer()
281+
_pf(io, fsi, x, op)
282+
String(take!(io))
283+
end
284+
s = fmt_Number(x, f)
285+
_pfmt_s(out, fs, s)
286+
end
287+
288+
function _pfmt_i(out::IO, fs::FormatSpec, x::Number, op::Op) where {Op}
289+
_pfmt_Number_i(out, fs, x, op, _pfmt_i)
290+
end
291+
292+
function _pfmt_f(out::IO, fs::FormatSpec, x::Number)
293+
_pfmt_Number_f(out, fs, x, _pfmt_f)
294+
end
295+
296+
function _pfmt_e(out::IO, fs::FormatSpec, x::Number)
297+
_pfmt_Number_f(out, fs, x, _pfmt_e)
298+
end
299+
300+
function fmt_Number(x::Complex, f::Function)
301+
s = f(real(x)) * (imag(x) >= 0 ? " + " : " - ") * f(abs(imag(x))) * "im"
302+
end

src/fmtspec.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,19 +164,30 @@ _srepr(x) = repr(x)
164164
_srepr(x::AbstractString) = x
165165
_srepr(x::AbstractChar) = string(x)
166166
_srepr(x::Enum) = string(x)
167+
@static if VERSION < v"1.2.0-DEV"
168+
_srepr(x::Irrational{sym}) where {sym} = string(sym)
169+
end
167170

168171
function printfmt(io::IO, fs::FormatSpec, x)
169172
cls = fs.cls
170173
ty = fs.typ
171174
if cls == 'i'
172-
ix = Integer(x)
175+
ix = x
176+
try
177+
ix = Integer(x)
178+
catch
179+
end
173180
ty == 'd' || ty == 'n' ? _pfmt_i(io, fs, ix, _Dec()) :
174181
ty == 'x' ? _pfmt_i(io, fs, ix, _Hex()) :
175182
ty == 'X' ? _pfmt_i(io, fs, ix, _HEX()) :
176183
ty == 'o' ? _pfmt_i(io, fs, ix, _Oct()) :
177184
_pfmt_i(io, fs, ix, _Bin())
178185
elseif cls == 'f'
179-
fx = float(x)
186+
fx = x
187+
try
188+
fx = float(x)
189+
catch
190+
end
180191
if isfinite(fx)
181192
ty == 'f' || ty == 'F' ? _pfmt_f(io, fs, fx) :
182193
ty == 'e' || ty == 'E' ? _pfmt_e(io, fs, fx) :

test/fmt.jl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,19 @@ i = 1234567
2020
@test fmt(i) == "1234567"
2121
@test fmt(i,:commas) == "1,234,567"
2222

23-
@test_throws ErrorException fmt_default(Real)
24-
@test_throws ErrorException fmt_default(Complex)
23+
@test fmt(2 - 3im, 10) == " 2 - 3im"
24+
@test fmt(pi - 3im, 15, 2) == " 3.14 - 3.00im"
25+
26+
@test fmt(3//4, 10) == " 3//4"
27+
@test fmt(1//2 + 6//2 * im, 15) == " 1//2 + 3//1*im"
28+
29+
fmt_default!(Rational, 'f', prec = 2)
30+
fmt_default!(Format.ComplexRational, 'f', prec = 2)
31+
32+
@test fmt(3//4, 10, 2) == " 0.75"
33+
@test fmt(3//4, 10, 1) == " 0.8"
34+
@test fmt(1//2 + 6//2 * im, 23) == " 0.500000 + 3.000000im"
35+
@test fmt(1//2 + 6//2 * im, 15, 2) == " 0.50 + 3.00im"
2536

2637
fmt_default!(Int, :commas, width = 12)
2738
@test fmt(i) == " 1,234,567"
@@ -41,3 +52,9 @@ fmt_default!(UInt16, 'd', :commas)
4152
fmt_default!(UInt32, UInt16, width=20)
4253
@test fmt(0xfffff) == " 1,048,575"
4354

55+
v = pi
56+
@test fmt(v) == "π"
57+
@test fmt(v; width=10) == " π"
58+
59+
v = MathConstants.eulergamma
60+
@test fmt(v, 10, 2) == " γ"

test/fmtspec.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,17 @@ end
234234
@test pyfmt("*>5f", Inf) == "**Inf"
235235
@test pyfmt("⋆>5f", Inf) == "⋆⋆Inf"
236236
end
237+
238+
@testset "Format Symbols (S) for Irrationals" begin
239+
@test pyfmt(">10s", pi) == " π"
240+
@test pyfmt("10s", pi) == "π "
241+
@test pyfmt("3", MathConstants.eulergamma) == " γ"
242+
@test pyfmt("10.2f", MathConstants.eulergamma) == " 0.58"
243+
@test pyfmt("<3s", MathConstants.e) == ""
244+
end
245+
246+
@testset "Format Symbols (S) for Irrationals" begin
247+
pyfmt("10s", 3//4) == "3//4 "
248+
pyfmt("10", 3//4) == " 3//4"
249+
pyfmt("10.1f", 3//4) == " 0.8"
250+
end

0 commit comments

Comments
 (0)