Skip to content

Commit 1685218

Browse files
committed
add regex based symbol matchen for metadata accessors
1 parent f07357a commit 1685218

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

src/metadata.jl

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,44 @@ function _assert_symbol_exists(c::ComponentModel, s::Symbol)
1818
return nothing
1919
end
2020

21+
function _match_symbol_name(c::ComponentModel, pattern)
22+
allsym = Symbol[]
23+
append!(allsym, sym(c))
24+
append!(allsym, psym(c))
25+
hasinsym(c) && append!(allsym, insym_all(c))
26+
append!(allsym, outsym_flat(c))
27+
append!(allsym, obssym(c))
28+
allssym = unique!(allsym)
29+
30+
fidx = findall(sym -> contains(string(sym), pattern), allsym)
31+
if isempty(fidx)
32+
throw(ArgumentError("No symbol matching pattern $pattern found in component model."))
33+
elseif length(fidx) > 1
34+
throw(ArgumentError("Multiple symbols matching pattern $pattern found in component model: $(allsym[fidx]). Please use a more specific pattern."))
35+
end
36+
return Symbol(allsym[only(fidx)])
37+
end
38+
2139
"""
2240
has_metadata(c::ComponentModel, sym::Symbol, key::Symbol)
2341
has_metadata(nw::Network, sni::SymbolicIndex, key::Symbol)
2442
2543
Checks if symbol metadata `key` is present for symbol `sym` in a component model,
2644
or for a symbol referenced by `sni` in a network.
45+
46+
`sym` can also be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
47+
2748
Throws an error if the symbol does not exist in the component model.
2849
"""
2950
function has_metadata(c::ComponentModel, sym::Symbol, key::Symbol)
3051
_assert_symbol_exists(c, sym)
3152
md = symmetadata(c)
3253
haskey(md, sym) && haskey(md[sym], key)
3354
end
55+
function has_metadata(c::ComponentModel, pattern::Union{String,Regex}, key::Symbol)
56+
sym = _match_symbol_name(c, pattern)
57+
has_metadata(c, sym, key)
58+
end
3459
function has_metadata(nw::Network, sym::SymbolicIndex, key::Symbol)
3560
has_metadata(getcomp(nw, sym), sym.subidx, key)
3661
end
@@ -41,12 +66,19 @@ end
4166
4267
Retrieves the metadata `key` for symbol `sym` in a component model,
4368
or for a symbol referenced by `sni` in a network.
69+
70+
`sym` can also be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
71+
4472
Throws an error if the symbol does not exist in the component model.
4573
"""
4674
function get_metadata(c::ComponentModel, sym::Symbol, key::Symbol)
4775
_assert_symbol_exists(c, sym)
4876
symmetadata(c)[sym][key]
4977
end
78+
function get_metadata(c::ComponentModel, pattern::Union{String,Regex}, key::Symbol)
79+
sym = _match_symbol_name(c, pattern)
80+
get_metadata(c, sym, key)
81+
end
5082
function get_metadata(nw::Network, sym::SymbolicIndex, key::Symbol)
5183
get_metadata(getcomp(nw, sym), sym.subidx, key)
5284
end
@@ -59,19 +91,29 @@ end
5991
6092
Sets the metadata `key` for symbol `sym` to `value` in a component model,
6193
or for a symbol referenced by `sni` in a network.
94+
95+
For component models, you can also use a `String` or `Regex` pattern to match symbol names:
96+
- String patterns use substring matching (e.g., `"δ"` matches `machine₊δ`)
97+
- Regex patterns use full regex matching (e.g., `r"P\$"` matches symbols ending with "P")
98+
This will error if there is none or multile matches.
99+
100+
If the pattern matches multiple symbols, an error is thrown. Use a more specific pattern.
62101
Throws an error if the symbol does not exist in the component model.
63102
"""
64103
function set_metadata!(c::ComponentModel, sym::Symbol, key::Symbol, value)
65104
_assert_symbol_exists(c, sym)
66105
d = get!(symmetadata(c), sym, Dict{Symbol,Any}())
67106
d[key] = value
68107
end
108+
function set_metadata!(c::ComponentModel, pattern::Union{String,Regex}, key::Symbol, value)
109+
sym = _match_symbol_name(c, pattern)
110+
set_metadata!(c, sym, key, value)
111+
end
69112
function set_metadata!(nw::Network, sym::SymbolicIndex, key::Symbol, value)
70113
set_metadata!(getcomp(nw, sym), sym.subidx, key, value)
71114
end
72115

73116
function set_metadata!(c::ComponentModel, sym::Symbol, pair::Pair)
74-
_assert_symbol_exists(c, sym)
75117
set_metadata!(c, sym, pair.first, pair.second)
76118
end
77119
function set_metadata!(nw::Network, sym::SymbolicIndex, pair::Pair)
@@ -84,6 +126,9 @@ end
84126
85127
Removes the metadata `key` for symbol `sym` in a component model,
86128
or for a symbol referenced by `sni` in a network.
129+
130+
`sym` can also be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
131+
87132
Returns `true` if the metadata existed and was removed, `false` otherwise.
88133
Throws an error if the symbol does not exist in the component model.
89134
"""
@@ -99,6 +144,10 @@ function delete_metadata!(c::ComponentModel, sym::Symbol, key::Symbol)
99144
end
100145
return false
101146
end
147+
function delete_metadata!(c::ComponentModel, pattern::Union{String,Regex}, key::Symbol)
148+
sym = _match_symbol_name(c, pattern)
149+
delete_metadata!(c, sym, key)
150+
end
102151
delete_metadata!(nw::Network, sym::SymbolicIndex, key::Symbol) = delete_metadata!(getcomp(nw, sym), sym.subidx, key)
103152

104153
"""
@@ -136,6 +185,8 @@ for md in [:default, :guess, :init, :bounds]
136185
Checks if a `$($(QuoteNode(md)))` value is present for symbol `sym` in a component model,
137186
or for a symbol referenced by `sni` in a network.
138187
188+
`sym` can be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
189+
139190
See also [`get_$($(QuoteNode(md)))`](@ref), [`set_$($(QuoteNode(md)))!`](@ref).
140191
"""
141192
$fname_has(c::Comp_or_NW, sym) = has_metadata(c, sym, $(QuoteNode(md)))
@@ -147,6 +198,8 @@ for md in [:default, :guess, :init, :bounds]
147198
Returns the `$($(QuoteNode(md)))` value for symbol `sym` in a component model,
148199
or for a symbol referenced by `sni` in a network.
149200
201+
`sym` can be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
202+
150203
See also [`has_$($(QuoteNode(md)))`](@ref), [`set_$($(QuoteNode(md)))!`](@ref).
151204
"""
152205
$fname_get(c::Comp_or_NW, sym) = get_metadata(c, sym, $(QuoteNode(md)))
@@ -160,6 +213,8 @@ for md in [:default, :guess, :init, :bounds]
160213
161214
If `value` is `nothing` or `missing`, the metadata is removed.
162215
216+
`sym` can be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
217+
163218
See also [`has_$($(QuoteNode(md)))`](@ref), [`get_$($(QuoteNode(md)))`](@ref).
164219
"""
165220
function $fname_set(c::Comp_or_NW, sym, val)
@@ -177,6 +232,8 @@ for md in [:default, :guess, :init, :bounds]
177232
Removes the `$($(QuoteNode(md)))` value for symbol `sym` in a component model,
178233
or for a symbol referenced by `sni` in a network.
179234
235+
`sym` can be a String or Regex, to address the only symbol containing the pattern, see [`set_metadata!`](@ref) for details.
236+
180237
See also [`has_$($(QuoteNode(md)))`](@ref), [`set_$($(QuoteNode(md)))!`](@ref).
181238
"""
182239
$fname_del(c::Comp_or_NW, sym) = delete_metadata!(c, sym, $(QuoteNode(md)))

test/metadata_test.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,42 @@ end
335335
@test ismissing(df_with_custom[2, :custom_key])
336336
end
337337

338+
@testset "Pattern matching in metadata functions" begin
339+
# Create a test vertex model
340+
vm = Lib.swing_mtk()
341+
342+
# Test happy path - string pattern matching
343+
set_metadata!(vm, "θ", :test_key, "test_value")
344+
@test get_metadata(vm, , :test_key) == "test_value"
345+
346+
# Test happy path - regex pattern matching
347+
set_default!(vm, r"", 1.5)
348+
@test get_default(vm, ) == 1.5
349+
350+
# Test no match - should throw ArgumentError
351+
@test_throws ArgumentError set_metadata!(vm, "nonexistent", :test_key, "value")
352+
@test_throws ArgumentError set_init!(vm, r"xyz", 2.0)
353+
354+
set_bounds!(vm, "Pmech", (0.0, 10.0))
355+
@test get_bounds(vm, :Pmech) == (0.0, 10.0)
356+
357+
set_guess!(vm, "M", 5.0)
358+
@test get_guess(vm, :M) == 5.0
359+
360+
@test_throws ArgumentError set_guess!(vm, "", 5.0)
361+
@test_throws ArgumentError set_guess!(vm, r"", 5.0)
362+
363+
# Test basic pattern matching functions
364+
@test has_metadata(vm, "θ", :test_key)
365+
@test has_metadata(vm, r"", :test_key)
366+
@test get_metadata(vm, "θ", :test_key) == "test_value"
367+
@test get_metadata(vm, r"", :test_key) == "test_value"
368+
@test delete_metadata!(vm, "θ", :test_key)
369+
@test !has_metadata(vm, , :test_key)
370+
@test_throws ArgumentError has_metadata(vm, "nonexistent", :test_key)
371+
@test_throws ArgumentError get_metadata(vm, r"xyz", :test_key)
372+
end
373+
338374
@testset "set_defaults! function" begin
339375
nw = basenetwork()
340376
modified_state = NWState(nw)

0 commit comments

Comments
 (0)