voxgig_struct 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/voxgig_struct.rb +35 -16
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff9e0e4d399722d0f1b625bc1c7ddc310a18db4affcdb6bc119fb300b30eae27
|
|
4
|
+
data.tar.gz: a51b33ce2ccd9f77a06092095017dc4f7aefb0be8e5a5981ab9a245d971913c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81946c4f83d01daf2a0705961cce4afcd74cea7ac7d02568bb2cd5ffe2ece3ed5f21e1182b65fe5e8eb08e2ad1ab429aa1fd11e1c42a6897060d7af683db3a2e
|
|
7
|
+
data.tar.gz: 3fea471cd507d9e78623301686f5dd29fdc9300675ea4a02b7adf60fe66a0d869e7e2053ac39813832a87a6313b4c29186ba2c521cdae387f9ab441893402fe5
|
data/README.md
CHANGED
|
@@ -468,7 +468,7 @@ VoxgigStruct.transform(
|
|
|
468
468
|
)
|
|
469
469
|
# { 'x' => { 'y' => [{ 'q' => 13, 'r' => 13, 'p' => 1 }, { 'q' => 23, 'r' => 23, 'p' => 1 }] } }
|
|
470
470
|
```
|
|
471
|
-
<!-- => {"x": {"y": [{"q": 13, "r": 13, "p": 1
|
|
471
|
+
<!-- => {"x": {"y": [{"p": 1, "q": 13, "r": 13}, {"p": 1, "q": 23, "r": 23}]}} -->
|
|
472
472
|
|
|
473
473
|
Putting a command in **key** position (or, for `$APPLY`, directly under a
|
|
474
474
|
map) is an error — commands must be list values:
|
|
@@ -490,7 +490,7 @@ VoxgigStruct.validate(
|
|
|
490
490
|
# { 'name' => 'Ada', 'age' => 36 }
|
|
491
491
|
```
|
|
492
492
|
|
|
493
|
-
<!-- => {"
|
|
493
|
+
<!-- => {"age": 36, "name": "Ada"} -->
|
|
494
494
|
|
|
495
495
|
<!-- example: select#query -->
|
|
496
496
|
```ruby
|
|
@@ -502,7 +502,7 @@ VoxgigStruct.select(
|
|
|
502
502
|
# [{ 'name' => 'Alice', 'age' => 30, '$KEY' => 'a' }]
|
|
503
503
|
```
|
|
504
504
|
|
|
505
|
-
<!-- => [{"
|
|
505
|
+
<!-- => [{"$KEY": "a", "age": 30, "name": "Alice"}] -->
|
|
506
506
|
|
|
507
507
|
### Builders
|
|
508
508
|
|
|
@@ -519,7 +519,7 @@ VoxgigStruct.jt(1, 2, 3) # [1, 2, 3]
|
|
|
519
519
|
### `Injection` class
|
|
520
520
|
|
|
521
521
|
Full implementation with `descend`, `child`, `setval` instance
|
|
522
|
-
methods.
|
|
522
|
+
methods. Used internally by `inject`/`transform`/`validate`; you
|
|
523
523
|
need it when writing custom injectors.
|
|
524
524
|
|
|
525
525
|
### Injection helpers
|
|
@@ -603,7 +603,7 @@ Ruby has `nil`. The port distinguishes:
|
|
|
603
603
|
### Method naming
|
|
604
604
|
|
|
605
605
|
Ruby method names match canonical lowercase (`getpath`, `setpath`,
|
|
606
|
-
`getprop`), not Ruby's idiomatic snake_case.
|
|
606
|
+
`getprop`), not Ruby's idiomatic snake_case. Parity beats style.
|
|
607
607
|
|
|
608
608
|
### Walk-based merge
|
|
609
609
|
|
|
@@ -640,7 +640,7 @@ portable to the Go / Rust / C / Lua / Zig ports.
|
|
|
640
640
|
### Sharp edges
|
|
641
641
|
|
|
642
642
|
- **Catastrophic backtracking.** Onigmo has internal mitigations for
|
|
643
|
-
some classic ReDoS shapes — `^(a+)+$` against 22 a
|
|
643
|
+
some classic ReDoS shapes — `^(a+)+$` against 22 repetitions of `a` plus `!` runs
|
|
644
644
|
in microseconds here. Larger inputs or different shapes can still
|
|
645
645
|
blow up; the safe rule is to stay inside the RE2 subset and avoid
|
|
646
646
|
nested quantifiers.
|
data/voxgig_struct.rb
CHANGED
|
@@ -5,8 +5,11 @@ module VoxgigStruct
|
|
|
5
5
|
# --- Debug Logging Configuration ---
|
|
6
6
|
DEBUG = false
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
# Lazy: the message block is only evaluated when DEBUG is on, so hot paths
|
|
9
|
+
# never pay to build (and `.inspect`-serialise whole nodes into) a debug
|
|
10
|
+
# string that would just be discarded.
|
|
11
|
+
def self.log
|
|
12
|
+
puts "[DEBUG] #{yield}" if DEBUG
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
# --- Helper to convert internal undefined marker to Ruby nil ---
|
|
@@ -202,34 +205,34 @@ module VoxgigStruct
|
|
|
202
205
|
# --- Internal getprop ---
|
|
203
206
|
# Returns the value if found; otherwise returns alt (default is UNDEF)
|
|
204
207
|
def self._getprop(val, key, alt = UNDEF)
|
|
205
|
-
log
|
|
208
|
+
log { "(_getprop) called with val=#{val.inspect} and key=#{key.inspect}" }
|
|
206
209
|
return alt if val.nil? || key.nil?
|
|
207
210
|
|
|
208
211
|
if islist(val)
|
|
209
212
|
key = key.to_i if key.to_s =~ /\A\d+\z/
|
|
210
213
|
unless key.is_a?(Numeric) && key >= 0 && key < val.size
|
|
211
|
-
log
|
|
214
|
+
log { "(_getprop) index #{key.inspect} out of bounds; returning alt" }
|
|
212
215
|
return alt
|
|
213
216
|
end
|
|
214
217
|
result = val[key]
|
|
215
|
-
log
|
|
218
|
+
log { "(_getprop) returning #{result.inspect} from array for key #{key}" }
|
|
216
219
|
result
|
|
217
220
|
elsif ismap(val)
|
|
218
221
|
key_str = key.to_s
|
|
219
222
|
if val.key?(key_str)
|
|
220
223
|
result = val[key_str]
|
|
221
|
-
log
|
|
224
|
+
log { "(_getprop) found key #{key_str.inspect} in hash, returning #{result.inspect}" }
|
|
222
225
|
result
|
|
223
226
|
elsif key.is_a?(String) && val.key?(key.to_sym)
|
|
224
227
|
result = val[key.to_sym]
|
|
225
|
-
log
|
|
228
|
+
log { "(_getprop) found symbol key #{key.to_sym.inspect} in hash, returning #{result.inspect}" }
|
|
226
229
|
result
|
|
227
230
|
else
|
|
228
|
-
log
|
|
231
|
+
log { "(_getprop) key #{key.inspect} not found; returning alt" }
|
|
229
232
|
alt
|
|
230
233
|
end
|
|
231
234
|
else
|
|
232
|
-
log
|
|
235
|
+
log { '(_getprop) value is not a node; returning alt' }
|
|
233
236
|
alt
|
|
234
237
|
end
|
|
235
238
|
end
|
|
@@ -280,7 +283,7 @@ module VoxgigStruct
|
|
|
280
283
|
end
|
|
281
284
|
|
|
282
285
|
def self.setprop(parent, key, val = :no_val_provided)
|
|
283
|
-
log
|
|
286
|
+
log { ">>> setprop called with parent=#{parent.inspect}, key=#{key.inspect}, val=#{val.inspect}" }
|
|
284
287
|
return parent unless iskey(key)
|
|
285
288
|
|
|
286
289
|
if ismap(parent)
|
|
@@ -305,7 +308,7 @@ module VoxgigStruct
|
|
|
305
308
|
parent.unshift(val)
|
|
306
309
|
end
|
|
307
310
|
end
|
|
308
|
-
log
|
|
311
|
+
log { "<<< setprop result: #{parent.inspect}" }
|
|
309
312
|
parent
|
|
310
313
|
end
|
|
311
314
|
|
|
@@ -942,8 +945,8 @@ module VoxgigStruct
|
|
|
942
945
|
part = stringify(getpath(inj_meta, part[6..-2]))
|
|
943
946
|
end
|
|
944
947
|
|
|
945
|
-
# $$ escapes $
|
|
946
|
-
part = part.gsub('$$', '$') if part.is_a?(String)
|
|
948
|
+
# $$ escapes $ (skip the gsub allocation for the common no-`$$` part)
|
|
949
|
+
part = part.gsub('$$', '$') if part.is_a?(String) && part.include?('$$')
|
|
947
950
|
|
|
948
951
|
if part == S_MT
|
|
949
952
|
ascends = 0
|
|
@@ -1789,8 +1792,21 @@ module VoxgigStruct
|
|
|
1789
1792
|
setprop(parent, n[0], clone(childtm))
|
|
1790
1793
|
end
|
|
1791
1794
|
parent.slice!(inj.dparent.length..-1) if parent.length > inj.dparent.length
|
|
1792
|
-
|
|
1793
|
-
|
|
1795
|
+
|
|
1796
|
+
# NOTE: modifying inj! This extends the child value loop in inject
|
|
1797
|
+
# to cover every cloned child.
|
|
1798
|
+
(size(keys)...size(parent)).each do |ckeyI|
|
|
1799
|
+
keys << strkey(ckeyI)
|
|
1800
|
+
end
|
|
1801
|
+
|
|
1802
|
+
# Restart the child value loop at the first element (the loop
|
|
1803
|
+
# increments keyI on resume) so that the first element is also
|
|
1804
|
+
# validated against the child template.
|
|
1805
|
+
inj.keyI = -1
|
|
1806
|
+
|
|
1807
|
+
# SKIP leaves the cloned child template in place at the first
|
|
1808
|
+
# element so the resumed loop can validate it.
|
|
1809
|
+
return SKIP
|
|
1794
1810
|
end
|
|
1795
1811
|
|
|
1796
1812
|
nil
|
|
@@ -1920,7 +1936,10 @@ module VoxgigStruct
|
|
|
1920
1936
|
pkeys = keysof(pval)
|
|
1921
1937
|
|
|
1922
1938
|
if pkeys.length.positive? && getprop(pval, '`$OPEN`') != true
|
|
1923
|
-
|
|
1939
|
+
# Literal presence: the shape DECLARES ck even when its value is nil.
|
|
1940
|
+
# Canonical uses `NONE === _lookup`; `haskey` is Group A (value-based)
|
|
1941
|
+
# and would drop records with a nil field from an open ($AND) select.
|
|
1942
|
+
badkeys = ckeys.reject { |ck| pval.is_a?(Hash) && pval.key?(strkey(ck)) }
|
|
1924
1943
|
if badkeys.length.positive?
|
|
1925
1944
|
inj.errs << "Unexpected keys at field #{pathify(inj.path, 1)}#{S_VIZ}#{join(badkeys, ', ')}"
|
|
1926
1945
|
end
|