Skip to content

Implement comprehensive struct utility library with injection and transformation#53

Merged
rjrodger merged 25 commits intomainfrom
claude/compare-language-versions-RAVax
Apr 12, 2026
Merged

Implement comprehensive struct utility library with injection and transformation#53
rjrodger merged 25 commits intomainfrom
claude/compare-language-versions-RAVax

Conversation

@rjrodger
Copy link
Copy Markdown
Contributor

Summary

This PR implements a complete, multi-language struct utility library with support for deep value injection, path-based access, type validation, and recursive tree transformation. The implementation achieves functional parity across TypeScript (canonical), JavaScript, Python, Go, PHP, Ruby, Lua, and partial implementations in Java and C++.

Key Changes

Core Library Implementation (Ruby)

  • New utility functions: Added 40+ utility functions including getdef, size, slice, pad, getelem, flatten, filter, delprop, join, joinurl, jsonify, replace, and tree traversal helpers
  • Injection system: Implemented complete Injection class and inject() function with support for backtick expression resolution, metadata injection, and custom handlers
  • Path-based access: Enhanced getpath() to support complex path expressions with meta-path syntax, escape sequences, and injection definitions
  • Tree walking: Redesigned walk() function with before/after callbacks, depth limiting, and proper node traversal
  • Type system: Added typename() function with bitfield type constants (T_any, T_noval, T_boolean, T_decimal, T_integer, T_number, T_string, T_function, T_symbol, T_null, T_list, T_map, T_instance, T_scalar, T_node)
  • Mode constants: Added M_KEYPRE, M_KEYPOST, M_VAL bitfield constants with MODENAME mapping for injection phases

Enhanced Existing Functions

  • clone(): Now handles UNDEF sentinel properly
  • isempty(): Extended to recognize UNDEF as empty
  • items(): Added optional apply function parameter; list indices now converted to strings for consistency
  • stringify(): Improved handling of UNDEF, added pretty-printing support, fixed maxlen logic
  • pathify(): Enhanced with better UNDEF handling and fallback logic
  • merge(): Complete rewrite with depth limiting and proper node merging semantics
  • haskey(): Simplified signature to use UNDEF sentinel instead of variable args

Constants and Sentinels

  • Added UNDEF = Object.new.freeze as unique undefined marker
  • Added mode constants: M_KEYPRE = 1, M_KEYPOST = 2, M_VAL = 4
  • Added MAXDEPTH = 32 for recursion limiting
  • Added MODENAME and PLACEMENT hashes for mode introspection

Test Infrastructure

  • Updated test suite with 75+ passing tests
  • Enhanced deep_equal() helper for robust comparison
  • Added support for new utility functions in test runner
  • Improved test organization and assertion clarity

Cross-Language Consistency

  • PHP: Updated getpath() signature to match canonical (removed current parameter)
  • Python: Added MODENAME constant for consistency
  • Documentation: Added comprehensive REPORT.md documenting API parity across all language implementations

Notable Implementation Details

  1. Injection System: The Injection class maintains state during recursive tree traversal, supporting three phases (key:pre, value, key:post) for flexible transformation hooks.

  2. Path Resolution: getpath() now supports:

    • Meta-path syntax: key$=value or key$~pattern
    • Escape sequences: $BT (backtick), $DS (dollar sign)
    • Special references: $KEY, $GET:path, $REF:path, $META:path
    • Relative paths with .. (empty string) for parent traversal
  3. Backtick Injection: _injectstr() resolves backtick expressions in strings, supporting both full-string (\path`) and partial (prefix`path`suffix`) injection with fallback to empty string for missing keys.

  4. Merge Semantics: merge() implements proper node merging where matching node types (map-to-map, list-to-list) merge recursively, while non-nodes override directly.

  5. Type Bitfield: typify() returns a bitfield integer where each bit represents a

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr

claude added 25 commits April 9, 2026 10:39
Analyzes all 8 language implementations against the TypeScript canonical
for functional parity: functions, transform commands, validate checkers,
constants, and test status. Ranks completeness from JS/Go (100%) through
Java/C++ (~40-45%) with prioritized recommendations.

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Python: add MODENAME = {M_VAL: 'val', M_KEYPRE: 'key:pre', M_KEYPOST: 'key:post'}
  and export it in __all__. 84/84 tests pass.
- Lua: confirmed at full parity, 75/75 tests pass.
- Update REPORT.md to reflect both at 100% parity.

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Add checkPlacement, injectorArgs, injectChild public methods
- Add transform_FORMAT and transform_APPLY with FORMATTER map
- Register $FORMAT and $APPLY in transform handler map
- Make SKIP a public const (was private static)
- Add public MODENAME and private PLACEMENT constants
- Refactor getpath(store, path, injdef) to match TS 3-param signature
  (remove unused $current param, rename $state to $injdef)
- Remove dead _injectexpr function
- Update tests to use new getpath signature
- 82/82 tests pass, 920 assertions
- Update REPORT.md: PHP now at 100% parity

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Rewrite test_voxgig_struct.rb to match TS canonical API signatures:
  - getpath(store, path, injdef) instead of getpath(path, store, current, state)
  - inject(val, store) without extra positional params
  - transform(data, spec, injdef) with injdef hash for modify/extra
  - validate(data, spec, injdef) with injdef hash for extra/errs
  - walk(val, before, after, maxdepth) with separate callbacks
  - select(children, query)
- Add tests for all missing functions: getelem, delprop, join, jsonify,
  flatten, filter, size, slice, pad, setpath, getdef, jm, jt
- Remove all skip markers from transform/validate tests
- Add select tests (basic, operators, edge, alts)
- Fix voxgig_runner.rb: getpath call order in match()

Tests will fail until voxgig_struct.rb implementation is updated.

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Add 17 missing functions: getdef, getelem, delprop, size, slice, pad,
  flatten, filter, join, jsonify, jm, jt, replace, setpath, checkPlacement,
  injectorArgs, injectChild (stub), select (stub)
- Fix typify: nil→T_scalar|T_null (JSON null), UNDEF→T_noval (absent)
- Fix items: return string keys for lists (matching TS)
- Fix typename: use clz32 approach matching TS
- Fix haskey: simplify to match TS signature
- Fix walk: support before/after callbacks and maxdepth
- Fix getpath: correct param order (store, path, injdef) matching TS
- Fix merge: skip nil values, accept maxdepth param
- Add constants: M_KEYPRE, M_KEYPOST, M_VAL, MODENAME, PLACEMENT, MAXDEPTH
- Rewrite test file for new signatures (all 75 tests unskipped)
- Fix test runner: getpath param order, UNDEF for absent entries
- 31/75 tests now passing (was 28/47 with 13 skipped)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix stringify, typify, clone, isempty, size, slice, pad, join, pathify, jsonify
- Fix test lambdas to use correct field names from test spec
- 37/75 tests now passing (was 31)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix join: collapse internal duplicate separators (match TS line 641)
- Fix pathify: distinguish nil from UNDEF for null display
- Fix pad: correct test field name (char not fill)
- Update REPORT.md: Ruby now at 38/75 tests passing, all 40 functions added
- Remaining failures are in complex functions needing Injection class rewrite

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Replace old hash-based inject with proper Injection class architecture
- Three-phase mode cycling (key:pre -> val -> key:post) per child
- Add all 11 transform commands: DELETE, COPY, KEY, ANNO, META, MERGE, EACH, PACK, REF, FORMAT, APPLY
- Add all 15 validate checkers: STRING, TYPE (NUMBER/INTEGER/DECIMAL/BOOLEAN/NULL/NIL/MAP/LIST/FUNCTION/INSTANCE), ANY, CHILD, ONE, EXACT
- Add _validation modify callback and _validatehandler
- Add select with query matching via validate
- 52/75 tests now passing (was 38)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix select: use bare '$KEY' not backtick-wrapped key name
- Fix getpath: use split(".", -1) to preserve trailing empty strings (match TS/Python)
- Fix runner: handle UNDEF in fix_json
- 56/75 tests now passing (was 52)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix walk_depth test: use copy callback matching TS test pattern
- Fix walk_copy test: use before callback with cursor pattern
- Fix deep_equal: normalize hash key order before comparing
- Fix getpath split to preserve trailing empty strings
- 58/75 tests now passing (was 56)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix Injection.setval: nil triggers delprop (matching TS undefined delete)
- Fix pathify: guard against nil from array slicing
- 59/75 tests now passing (was 58)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Rewrite jsonify to match TS JSON.stringify(val, null, indent) behavior
  including empty array/object handling and indent/offset flags
- Fix setpath test: store args in runner for match validation
- Fix runner match result to include args for in-place mutation checks
- All 32 minor tests now passing
- 62/75 total tests passing (was 59)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Replace simple deep_merge with walk-based merge matching TS/Python
- Support maxdepth parameter
- Non-node values (including nil) override correctly
- Fix depth-limited merge: always set cur[pI] at boundary
- All 6 merge tests now passing
- 67/75 total tests passing (was 62)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix transform_KEY/ANNO/META: use delprop instead of setprop(nil)
- Fix transform_REF: delprop for unresolved refs
- Fix FORMATTER: nil.to_s → "null" matching TS (null+"").toUpperCase()
- Fix _injectstr partial: null data values produce "null" not empty string
- transform_each and transform_ref now passing
- inject_string now passing
- 70/75 tests pass, 0 failures, 5 remaining errors

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix concat formatter: nil values produce 'null' string (matching TS)
- transform_format test now passes
- 71/75 tests passing, 4 remaining edge cases

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
…tstr

- Fix delprop: validate integer key before delete_at on lists
  (was deleting index 0 for non-integer keys like `$ANNO`)
- Fix FORMATTER concat: nil values produce 'null' string
- Fix _injectstr partial: null data values produce 'null' not empty
- All 12 transform tests now passing
- 72/75 total tests passing (3 remaining: validate_exact, select_operators, select_edge)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Fix Injection.setval: nil without ancestor deletes (TS undefined behavior)
  nil WITH ancestor >= 2 sets to nil (preserves key for $ONE/$EXACT)
- All 8 validate tests now passing
- 73/75 total tests (2 remaining: select_operators, select_edge)

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
- Implement select operators: select_AND, select_OR, select_NOT, select_CMP
- Pass select operators as 'extra' in select's validate call
- Fix _validation exact mode: check key existence for null values
  (query {value:null} should not match child {} with no value key)
- All 75 tests passing across all categories:
  32 minor, 4 walk, 6 merge, 4 getpath, 3 inject,
  12 transform, 8 validate, 4 select, 1 json-builder, 1 exists

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
All 7 testable language versions verified with current test results:
- ts (canonical): 83/83 pass
- js: 84/84 pass - 100% parity
- py: 84/84 pass - 100% parity
- go: 92/92 pass - 100% parity
- php: 82/82 pass - 100% parity
- rb: 75/75 pass - 100% parity
- lua: 75/75 pass - 100% parity
- java: ~45% parity (incomplete)
- cpp: ~40% parity (incomplete)

7 of 9 languages at full parity with TypeScript canonical.

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
New test entries added to every test spec file:
- minor: clone (empty/false/0/nested), pad (numeric/null), setpath (deep paths)
- walk: mixed depth, null values, nested arrays
- merge: override precedence, null handling, array merge semantics
- getpath: null values, empty containers, non-existent paths
- transform: duplicate references, array specs, default values
- validate: null/$ANY/$NULL/$BOOLEAN type checks, multi-field validation
- select: empty query matches all, no-match returns empty

All 7 language implementations pass all tests:
- ts: 83/83, js: 84/84, py: 84/84, go: 92/92
- php: 82/82, rb: 75/75, lua: 75/75

https://claude.ai/code/session_01QkN2u1cRavoxb7UebdMcDr
@rjrodger rjrodger merged commit 1dda4e9 into main Apr 12, 2026
46 of 53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants