In DataFrames.jl there are a number of places where you have use this syntax
:col => fn => :newcol to compute new columns. This makes sense once you get used to it, but sometimes you want a traditional syntax of
newcol = functionName(:col)
So I decided to learn a bit of metaprogramming and try my hands at writing a simple macro. I think DataFramesMeta.jl does so some transformations like this but more complete. I hope that I can contribute to that in the future.
I call the macro PairAsPipe so
Coding tips for macros more than welcome.
df = DataFrame(X = 1:3) replacex(x) = x .* 2 # macro-less DataFrames.jl way transform(df, :X => replacex => :newX) # pap way with named new col transform(df, @pap newX = replacex(:X)) # pap way without named new col transform(df, @pap replacex(:X))
using MacroTools ex = :(replacex(:X)) macro pap(ex) has_newcol = @capture(ex, newcol_ = rhs_) if !has_newcol rhs = ex end # for obtaining symbols symbols = QuoteNode gen_symbols = Symbol rhs = MacroTools.postwalk(function(x) if x isa QuoteNode push!(symbols, x) push!(gen_symbols, MacroTools.gensym(x.value)) return gen_symbols[end] else return x end end, rhs) lhs = Expr(:tuple, gen_symbols...) # the fn in # :col => fn fn = Expr(:->, lhs, rhs) # the (:col1, :col2) in # the (:col1, :col2) => fn cols = Expr(:vect, symbols...) if has_newcol fn = Expr(:call, :(=>), fn, QuoteNode(newcol)) end Expr(:call, :(=>), cols, fn) end