I've been working on a package Mocking.jl 
<https://github.com/invenia/Mocking.jl> which allows developers to 
temporarily overwrite a method in order to facilitate testing. I've got 
everything working pretty well with the exception of the creation of a new 
macro which is suppose to ensure that Julia doesn't inline or optimize the 
call in such a way that the originally specified call can be overwritten:

julia> function myfunc(filename)

           readall(open(filename))

       end

myfunc (generic function with 1 method)


julia> myfunc("foo")

ERROR: SystemError: opening file foo: No such file or directory

 in open at ./iostream.jl:90

 in myfunc at none:2


julia> Base.open(name::AbstractString) = IOBuffer("bar")

WARNING: Method definition open(AbstractString) in module Base at 
iostream.jl:99 overwritten in module Main at none:1.

open (generic function with 8 methods)


julia> myfunc("foo")  # Open call within `myfunc` is not overwritten

ERROR: SystemError: opening file foo: No such file or directory

 in open at ./iostream.jl:90

 in myfunc at none:2


I can get this to work correctly with by adjusting the myfunc slightly:


julia> function myfunc(filename)

           readall([open([filename]...)]...)

       end

myfunc (generic function with 1 method)


julia> myfunc("foo")

ERROR: SystemError: opening file foo: No such file or directory

 in open at ./iostream.jl:90

 in open at iostream.jl:99

 in myfunc at none:2


julia> Base.open(name::AbstractString) = IOBuffer("bar")

WARNING: Method definition open(AbstractString) in module Base at 
iostream.jl:99 overwritten in module Main at none:1.

open (generic function with 8 methods)


julia> myfunc("foo")

"bar"


But this makes forces people to change their code and make it harder to 
read. Not to mention that this is just fooling the compiler into getting 
the behaviour I want. I would prefer to use a macro to get this behaviour 
and I managed to get the following horrible macro to work:



julia> macro fix(ex)

           name = gensym()

           :(@generated function $name() $ex end; $name())

       end


julia> function myfunc(filename)

           @fix readall(open(filename))

       end

myfunc (generic function with 1 method)


julia> myfunc("foo")

ERROR: SystemError: opening file foo: No such file or directory

 in open at ./iostream.jl:90

 in open at iostream.jl:99

 in #2###6995 at none:3

 in myfunc at none:2


julia> Base.open(name::AbstractString) = IOBuffer("bar")

WARNING: Method definition open(AbstractString) in module Base at 
iostream.jl:99 overwritten in module Main at none:1.

open (generic function with 8 methods)


julia> myfunc("foo")

"bar"


Does anyone have any suggestions on how I can improve this macro and get 
this behaviour? Bonus points if someone can tell me a good way of 
determining if the macro is being called from within a `Pkg.test(...)` 
process.

Reply via email to