Skip to content

Commit

Permalink
use weakdeps wherever possible
Browse files Browse the repository at this point in the history
  • Loading branch information
aplavin committed Jan 5, 2024
1 parent 630e0d6 commit 21c4082
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 81 deletions.
6 changes: 6 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,22 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[weakdeps]
AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[extensions]
AccessorsAxisKeysExt = "AxisKeys"
AccessorsDatesExt = "Dates"
AccessorsIntervalSetsExt = "IntervalSets"
AccessorsLinearAlgebraExt = "LinearAlgebra"
AccessorsStaticArraysExt = "StaticArrays"
AccessorsStructArraysExt = "StructArrays"
AccessorsTestExt = "Test"

[compat]
AxisKeys = "0.2"
Expand Down
37 changes: 37 additions & 0 deletions ext/AccessorsDatesExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module AccessorsDatesExt

using Accessors
import Accessors: set
using Dates

set(x::DateTime, ::Type{Date}, y) = DateTime(y, Time(x))
set(x::DateTime, ::Type{Time}, y) = DateTime(Date(x), y)
set(x::T, ::Type{T}, y) where {T <: Union{Date, Time}} = y

# directly mirrors Dates.value implementation in stdlib
set(x::Date, ::typeof(Dates.value), y) = @set x.instant.periods.value = y
set(x::DateTime, ::typeof(Dates.value), y) = @set x.instant.periods.value = y
set(x::Time, ::typeof(Dates.value), y) = @set x.instant.value = y

set(x::Date, ::typeof(year), y) = Date(y, month(x), day(x))
set(x::Date, ::typeof(month), y) = Date(year(x), y, day(x))
set(x::Date, ::typeof(day), y) = Date(year(x), month(x), y)
set(x::Date, ::typeof(yearmonth), y::NTuple{2}) = Date(y..., day(x))
set(x::Date, ::typeof(monthday), y::NTuple{2}) = Date(year(x), y...)
set(x::Date, ::typeof(yearmonthday), y::NTuple{3}) = Date(y...)
set(x::Date, ::typeof(dayofweek), y) = firstdayofweek(x) + Day(y - 1)

set(x::Time, ::typeof(hour), y) = Time(y, minute(x), second(x), millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(minute), y) = Time(hour(x), y, second(x), millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(second), y) = Time(hour(x), minute(x), y, millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(millisecond), y) = Time(hour(x), minute(x), second(x), y, microsecond(x), nanosecond(x))
set(x::Time, ::typeof(microsecond), y) = Time(hour(x), minute(x), second(x), millisecond(x), y, nanosecond(x))
set(x::Time, ::typeof(nanosecond), y) = Time(hour(x), minute(x), second(x), millisecond(x), microsecond(x), y)

set(x::DateTime, optic::Union{typeof.((year, month, day, yearmonth, monthday, yearmonthday, dayofweek))...}, y) = modify(d -> set(d, optic, y), x, Date)
set(x::DateTime, optic::Union{typeof.((hour, minute, second, millisecond))...}, y) = modify(d -> set(d, optic, y), x, Time)


set(x::AbstractString, optic::Base.Fix2{Type{T}}, dt::T) where {T <: Union{Date, Time, DateTime}} = Dates.format(dt, optic.x)

end
9 changes: 9 additions & 0 deletions ext/AccessorsLinearAlgebraExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module AccessorsLinearAlgebraExt

import Accessors: set
using LinearAlgebra: norm, normalize

set(arr, ::typeof(normalize), val) = norm(arr) * val
set(arr, ::typeof(norm), val) = map(Base.Fix2(*, val / norm(arr)), arr) # should we check val is positive?

end
44 changes: 44 additions & 0 deletions ext/AccessorsTestExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module AccessorsTestExt

using Accessors
using Test: @test

function Accessors.test_getset_laws(lens, obj, val1, val2; cmp=(==))
# set ⨟ get
val = lens(obj)
@test cmp(set(obj, lens, val), obj)

# get ⨟ set
obj1 = set(obj, lens, val1)
@test cmp(lens(obj1), val1)

# set idempotent
obj12 = set(obj1, lens, val2)
obj2 = set(obj12, lens, val2)
@test cmp(obj12, obj2)
end

function Accessors.test_modify_law(f, lens, obj)
obj_modify = modify(f, obj, lens)
old_val = lens(obj)
val = f(old_val)
obj_setfget = set(obj, lens, val)
@test obj_modify == obj_setfget
end

function Accessors.test_getsetall_laws(optic, obj, vals1, vals2; cmp=(==))
# setall ⨟ getall
vals = getall(obj, optic)
@test cmp(setall(obj, optic, vals), obj)

# getall ⨟ setall
obj1 = setall(obj, optic, vals1)
@test cmp(collect(getall(obj1, optic)), collect(vals1))

# setall idempotent
obj12 = setall(obj1, optic, vals2)
obj2 = setall(obj12, optic, vals2)
@test obj12 == obj2
end

end
6 changes: 6 additions & 0 deletions src/Accessors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ include("sugar.jl")
include("functionlenses.jl")
include("testing.jl")

@static if !isdefined(Base, :get_extension)
include("../ext/AccessorsDatesExt.jl")
include("../ext/AccessorsLinearAlgebraExt.jl")
include("../ext/AccessorsTestExt.jl")
end

end
43 changes: 2 additions & 41 deletions src/functionlenses.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using LinearAlgebra: norm, normalize
using Dates

# first and last on general indexable collections
set(obj, ::typeof(first), val) = @set obj[firstindex(obj)] = val
set(obj, ::typeof(last), val) = @set obj[lastindex(obj)] = val
Expand Down Expand Up @@ -132,46 +129,10 @@ set(x, f::Base.Fix2{typeof(rem)}, y) = set(x, @optic(last(divrem(_, f.x))), y)

set(x::AbstractString, f::Base.Fix1{typeof(parse), Type{T}}, y::T) where {T} = string(y)

set(arr, ::typeof(normalize), val) = norm(arr) * val
set(arr, ::typeof(norm), val) = map(Base.Fix2(*, val / norm(arr)), arr) # should we check val is positive?

set(f, ::typeof(inverse), invf) = setinverse(f, invf)

set(obj, ::typeof(Base.splat(atan)), val) = @set Tuple(obj) = norm(obj) .* sincos(val)
set(obj, ::typeof(Base.splat(hypot)), val) = @set norm(obj) = val

################################################################################
##### dates
################################################################################
set(x::DateTime, ::Type{Date}, y) = DateTime(y, Time(x))
set(x::DateTime, ::Type{Time}, y) = DateTime(Date(x), y)
set(x::T, ::Type{T}, y) where {T <: Union{Date, Time}} = y

# directly mirrors Dates.value implementation in stdlib
set(x::Date, ::typeof(Dates.value), y) = @set x.instant.periods.value = y
set(x::DateTime, ::typeof(Dates.value), y) = @set x.instant.periods.value = y
set(x::Time, ::typeof(Dates.value), y) = @set x.instant.value = y

set(x::Date, ::typeof(year), y) = Date(y, month(x), day(x))
set(x::Date, ::typeof(month), y) = Date(year(x), y, day(x))
set(x::Date, ::typeof(day), y) = Date(year(x), month(x), y)
set(x::Date, ::typeof(yearmonth), y::NTuple{2}) = Date(y..., day(x))
set(x::Date, ::typeof(monthday), y::NTuple{2}) = Date(year(x), y...)
set(x::Date, ::typeof(yearmonthday), y::NTuple{3}) = Date(y...)
set(x::Date, ::typeof(dayofweek), y) = firstdayofweek(x) + Day(y - 1)

set(x::Time, ::typeof(hour), y) = Time(y, minute(x), second(x), millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(minute), y) = Time(hour(x), y, second(x), millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(second), y) = Time(hour(x), minute(x), y, millisecond(x), microsecond(x), nanosecond(x))
set(x::Time, ::typeof(millisecond), y) = Time(hour(x), minute(x), second(x), y, microsecond(x), nanosecond(x))
set(x::Time, ::typeof(microsecond), y) = Time(hour(x), minute(x), second(x), millisecond(x), y, nanosecond(x))
set(x::Time, ::typeof(nanosecond), y) = Time(hour(x), minute(x), second(x), millisecond(x), microsecond(x), y)

set(x::DateTime, optic::Union{typeof.((year, month, day, yearmonth, monthday, yearmonthday, dayofweek))...}, y) = modify(d -> set(d, optic, y), x, Date)
set(x::DateTime, optic::Union{typeof.((hour, minute, second, millisecond))...}, y) = modify(d -> set(d, optic, y), x, Time)


set(x::AbstractString, optic::Base.Fix2{Type{T}}, dt::T) where {T <: Union{Date, Time, DateTime}} = Dates.format(dt, optic.x)
set(obj, ::typeof(Base.splat(atan)), val) = @set Tuple(obj) = hypot(obj...) .* sincos(val)
set(obj, ::typeof(Base.splat(hypot)), val) = map(Base.Fix2(*, val / hypot(obj...)), obj)

################################################################################
##### strings
Expand Down
45 changes: 5 additions & 40 deletions src/testing.jl
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
using Test: @test
function test_getset_laws(lens, obj, val1, val2; cmp=(==))

# set ⨟ get
val = lens(obj)
@test cmp(set(obj, lens, val), obj)

# get ⨟ set
obj1 = set(obj, lens, val1)
@test cmp(lens(obj1), val1)

# set idempotent
obj12 = set(obj1, lens, val2)
obj2 = set(obj12, lens, val2)
@test cmp(obj12, obj2)
end

function test_modify_law(f, lens, obj)
obj_modify = modify(f, obj, lens)
old_val = lens(obj)
val = f(old_val)
obj_setfget = set(obj, lens, val)
@test obj_modify == obj_setfget
end

function test_getsetall_laws(optic, obj, vals1, vals2; cmp=(==))

# setall ⨟ getall
vals = getall(obj, optic)
@test cmp(setall(obj, optic, vals), obj)

# getall ⨟ setall
obj1 = setall(obj, optic, vals1)
@test cmp(collect(getall(obj1, optic)), collect(vals1))

# setall idempotent
obj12 = setall(obj1, optic, vals2)
obj2 = setall(obj12, optic, vals2)
@test obj12 == obj2
end
# placeholders only
# actual definitions in ext/AccessorsTestExt.jl
function test_getset_laws end
function test_modify_law end
function test_getsetall_laws end

0 comments on commit 21c4082

Please sign in to comment.