Skip to content

Support globals in Quickjs.eval_code - #64

Open
ollym wants to merge 1 commit into
hmsk:mainfrom
ollym:agent/eval-code-arguments
Open

Support globals in Quickjs.eval_code#64
ollym wants to merge 1 commit into
hmsk:mainfrom
ollym:agent/eval-code-arguments

Conversation

@ollym

@ollym ollym commented Aug 2, 2026

Copy link
Copy Markdown

Summary

  • add a globals: option to Quickjs.eval_code and Quickjs::VM.new
  • expose supplied Ruby values as JavaScript globals through QuickJS's native C API
  • reuse the existing Ruby-to-JavaScript converter for primitives, arrays, and hashes
  • document the API and add focused coverage for conversion and invalid input

Why

Callers currently need to interpolate values into JavaScript source. Native variable injection provides a concise API without generating a JavaScript wrapper or changing QuickJS core:

Quickjs.eval_code("a + b", globals: { a: 1, b: 2 }) # => 3

The values are installed on the new VM's global object during native initialization, before the code is evaluated.

Validation

  • bundle exec rake
  • 500 tests, 775 assertions, 0 failures, 1 existing skip
  • RBS validation passes

Allow callers to expose Ruby values as JavaScript globals through the globals option. Reuse the native Ruby-to-JavaScript converter so values do not need to be interpolated into generated source.
@ollym
ollym force-pushed the agent/eval-code-arguments branch from 64f8bff to acd155a Compare August 2, 2026 14:20
@ollym ollym changed the title Support variables in Quickjs.eval_code Support globals in Quickjs.eval_code Aug 2, 2026
@ollym
ollym marked this pull request as ready for review August 2, 2026 14:21
@hmsk

hmsk commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Thanks for the PR, and for covering docs, RBS and tests.

It's a real gap. My own README examples interpolate values into JS source, so this is on me to solve. I'd like to get the shape right first though, because "globals" turns out to be ambiguous here: let / const declarations persist across eval_code calls, but never appear on globalThis.

vm.eval_code('globalThis.a = 1;')   # what this PR does
vm.eval_code('let a = 2; a')        #=> 2
vm.eval_code('globalThis.a')        #=> 1

Two live values under one name. Related: the injected value is a one-time copy, though globals: { user: user } reads like it hands over the object.

Works today

define_function covers most of this, and a call site makes the crossing into Ruby explicit:

vm.define_function('a') { 1 }
vm.define_function('b') { 2 }
vm.eval_code('a() + b()')  #=> 3

vm.define_function('user') { user }   # returns go through the same converter
vm.eval_code('user().name')           #=> "Itadori", and stays live if you mutate `user`

For JS you don't control that expects the global to exist already, pin it once at setup and leave the JS untouched:

vm.eval_code('globalThis.user = user();')

The gap that leaves is one-shot Quickjs.eval_code, since there's no VM handle to define on. That's the case I want to design around.

I'm still doodling ideal APIs. I'll open a PR and link it here, feedback welcome when I do.

@hmsk hmsk added the enhancement New feature or request label Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants