diff --git a/Project.toml b/Project.toml index 6e337361..b52a49e9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Accessors" uuid = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" authors = ["Takafumi Arakaki ", "Jan Weidner and contributors"] -version = "0.1.34" +version = "0.1.35" [deps] CompositionsBase = "a33af91c-f02d-484b-be07-31d278c5ca2b" @@ -15,22 +15,16 @@ 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" diff --git a/ext/AccessorsDatesExt.jl b/ext/AccessorsDatesExt.jl deleted file mode 100644 index 392f5276..00000000 --- a/ext/AccessorsDatesExt.jl +++ /dev/null @@ -1,37 +0,0 @@ -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 diff --git a/ext/AccessorsLinearAlgebraExt.jl b/ext/AccessorsLinearAlgebraExt.jl deleted file mode 100644 index ca47b952..00000000 --- a/ext/AccessorsLinearAlgebraExt.jl +++ /dev/null @@ -1,11 +0,0 @@ -module AccessorsLinearAlgebraExt - -import Accessors: set, @set -using LinearAlgebra: norm, normalize, diag, diagind - -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(A, ::typeof(diag), val) = @set A[diagind(A)] = val - -end diff --git a/ext/AccessorsTestExt.jl b/ext/AccessorsTestExt.jl deleted file mode 100644 index f69bc41c..00000000 --- a/ext/AccessorsTestExt.jl +++ /dev/null @@ -1,44 +0,0 @@ -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 diff --git a/src/Accessors.jl b/src/Accessors.jl index d23f319e..0a1cc2a7 100644 --- a/src/Accessors.jl +++ b/src/Accessors.jl @@ -20,10 +20,4 @@ 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 diff --git a/src/functionlenses.jl b/src/functionlenses.jl index ed5e3071..90a4adb8 100644 --- a/src/functionlenses.jl +++ b/src/functionlenses.jl @@ -1,3 +1,6 @@ +using LinearAlgebra: norm, normalize, diag, diagind +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 @@ -99,6 +102,8 @@ modify(f, obj, o::typeof(skipmissing)) = @modify(f, obj |> filter(!ismissing, _) set(obj, ::typeof(sort), val) = @set obj[sortperm(obj)] = val modify(f, obj, ::typeof(sort)) = @modify(f, obj[sortperm(obj)]) +set(A, ::typeof(diag), val) = @set A[diagind(A)] = val + ################################################################################ ##### os ################################################################################ @@ -131,10 +136,46 @@ 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) = hypot(obj...) .* sincos(val) -set(obj, ::typeof(Base.splat(hypot)), val) = map(Base.Fix2(*, val / hypot(obj...)), obj) +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) ################################################################################ ##### strings diff --git a/src/testing.jl b/src/testing.jl index 2687a6ae..e5f356a9 100644 --- a/src/testing.jl +++ b/src/testing.jl @@ -1,5 +1,40 @@ -# placeholders only -# actual definitions in ext/AccessorsTestExt.jl -function test_getset_laws end -function test_modify_law end -function test_getsetall_laws end +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