From d57c9e33aeaab7a25111d2194c8077bc1f638aa4 Mon Sep 17 00:00:00 2001 From: mcmcgrath13 Date: Fri, 5 Jun 2020 16:07:16 -0400 Subject: [PATCH 1/3] feat: add function todict to revert to dictionary --- src/DotMaps.jl | 31 +++++++++++++++++++++++++------ test/runtests.jl | 10 ++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/DotMaps.jl b/src/DotMaps.jl index 508624b..928dd82 100644 --- a/src/DotMaps.jl +++ b/src/DotMaps.jl @@ -22,6 +22,25 @@ end DotMap(d::Any) = d +""" + DotMaps.todict(::DotMap) + +Constructs a Dict from a DotMap. +""" +function todict(obj::DotMap; keys_as_strings::Bool = false) + new_dict = Dict() + dm = obj.__dict__ + for (k, v) in dm + nk = keys_as_strings ? string(k) : k + new_dict[nk] = todict(v, keys_as_strings = keys_as_strings) + end + + return new_dict +end + +# return at leaves +todict(obj::Any; keys_as_strings::Bool = false) = obj + # make dots work function Base.getproperty(obj::DotMap, name::Symbol) if name == :__dict__ @@ -31,16 +50,16 @@ function Base.getproperty(obj::DotMap, name::Symbol) end end -function Base.setproperty!(obj::DotMap, name::Symbol, x) - obj.__dict__[name] = x -end - # make dictionary indexing work Base.getindex(obj::DotMap, name::Symbol) = Base.getindex(obj.__dict__, name) Base.getindex(obj::DotMap, name::Any) = Base.getindex(obj, Symbol(name)) -Base.setindex!(obj::DotMap, name::Symbol, x) = Base.setindex!(obj.__dict__, name, x) -Base.setindex!(obj::DotMap, name, x) = Base.setindex!(obj, Symbol(name), x) +Base.setindex!(obj::DotMap, x, name::Symbol) = Base.setindex!(obj.__dict__, x, name) +Base.setindex!(obj::DotMap, x::Dict, name::Symbol) = Base.setindex!(obj.__dict__, DotMap(x), name) +Base.setindex!(obj::DotMap, x, name) = Base.setindex!(obj, x, Symbol(name)) + +# assignment with dots +Base.setproperty!(obj::DotMap, name::Symbol, x) = Base.setindex!(obj, x, name) # iteration Base.iterate(obj::DotMap) = Base.iterate(obj.__dict__) diff --git a/test/runtests.jl b/test/runtests.jl index ec6a5fb..4cc62a0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -19,6 +19,9 @@ using Test @test DM.c.e == 5 @test DM["c"].e == 5 + DM.c.f = Dict("g" => 6) + @test DM.c.f.g == 6 + for (k, v) in DM @test isa(k, Symbol) end @@ -39,4 +42,11 @@ using Test @test :a in propertynames(DM) @test isempty(DotMap()) + + d = DotMap() + d.a = Dict("b" => 2) + dd = DotMaps.todict(d, keys_as_strings=true) + @test dd == Dict("a" => Dict("b" => 2)) + dds = DotMaps.todict(d) + @test dds == Dict(:a => Dict(:b => 2)) end From a2e02a5efb10c3d6b9d1ddc772fd746db776e8e8 Mon Sep 17 00:00:00 2001 From: mcmcgrath13 Date: Fri, 5 Jun 2020 16:17:35 -0400 Subject: [PATCH 2/3] docs: fix docstring, add to readme --- README.md | 3 +++ src/DotMaps.jl | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c388b67..88c67af 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ dm = DotMap(dict) dm.c.d # returns 3 dm.c.e = 5 dm["c"].e # returns 5 + +DotMap.todict(dm, keys_as_strings=true) # returns Dict("a"=>1, "b"=>2, "c" => Dict("d"=>3, "e"=>5)) +DotMap.todict(dm) # returns Dict(:a=>1, :b=>2, :c => Dict(:d=>3, :e=>5)) ``` **NOTE** This is not as performative as using normal dictionaries, but is nice for accessing deeply nested dictionary structures, such as large config/yaml/json files. diff --git a/src/DotMaps.jl b/src/DotMaps.jl index 928dd82..2db64c8 100644 --- a/src/DotMaps.jl +++ b/src/DotMaps.jl @@ -23,19 +23,18 @@ end DotMap(d::Any) = d """ - DotMaps.todict(::DotMap) + DotMaps.todict(::DotMap; keys_as_strings=false) -Constructs a Dict from a DotMap. +Constructs a Dict from a DotMap. If `keys_as_strings`, the keys will be `String` instead of `Symbol`. """ function todict(obj::DotMap; keys_as_strings::Bool = false) - new_dict = Dict() - dm = obj.__dict__ - for (k, v) in dm + dict = Dict() + for (k, v) in obj nk = keys_as_strings ? string(k) : k - new_dict[nk] = todict(v, keys_as_strings = keys_as_strings) + dict[nk] = todict(v, keys_as_strings = keys_as_strings) end - return new_dict + return dict end # return at leaves From 6963156e100a01814d3503b16e26835e4da21e82 Mon Sep 17 00:00:00 2001 From: mcmcgrath13 Date: Wed, 29 Jul 2020 20:37:42 -0400 Subject: [PATCH 3/3] feat: contructor uses abstract dict --- src/DotMaps.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DotMaps.jl b/src/DotMaps.jl index 2db64c8..54ab060 100644 --- a/src/DotMaps.jl +++ b/src/DotMaps.jl @@ -3,7 +3,7 @@ module DotMaps export DotMap """ - DotMaps.DotMap(::Dict) + DotMaps.DotMap(::AbstractDict) Constructs a DotMap from a Dict. This provides the same functionaliity as dictionaries, but allows indexing with `.` instead of (or in addition to) `[""]`. """ @@ -12,7 +12,7 @@ mutable struct DotMap DotMap() = new(Dict{Symbol,Any}()) end -function DotMap(d::Dict) +function DotMap(d::AbstractDict) dm = DotMap() for (k, v) in d dm.__dict__[Symbol(k)] = DotMap(v)