From 756181676e9e3a781ec6ddb19f45fc96b2cb083f Mon Sep 17 00:00:00 2001 From: David Gustavsson Date: Sat, 20 Feb 2021 13:54:00 +0100 Subject: [PATCH] Version 3.0.0 Major rework of the package, using the new UnitfulLatexify package, and with a more robust syntax for the @datax macro. Older scripts likely to be broken. --- Project.toml | 10 +-- README.md | 18 ++--- src/LaTeXDatax.jl | 197 +++++++++++++++++++--------------------------- test/runtests.jl | 40 +++++----- 4 files changed, 111 insertions(+), 154 deletions(-) diff --git a/Project.toml b/Project.toml index 4cb6b07..37f3bf2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,17 +1,17 @@ name = "LaTeXDatax" uuid = "644dedec-337d-45c6-9a86-27a5fed2b77d" authors = ["David Gustavsson and contributors"] -version = "2.1.0" +version = "3.0.0" [deps] -Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" +Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +UnitfulLatexify = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" [compat] -Formatting = "0.4" -Requires = "1.1" +Latexify = "0.14.7" Unitful = "1.5" +UnitfulLatexify = "1.3.0" julia = "1" [extras] diff --git a/README.md b/README.md index a78f8cf..ec16b78 100644 --- a/README.md +++ b/README.md @@ -8,29 +8,21 @@ the accompanying package `datax.sty`. ## Usage ```julia -using LaTeXDatax -filename = "datafile.tex"; # default is "data.tex" +using LaTeXDatax, Unitful a = 25; -b = "Something"; -c = (300,"\\mega\\meter\\per\\second"); -using Unitful -d = 4.2u"Hz"; - -@datax a b c d filename -# or, equivalently, -data(a=a, b="Something", c=c, d=d, filename="datafile.tex"); +@datax a b=3a c=3e8u"m/s" d="Raw string" filename:="data.tex" ``` ```latex \documentclass{article} \usepackage{siunitx} -\usepackage[dataxfile=datafile.tex]{datax} +\usepackage[dataxfile=data.tex]{datax} \begin{document} The speed of light is \datax{c}. \end{document} ``` -More detailed usage information is in the docstrings of the code, run `?datax` -and `?@datax` in REPL to read them. +More detailed usage information is in the docstrings of the code, run `?@datax` +in REPL to read them. diff --git a/src/LaTeXDatax.jl b/src/LaTeXDatax.jl index 1753071..99f38a8 100644 --- a/src/LaTeXDatax.jl +++ b/src/LaTeXDatax.jl @@ -1,143 +1,112 @@ module LaTeXDatax -using Requires, Formatting +using Unitful, UnitfulLatexify, Latexify -export datax,@datax +export @datax """ ```julia -datax(...) +@datax ``` -Print the arguments to a file readable by pgfkeys (Best for use with the -`datax` LaTeX package). A string will be printed as is, a number will be -wrapped in `siunitx`'s `\\num`, and a tuple `(value::Number, unit::String)` or -a `Unitful` quantity will be wrapped in `\\SI`. If the argument is a `Tuple` -and the first argument is a string, it is used as a c-printf style format -string for the rest of the tuple (overriding the default format set by the -"format" argument). There's also a macro form, `@datax`, which reuses the -variable names from the script. +Print the arguments to a data file to be read by pgfkeys. Best used with the +[`datax` LaTeX package](https://ctan.org/pkg/datax). Variables can be supplied +either by name or as assignments, and meta-arguments are supplied using the +`:=` operator. -The variable names "filename" and "format" cannot be stored, but will instead -be used as the name of the file and the default number format respectively. +The meta-arguments include all the keyword arguments from `Latexify.jl` and +`UnitfulLatexify.jl` (for instance `unitformat := :siunitx`, `fmt := "%.2e"`), +as well as a few extra: + +# Meta-arguments +* `filename`: The path to a file that will be written. +* `io`: an `IO` object to write to instead of a file. Overrides the `filename` + argument. If neither this nor `filename` is given, `stdout` is used. +* `permissions`: Defaults to `"w"`. Can be given as `"a"` to append to a file + instead of overwriting. Only meaningful with a `filename` argument. # Examples ```julia -datax(a=2,b=1.24,c="hi",d=(24,"\\meter"),e=15u"kg/s^2") -``` -Save the given variables in siunitx form. +julia> a = 2; +julia> b = 3.2u"m"; +julia> @datax a b c=3*a d=27 unitformat:=:siunitx +\\pgfkeyssetvalue{/datax/a}{\\num{2}} +\\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}} +\\pgfkeyssetvalue{/datax/c}{\\num{6}} +\\pgfkeyssetvalue{/datax/d}{\\num{27}} -```julia -datax(lambda=612.2u"nm",filename="other.tex",format="%.4e") -datax(lambda=("%.4e",612.2,"\\nano\\meter"),filename="other.tex") ``` -Save just the variable lambda, in the file "other.tex", in scientific notation -with 4 digits of accuracy. The two lines are equivalent. """ -function datax(;filename="data.tex",format="%.4g",kwargs...) - datax(Dict(kwargs),filename=filename) +macro datax(args...) + esc(datax_helper(args...)) end -function datax(d::Dict{Symbol,<:Any};filename="data.tex",format::String="%.4g") - open(filename,"w") do f - println(f,"% Autogenerated by LaTeXDatax.jl, will be overwritten") - for (k,v) in d - print(f,"\\pgfkeyssetvalue{/datax/$k}{") - printdata(f,v,format) - print(f,"}\n") +function datax_helper(args...) + metaargs = Expr[] + names = Symbol[] + values = Any[] + for a in args + if a isa Symbol + push!(names, a) + push!(values, a) + continue + end + if a.head == :(=) + push!(names, a.args[1]) + push!(values, a.args[2]) + continue end + if a.head == :(:=) + push!(metaargs, Expr(:kw,a.args[1],a.args[2])) + continue + end + error("I don't know what to do with argument $a") end -end - -""" -```julia -@datax ... -``` -Print the arguments to a file readable by pgfkeys (Best for use with the -`datax` LaTeX package). Like the `datax()` function, but use the variables' -names. - -# Examples -```julia -a=2; -b=3.2u"m"; -c="hi"; -filename="datafile.tex"; -format="%.2g"; -@datax a b c filename format -``` -""" -macro datax(args...) - esc(datax_helper(args...)) -end -function datax_helper(filname="data.tex",format="%.4g",args...) - names = Expr(:vect, QuoteNode.(args)...) - values = Expr(:vect, args...) + names = Expr(:tuple, QuoteNode.(names)...) + values = Expr(:tuple, values...) quote - datax(Dict($names .=> $values),filename=filename) + LaTeXDatax.datax($names,$values;$(metaargs...)) + nothing end end -printdata(f::IO,v::String,fmt::String) = print(f,v) -printdata(f::IO,v::Number,fmt::String) = print(f,"\\num{",sprintf1(fmt,v),"}") -printdata(f::IO,v::AbstractArray{<:Number},fmt::String) = print(f,"\\numlist{",prod(sprintf1.(fmt,v).*";"),"}") -printdata(f::IO,v::Tuple{<:Number,String},fmt::String) = print(f,"\\SI{",sprintf1(fmt,v[1]),"}{",v[2],"}") -printdata(f::IO,v::Tuple{AbstractArray{<:Number},String},fmt::String) = print(f, - "\\SIlist{", - prod( - sprintf1.(fmt,v[1]).*";") - ,"}{", - v[2], - "}" - ) -printdata(f::IO,v::Tuple{String,Vararg},fmt::String) = printdata(f,length(v)>2 ? v[2:end] : v[2], v[1]) +function datax(names, values; kwargs...) + if haskey(kwargs, :io) + datax(kwargs[:io], names, values; kwargs...) + return nothing + end + if haskey(kwargs, :filename) + datax(kwargs[:filename], names, values; kwargs...) + return nothing + end + datax(stdout, names, values; kwargs...) + return nothing +end -function __init__() - @require Unitful="1986cc42-f94f-5a68-af5c-568840ba703d" begin +datax(io::IO, names, values; kwargs...) = printkeyval.(Ref(io),names,values; kwargs...) - function printdata(f::IO,v::Unitful.Quantity,fmt::String) - print(f,"\\SI{"*sprintf1(fmt,v.val)*"}{") - siunitxprint(f,Unitful.unit(v)) - print(f,"}") - end - function printdata(f::IO,v::AbstractArray{T},fmt::String) where T<:Unitful.Quantity - print(f,"\\SIlist{"*prod(sprintf1.(fmt,Unitful.ustrip(v)).*";")*"}{") - siunitxprint(f,Unitful.unit(T)) - print(f,"}") +function datax(filename::String, names, values; permissions="w", kwargs...) + if haskey(kwargs,:overwrite) + if kwargs[:overwrite] + permissions = "w" + else + permissions = "a" end - - function siunitxprint(f::IO,u::Unitful.FreeUnits) - prefixes = Dict( - -24 => "\\yocto", - -21 => "\\zepto", - -18 => "\\atto", - -15 => "\\femto", - -12 => "\\pico", - -9 => "\\nano", - -6 => "\\micro", - -3 => "\\milli", - -2 => "\\centi", - -1 => "\\deci", - 0 => "", - 1 => "\\deka", - 2 => "\\hecto", - 3 => "\\kilo", - 6 => "\\mega", - 9 => "\\giga", - 12 => "\\tera", - 15 => "\\peta", - 18 => "\\exa", - 21 => "\\zetta", - 24 => "\\yotta" - ) - for p in typeof(u).parameters[1] - p.power<0 && print(f,"\\per") - iszero(p.tens) || print(f,prefixes[p.tens]) - print(f,"\\$(lowercase(String(Unitful.name(p))))") - abs(p.power)==1 || print(f,"\\tothe$(Int64(abs(p.power)))") - end - end - + end + open(filename, permissions) do io + permissions == "w" && println(io, "% Autogenerated by LaTeXDatax.jl, will be overwritten") + datax(io, names, values; kwargs...) end end +function printkeyval(io::IO, name, value; kwargs...) + print(io, "\\pgfkeyssetvalue{/datax/", name, "}{") + printdata(io, value; kwargs...) + print(io, "}\n") + return nothing +end + +printdata(io::IO, v::String; kwargs...) = print(io, v) +printdata(io::IO, v::Number; kwargs...) = print(io, latexify(v*u"one"; kwargs...)) +printdata(io::IO, v; kwargs...) = print(io, latexify(v; kwargs...)) + end # module diff --git a/test/runtests.jl b/test/runtests.jl index a943fe2..e02b257 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,32 +4,28 @@ using Test @testset "LaTeXDatax.jl" begin io = IOBuffer(); - # Basic printing - LaTeXDatax.printdata(io,"String","%.4g") + # Basic data printing + LaTeXDatax.printdata(io,"String") @test String(take!(io)) == "String" - LaTeXDatax.printdata(io,4.1,"%.4g") - @test String(take!(io)) == "\\num{4.1}" - LaTeXDatax.printdata(io,[1.0,2.4,3.0],"%.4g") - @test String(take!(io)) == "\\numlist{1;2.4;3;}" - # Print units - LaTeXDatax.printdata(io,(1.0,"\\meter"),"%.4g") - @test String(take!(io)) == "\\SI{1}{\\meter}" - LaTeXDatax.printdata(io,([1,2,3],"\\kilogram"),"%.4g") - @test String(take!(io)) == "\\SIlist{1;2;3;}{\\kilogram}" + LaTeXDatax.printdata(io,1.25) + @test String(take!(io)) == "\$1.25\$" - # Format strings - LaTeXDatax.printdata(io,pi,"%.3g") + LaTeXDatax.printdata(io,3.141592; fmt="%.2f", unitformat=:siunitx) @test String(take!(io)) == "\\num{3.14}" - LaTeXDatax.printdata(io,("%.2g",pi),"%.4g") - @test String(take!(io)) == "\\num{3.1}" - LaTeXDatax.printdata(io,("%.5g",pi,"\\liter"),"%.4g") - @test String(take!(io)) == "\\SI{3.1416}{\\liter}" - # Unitful - LaTeXDatax.printdata(io,2u"m","%.4g") - @test String(take!(io)) == "\\SI{2}{\\meter}" - LaTeXDatax.printdata(io,[1.4,2.8]u"g/J","%.4g") - @test String(take!(io)) == "\\SIlist{1.4;2.8;}{\\gram\\per\\joule}" + # keyval printing + LaTeXDatax.printkeyval(io, :a, 612.2u"nm") + @test String(take!(io)) == "\\pgfkeyssetvalue{/datax/a}{\$612.2\\;\\mathrm{nm}\$}\n" + # complete macro + a = 2; + b = 3.2u"m"; + @datax a b c=3*a d=27 unitformat:=:siunitx io:=io + @test String(take!(io)) == """ + \\pgfkeyssetvalue{/datax/a}{\\num{2}} + \\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}} + \\pgfkeyssetvalue{/datax/c}{\\num{6}} + \\pgfkeyssetvalue{/datax/d}{\\num{27}} + """ end