|
1 | 1 | module DynamicObjects |
2 | | -export DynamicObject, @dynamic_object#, update, cached, |
| 2 | +export AbstractDynamicObject, DynamicObject, @dynamic_object, @dynamic_type#, update, cached, |
3 | 3 | import Serialization |
4 | 4 |
|
5 | | -""" |
6 | | - DynamicObject{T} |
7 | 5 |
|
8 | | -A `DynamicObject` is a thin named wrapper around a generic NamedTuple which enables function overloading. |
9 | | -The type is inefficient computationally, but can enable more efficient prototyping/development. |
10 | | -""" |
11 | | -struct DynamicObject{T} |
12 | | - nt::NamedTuple |
13 | | - DynamicObject{T}(nt::NamedTuple) where T = new(nt) |
14 | | -end |
15 | 6 | esc_arg(arg::Symbol) = esc(arg) |
16 | 7 | function esc_arg(arg::Expr) |
17 | 8 | if arg.head == :(=) |
@@ -43,75 +34,128 @@ This dynamic type can be used in function definitions as |
43 | 34 | area(what::Rectangle) = what.height * what.width |
44 | 35 | ``` |
45 | 36 | """ |
| 37 | +get_sname(name::Symbol) = QuoteNode(name) |
| 38 | +get_sname(name::Expr) = QuoteNode(name.args[1]) |
| 39 | +ename_and_ebase(name::Symbol, default) = esc(name), esc(default) |
| 40 | +ename_and_ebase(name::Expr, default) = esc.(name.args) |
46 | 41 | macro dynamic_object(name, args...) |
47 | | - sname = QuoteNode(name) |
48 | | - ename = esc(name) |
| 42 | + sname = get_sname(name) |
| 43 | + ename, ebase = ename_and_ebase(name, :DynamicObject) |
| 44 | + # ename = esc(name) |
49 | 45 | eargs = esc_arg.(args) |
50 | 46 | kwargs = esc(:kwargs) |
51 | 47 | argnames = get_arg_symbol.(args) |
52 | 48 | aargs = [esc(:($(arg)=$(arg))) for arg in argnames] |
53 | 49 | quote |
54 | | - Base.@__doc__ $ename = DynamicObject{$sname} |
55 | | - $DynamicObject{$sname}($(eargs...); $kwargs...) = DynamicObject{$sname}(( |
| 50 | + Base.@__doc__ $ename = $ebase{$sname} |
| 51 | + $ebase{$sname}($(eargs...); $kwargs...) = $ebase{$sname}(( |
56 | 52 | $(aargs...), $kwargs... |
57 | 53 | )) |
58 | 54 | end |
59 | 55 | end |
60 | | -Base.propertynames(value::DynamicObject) = propertynames(value.nt) |
61 | | -function Base.getproperty(value::DynamicObject, name::Symbol) |
62 | | - if name == :nt |
63 | | - getfield(value, name) |
64 | | - else |
65 | | - if hasproperty(value.nt, name) |
66 | | - getproperty(value.nt, name) |
67 | | - else |
68 | | - getfield(Main, name)(value) |
| 56 | + |
| 57 | +abstract type AbstractDynamicObject end |
| 58 | + |
| 59 | +macro dynamic_type(name) |
| 60 | + ename, ebase = ename_and_ebase(name, :AbstractDynamicObject) |
| 61 | + NT = esc(:NamedTuple) |
| 62 | + Base = esc(:Base) |
| 63 | + quote |
| 64 | + Base.@__doc__ struct $ename{T} <: $ebase |
| 65 | + nt::$NT |
| 66 | + # $ename{T}(nt::$NT) where T = new(nt) |
| 67 | + end |
| 68 | + $Base.propertynames(what::$ename) = propertynames(what.nt) |
| 69 | + function $Base.getproperty(what::$ename, name::Symbol) |
| 70 | + if name == :nt |
| 71 | + getfield(what, name) |
| 72 | + else |
| 73 | + if hasproperty(what.nt, name) |
| 74 | + getproperty(what.nt, name) |
| 75 | + else |
| 76 | + getfield(Main, name)(what) |
| 77 | + end |
| 78 | + end |
69 | 79 | end |
| 80 | + $ename{T}(what::$ename) where T = $ename{T}(what.nt) |
| 81 | + $ename{T}(;kwargs...) where T = $ename{T}((;kwargs...)) |
| 82 | + $Base.show(io::IO, what::$ename{T}) where T = print(io, T, what.nt) |
| 83 | + $Base.merge(what::$ename, args...) = typeof(what)(merge(what.nt, args...)) |
| 84 | + update(what::$ename; kwargs...) = merge(what, (;kwargs...)) |
| 85 | + update(what::$ename, args...) = merge(what, (;zip(args, getproperty.([what], args))...)) |
| 86 | + $Base.hash(what::$ename{T}, h::Int=0) where T = hash((what.nt, T, h)) |
70 | 87 | end |
71 | 88 | end |
72 | | -# DynamicObject{T}(nt::NamedTuple) where T = DynamicObject{T}(nt) |
73 | | -DynamicObject{T}(what::DynamicObject) where T = DynamicObject{T}(what.nt) |
74 | | -DynamicObject{T}(;kwargs...) where T = DynamicObject{T}((;kwargs...)) |
| 89 | + |
| 90 | +""" |
| 91 | + DynamicObject{T} |
| 92 | +
|
| 93 | +A `DynamicObject` is a thin named wrapper around a generic NamedTuple which enables function overloading. |
| 94 | +The type is inefficient computationally, but can enable more efficient prototyping/development. |
| 95 | +""" |
| 96 | +@dynamic_type DynamicObject |
| 97 | +# struct DynamicObject{T} |
| 98 | +# nt::NamedTuple |
| 99 | +# DynamicObject{T}(nt::NamedTuple) where T = new(nt) |
| 100 | +# end |
| 101 | + |
| 102 | +# Base.propertynames(value::DynamicObject) = propertynames(value.nt) |
| 103 | +# function Base.getproperty(value::DynamicObject, name::Symbol) |
| 104 | +# if name == :nt |
| 105 | +# getfield(value, name) |
| 106 | +# else |
| 107 | +# if hasproperty(value.nt, name) |
| 108 | +# getproperty(value.nt, name) |
| 109 | +# else |
| 110 | +# getfield(Main, name)(value) |
| 111 | +# end |
| 112 | +# end |
| 113 | +# end |
| 114 | +# # DynamicObject{T}(nt::NamedTuple) where T = DynamicObject{T}(nt) |
| 115 | +# DynamicObject{T}(what::DynamicObject) where T = DynamicObject{T}(what.nt) |
| 116 | +# DynamicObject{T}(;kwargs...) where T = DynamicObject{T}((;kwargs...)) |
| 117 | +# Base.show(io::IO, what::DynamicObject{T}) where T = print(io, T, what.nt) |
| 118 | +# Base.merge(what::DynamicObject, args...) = typeof(what)(merge(what.nt, args...)) |
| 119 | +# update(what; kwargs...) = merge(what, (;kwargs...)) |
| 120 | +# update(what, args...) = merge(what, (;zip(args, getproperty.([what], args))...)) |
| 121 | +# Base.hash(what::DynamicObject{T}, h::Int=0) where T = Base.hash((what.nt, T, h)) |
| 122 | + |
| 123 | + |
| 124 | +# function cached(what::DynamicObject, key) |
| 125 | +# if hasproperty(what, key) |
| 126 | +# # println("LOADING FROM DynamicObject") |
| 127 | +# getproperty(what, key) |
| 128 | +# else |
| 129 | +# if !isdir("cache") |
| 130 | +# mkdir("cache") |
| 131 | +# end |
| 132 | +# file_name = "cache/$(key)_$(what.hash)" |
| 133 | +# if isfile(file_name) |
| 134 | +# # println("LOADING FROM FILE!") |
| 135 | +# Serialization.deserialize(file_name) |
| 136 | +# else |
| 137 | +# # println("COMPUTING") |
| 138 | +# rv = getproperty(what, key) |
| 139 | +# Serialization.serialize(file_name, rv) |
| 140 | +# rv |
| 141 | +# end |
| 142 | +# end |
| 143 | +# end |
75 | 144 |
|
76 | 145 | # DynamicObject{T}() where T = DynamicObject{T}(NamedTuple()) |
77 | 146 | # default(what, name) = missing |
78 | 147 | # getprop(what, name, def=default(DynamicObject, name)) = hasproperty(what, name) ? getproperty(what, name) : def |
79 | | -Base.show(io::IO, what::DynamicObject{T}) where T = print(io, T, what.nt) |
80 | | -Base.merge(what::DynamicObject, args...) = typeof(what)(merge(what.nt, args...)) |
| 148 | + |
81 | 149 | # Base.length(what::DynamicObject) = 1 |
82 | 150 | # Base.size(what::DynamicObject) = () |
83 | 151 | # Base.getindex(what::DynamicObject, i) = what |
84 | 152 | # Base.iterate(what::DynamicObject) = iterate([what]) |
85 | 153 | # Base.merge(what::DynamicObject, arg1::DynamicObject, args...) = typeof(what)(merge(what.nt, arg1.nt, args...)) |
86 | 154 | # igetproperty(obj, sym) = getproperty(obj, sym) |
87 | 155 | # igetproperty(obj, sym, args...) = igetproperty(getproperty(obj, sym), args...) |
88 | | -update(what; kwargs...) = merge(what, (;kwargs...)) |
89 | | -update(what, args...) = merge(what, (;zip(args, getproperty.([what], args))...)) |
90 | 156 | # update_default(what, args...) = update(wha) |
91 | 157 |
|
92 | 158 | # what = DynamicObject |
93 | | -Base.hash(what::DynamicObject{T}, h::Int=0) where T = Base.hash((what.nt, T, h)) |
94 | | - |
95 | | -function cached(what::DynamicObject, key) |
96 | | - if hasproperty(what, key) |
97 | | - # println("LOADING FROM DynamicObject") |
98 | | - getproperty(what, key) |
99 | | - else |
100 | | - if !isdir("cache") |
101 | | - mkdir("cache") |
102 | | - end |
103 | | - file_name = "cache/$(key)_$(what.hash)" |
104 | | - if isfile(file_name) |
105 | | - # println("LOADING FROM FILE!") |
106 | | - Serialization.deserialize(file_name) |
107 | | - else |
108 | | - # println("COMPUTING") |
109 | | - rv = getproperty(what, key) |
110 | | - Serialization.serialize(file_name, rv) |
111 | | - rv |
112 | | - end |
113 | | - end |
114 | | -end |
115 | 159 | # update_cached(what, args...) = merge(what, (;zip(args, cached.([what], args))...)) |
116 | 160 | # Plots.plot!(p, what) = Plots.plot() |
117 | 161 | # Plots.plot(what::DynamicObject{T}) where T = Plots.plot!(Plots.plot(), what) |
|
0 commit comments