Skip to content

Add MapExprFile #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/pkgfiles.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
"""
`MapExprFile(mapexpr, filename::String)` stores the arguments needed for
`include(mapexpr, filename)`. `mapexpr` is a function mapping `Expr` to an
`Expr`, which is applied to the parsed expressions from `filename` before
evaluation. This is sometimes used for preprocessing files before they are
loaded.

Otherwise, `MapExprFile` behaves like a string, allowing it to be used
wherever a file path is expected.
"""
struct MapExprFile <: AbstractString
mapexpr
filename::String
end
MapExprFile(filename::String) = MapExprFile(identity, filename)

Base.show(io::IO, mapfile::MapExprFile) =
print(io, "MapExprFile(", mapfile.mapexpr, ", \"", mapfile.filename, "\")")

# AbstractString interface
Base.iterate(mapfile::MapExprFile) = iterate(mapfile.filename)
Base.iterate(mapfile::MapExprFile, state::Integer) = iterate(mapfile.filename, state)

Base.getindex(mapfile::MapExprFile, i::Integer) = getindex(mapfile.filename, i)

Base.ncodeunits(mapfile::MapExprFile) = ncodeunits(mapfile.filename)
Base.codeunit(mapfile::MapExprFile, i::Integer) = codeunit(mapfile.filename, i)

Base.:(==)(mapfile1::MapExprFile, mapfile2::MapExprFile) =
(mapfile1.mapexpr == mapfile2.mapexpr) & (mapfile1.filename == mapfile2.filename)
Base.:(==)(mapfile1::MapExprFile, file2::AbstractString) = false
Base.:(==)(file1::AbstractString, mapfile2::MapExprFile) = false

# Don't lose the `mapexpr` from common path operations
Base.:(*)(mapfile::MapExprFile, path::AbstractString) =
MapExprFile(mapfile.mapexpr, mapfile.filename * path)
Base.:(*)(path::AbstractString, mapfile::MapExprFile) =
MapExprFile(mapfile.mapexpr, path * mapfile.filename)
# The above would be enough for `joinpath` except for its return-type assertion ::String
function Base.joinpath(mapfile::MapExprFile, path::AbstractString)
@assert !isa(path, MapExprFile) "Cannot join MapExprFile with another MapExprFile"
return MapExprFile(mapfile.mapexpr, joinpath(mapfile.filename, path))
end
function Base.joinpath(path::AbstractString, mapfile::MapExprFile)
@assert !isa(path, MapExprFile) "Cannot join MapExprFile with another MapExprFile"
return MapExprFile(mapfile.mapexpr, joinpath(path, mapfile.filename))
end
Base.normpath(mapfile::MapExprFile) = MapExprFile(mapfile.mapexpr, normpath(mapfile.filename))
Base.abspath(mapfile::MapExprFile) = MapExprFile(mapfile.mapexpr, abspath(mapfile.filename))
function Base.relpath(mapfile::MapExprFile, path::AbstractString)
@assert !isa(path, MapExprFile) "Cannot get relative path from MapExprFile to another MapExprFile"
return MapExprFile(mapfile.mapexpr, relpath(mapfile.filename, path))
end

"""
PkgFiles encodes information about the current location of a package.
Fields:
Expand All @@ -10,7 +64,7 @@ Note that `basedir` may be subsequently updated by Pkg operations such as `add`
mutable struct PkgFiles
id::PkgId
basedir::String
files::Vector{Any}
files::Vector{Any} # might contain `filename::String`, `::MapExprFile`, or custom file types (https://github.com/timholy/Revise.jl/pull/680)
end

PkgFiles(id::PkgId, path::AbstractString) = PkgFiles(id, path, Any[])
Expand Down
23 changes: 22 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using CodeTracking
using Test, InteractiveUtils, REPL, LinearAlgebra, SparseArrays
# Note: ColorTypes needs to be installed, but note the intentional absence of `using ColorTypes`

using CodeTracking: line_is_decl, MethodInfoKey
using CodeTracking: line_is_decl, MethodInfoKey, MapExprFile

if !isempty(ARGS) && "revise" ∈ ARGS
# For running tests with and without Revise
Expand Down Expand Up @@ -294,6 +294,27 @@ isdefined(Main, :Revise) ? Main.Revise.includet("script.jl") : include("script.j
@test line == 148
end

@testset "MapExprFile" begin
mapfile = MapExprFile(identity, "testfile.jl")
@test String(mapfile) == "testfile.jl"
@test sprint(show, mapfile) == "MapExprFile(identity, \"testfile.jl\")"
mappath = joinpath("base", mapfile)
@test mappath == MapExprFile(identity, joinpath("base", "testfile.jl"))
@test abspath(mapfile) == MapExprFile(identity, abspath("testfile.jl"))
@test normpath(mapfile) == MapExprFile(identity, normpath("testfile.jl"))
@test relpath(mappath, "base") == mapfile
@test isabspath(mapfile) == false
@test ispath(mapfile) == false
@test isfile(mapfile) == false
open(mapfile, "w") do io
write(io, "test content")
end
@test isabspath(mapfile) == false
@test ispath(mapfile) == true
@test isfile(mapfile) == true
rm(mapfile)
end

@testset "With Revise" begin
if isdefined(Main, :Revise)
m = @which gcd(10, 20)
Expand Down
Loading