I'm able to run the following code just fine and it provides the expected result:
julia> using DataFrames, DataFramesMeta
julia> expr = "2*:a+:b"
"2*:a+:b"
julia> df = DataFrame(a=[1,2],b=[3,4])
2×2 DataFrame
Row │ a b
│ Int64 Int64
─────┼──────────────
1 │ 1 3
2 │ 2 4
julia> eval(Meta.parse("@transform(df, " * join(collect(":res" => expr), " = ") * ")"))
2×3 DataFrame
Row │ a b res
│ Int64 Int64 Int64
─────┼─────────────────────
1 │ 1 3 5
2 │ 2 4 8
However, this fails when done inside a module.
julia> module foo
using DataFrames, DataFramesMeta
function bar()
expr = "2*:a+:b"
df = DataFrame(a=[1,2],b=[3,4])
eval(Meta.parse("@transform(df, " * join(collect(":res" => expr), " = ") * ")"))
end
end
Main.foo
julia> foo.bar()
ERROR: UndefVarError: df not defined
Stacktrace:
[1] top-level scope
@ ~/.julia/packages/DataFramesMeta/BkRtJ/src/macros.jl:1363
[2] eval
@ ./boot.jl:368 [inlined]
[3] eval
@ ./REPL[9]:1 [inlined]
[4] bar()
@ Main.foo ./REPL[9]:6
[5] top-level scope
@ REPL[10]:1
I imagine this is possible scope issue, and tried to be explicit by using foo.df
instead of df
in the function call, but without success.
Would anyone know how what is preventing df
from being recognized as a defined variable here?
Like Bogumil said eval
totally does not look like a recommended way to write your code.
However if your goal is learning macros this is the correct code:
module Foo2
using DataFrames, DataFramesMeta
function bar()
expr = "2*:a+:b"
df = DataFrame(a=[1,2],b=[3,4])
code = quote
@transform($df, :res = $(Meta.parse(expr)))
end
eval(code)
end
end
Now you can run:
julia> Foo2.bar()
2×3 DataFrame
Row │ a b res
│ Int64 Int64 Int64
─────┼─────────────────────
1 │ 1 3 5
2 │ 2 4 8