Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Heptazhou committed Oct 28, 2024
1 parent 395dd57 commit 1698c45
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 6 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ jobs:
- uses: heptazhou/julia-codecov@v1
with:
dirs: src:ext
- uses: codecov/codecov-action@v3.1.5
- uses: codecov/codecov-action@v4
with:
file: lcov.info
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
docs:
runs-on: ubuntu-latest
timeout-minutes: 10
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Exts"
uuid = "0b12d779-4123-4875-9d6c-e33c2e29e2c9"
authors = ["Heptazhou <zhou at 0h7z dot com>"]
version = "0.1.8"
version = "0.1.9"

[deps]
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
Expand Down
2 changes: 1 addition & 1 deletion ext/StatisticsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Compute the weighted mean of array `A` with weight vector `w`, and fallback
to the unweighted mean if `w` is all zero(s) (instead of returning `NaN`). If
`dims` (of type `Int`) is provided, compute the mean along dimension `dims`.
See also [`mean(::AbstractArray)`](@extref `Statistics.mean`),
See also [`mean(::AbstractArray)`](@extref Statistics.mean),
[`mean(::AbstractArray,
::AbstractWeights)`](https://juliastats.org/StatsBase.jl/stable/scalarstats/#Statistics.mean).
"""
Expand Down
11 changes: 9 additions & 2 deletions src/Exts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ export Maybe
export SymOrStr
export VTuple

export @catch
export @noinfo
export @nowarn
export @try
export @trycatch
export getfirst
export getlast
export invsqrt
export lmap
export nanmean
export readstr
export stdpath

using Logging: Logging
using Reexport: @reexport
Expand All @@ -36,8 +40,6 @@ using Reexport: @reexport
using Base.Threads: @spawn, @threads, nthreads
end

include("BaseExt.jl")
include("Function.jl")
include("Macro.jl")
include("Type.jl")

Expand All @@ -47,6 +49,11 @@ getfirst(predicate::Function) = Base.Fix1(getfirst, predicate)
getlast(predicate::Function, A) = A[findlast(predicate, A)]
getlast(predicate::Function) = Base.Fix1(getlast, predicate)

slash(x::AbstractString)::String = replace(x, '\\' => '/')

include("BaseExt.jl")
include("Function.jl")

# StatisticsExt
function nanmean end

Expand Down
82 changes: 81 additions & 1 deletion src/Function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ end
lmap(f, iterators...)
Create a lazy mapping. This is another syntax for writing `(f(args...) for
args in zip(iterators...))`.
args in zip(iterators...))`. Equivalent to [`Iterators.map`](@extref
Base.Iterators.map).
See also [`map`](@extref Base.map).
# Examples
```jldoctest
Expand Down Expand Up @@ -76,3 +79,80 @@ function invsqrt(x::T) where T <: Real
F(big(x) |> inv |> sqrt)
end

"""
Exts.isdir(path::AbstractString) -> Bool
Return `true` if `path` is a directory, `false` otherwise.
# Examples
```jldoctest
julia> Exts.isdir(homedir())
true
julia> Exts.isdir("not/a/directory")
false
```
See also [`isfile`](@extref Base.Filesystem.isfile) and [`ispath`](@extref
Base.Filesystem.ispath).
"""
function isdir(path::AbstractString)::Bool
p = slash(path)
r = Base.isdir(p)
@static !Sys.iswindows() ? r : r =
!r || !contains(p, r"(?:^|/)\.{3,}(?:/|$)"s) ? r :
@try pwd() cd(pwd, p) realpath("/") false
end

"""
Exts.isdirpath(path::AbstractString) -> Bool
Determine whether a path refers to a directory (for example, ends with a path
separator).
# Examples
```jldoctest
julia> Exts.isdirpath("/home")
false
julia> Exts.isdirpath("/home/")
true
```
"""
function isdirpath(path::AbstractString)::Bool
path == "" && return false
Base.isdirpath(path)
end

"""
stdpath(path::AbstractString...; real = false) -> String
Standardize a path (or a set of paths, by joining them together), removing
"." and ".." entries and changing path separator to the standard "/".
If `path` is a directory, the returned path will end with a "/".
If `real` is true, symbolic links are expanded, however the `path` must exist
in the filesystem. On case-insensitive case-preserving filesystems, the
filesystem's stored case for the path is returned.
# Examples
```jldoctest
julia> stdpath("/home/myuser/../example.jl")
"/home/example.jl"
julia> stdpath("Documents\\\\Julia\\\\")
"Documents/Julia/"
```
"""
function stdpath(path::AbstractString, paths::AbstractString...; real::Bool = false)::String
p = joinpath(path, paths...)
p = !isempty(p) ? normpath(p) : return p
a = isabspath(p)
d = isdirpath(p) || isdir(p)
p = real ? realpath(p) : p
p = !a ? relpath(p) : p
p = slash(p)
p = !d || endswith(p, '/') ? p : p * '/'
end

58 changes: 58 additions & 0 deletions src/Macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,61 @@ for level ∈ ("info", "warn")
end
end

@eval begin
"""
@try expr default = nothing
Evaluate the expression with a `try/catch` construct and return the
result. If any error (exception) occurs, return `default`.
See also [The-try/catch-statement](@extref), [`try/catch`](@extref try),
[`@trycatch`](@ref), [`@catch`](@ref).
"""
macro $(Symbol(:try))(expr, default = nothing)
quote
try
$(esc(expr))
catch
$(esc(default))
end
end
end
"""
@catch expr
Evaluate the expression with a `try/catch` construct and return the
thrown exception. If no error (exception) occurs, return `nothing`.
See also [The-try/catch-statement](@extref), [`try/catch`](@extref try),
[`@trycatch`](@ref), [`@try`](@ref).
"""
macro $(Symbol(:catch))(expr)
quote
try
$(esc(expr))
nothing
catch e
e
end
end
end
"""
@trycatch expr
Evaluate the expression with a `try/catch` construct and return either
the result or the thrown exception, whichever available.
See also [The-try/catch-statement](@extref), [`try/catch`](@extref try),
[`@try`](@ref), [`@catch`](@ref).
"""
macro trycatch(expr)
quote
try
$(esc(expr))
catch e
e
end
end
end
end

60 changes: 60 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,36 @@ end
@test all(@. float(v) <: AbstractFloat)
end

@testset "Base" begin
@static if !Sys.iswindows()
#! format: noindent
@test Bool(0) == Base.isdir("")
@test Bool(1) == Base.isdir(".")
@test Bool(1) == Base.isdir("..")
@test Bool(0) == Base.isdir("...")
@test Bool(0) == Base.isdir("/...")
@test Bool(0) == Base.isdir("/.../")
else
#! format: noindent
@test Bool(0) == Base.isdir("")
@test Bool(1) == Base.isdir(".")
@test Bool(1) == Base.isdir("..")
@test Bool(1) == Base.isdir("...") # why?
@test Bool(1) == Base.isdir("/...") # why?
@test Bool(1) == Base.isdir("/.../") # why?
end
@test Bool(1) == Base.isdirpath("") # why?
@test Bool(1) == Base.isdirpath(".")
@test Bool(1) == Base.isdirpath("..")
@test Bool(0) == Base.isdirpath("...")
@test Bool(0) == Base.isdirpath("/...")
@test Bool(1) == Base.isdirpath("/.../")

@test joinpath("") == ""
@test normpath("") == "." # why?
@test_throws Base.IOError realpath("")
end

@testset "BaseExt" begin
@test_throws MethodError convert(Set, 1:3)
@test_throws MethodError convert(Set{Int}, 1:3)
Expand All @@ -46,20 +76,50 @@ end
@test_throws UndefVarError invsqrt
@test_throws UndefVarError Maybe
@test_throws UndefVarError readstr
@test_throws UndefVarError stdpath
using Exts

@test [:_ -1] == [:_, -1]'
@test [:p :q] == [:p, :q]'
@test ['1' '2'] == ['1', '2']'
@test ["x" "y"] == ["x", "y"]'
@test cd(() -> stdpath("../test"), @__DIR__) == "./"
@test chomp(readstr(@__FILE__)) == readchomp(@__FILE__)
@test convert(Set{Int}, 1:3) == convert(Set, 1:3) == Set(1:3)
@test getfirst(iseven, 1:9) == getfirst(iseven)(1:9) == 2
@test getlast(iseven, 1:9) == getlast(iseven)(1:9) == 8
@test invsqrt(2^-2) == 2
@test Maybe{Int} == Maybe(Int) == Maybe(Int, Int)
@test Maybe{Nothing} == Maybe(Nothing) == Nothing
@test stdpath("...") == "..."
@test stdpath("..") == "../"
@test stdpath(".") == "./"
@test stdpath("") == ""
@test_nowarn log10(11, 2)

@test Bool(0) == Exts.isdir("")
@test Bool(1) == Exts.isdir(".")
@test Bool(1) == Exts.isdir("..")
@test Bool(0) == Exts.isdir("...")
@test Bool(0) == Exts.isdir("/...")
@test Bool(0) == Exts.isdir("/.../")

@test Bool(0) == Exts.isdirpath("")
@test Bool(1) == Exts.isdirpath(".")
@test Bool(1) == Exts.isdirpath("..")
@test Bool(0) == Exts.isdirpath("...")
@test Bool(0) == Exts.isdirpath("/...")
@test Bool(1) == Exts.isdirpath("/.../")

@eval begin
#! format: noindent
@test @try error() true
@test @trycatch true
@test ErrorException("") == @catch error()
@test ErrorException("") == @trycatch error()
@test isnothing(@catch true)
@test isnothing(@try error())
end
end

@testset "DataFramesExt" begin
Expand Down

0 comments on commit 1698c45

Please sign in to comment.