Skip to content

Commit bba92bd

Browse files
committed
ruby runtimeのエラーを修正, wasip1指定を消しdefaultrubyvmに変更
1 parent e0eaed0 commit bba92bd

3 files changed

Lines changed: 192 additions & 170 deletions

File tree

app/terminal/ruby/runtime.tsx

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function useRuby(): RuntimeContext {
2727
type MessageToWorker =
2828
| {
2929
type: "init";
30-
payload: { RUBY_WASM_URL: string };
30+
payload: {};
3131
}
3232
| {
3333
type: "runRuby";
@@ -90,13 +90,9 @@ export function RubyProvider({ children }: { children: ReactNode }) {
9090
}
9191
};
9292

93-
// Use CDN URL for Ruby WASM with stdlib
94-
const RUBY_WASM_URL =
95-
"https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.2/dist/ruby+stdlib.wasm";
96-
9793
return postMessage<InitPayloadFromWorker>({
9894
type: "init",
99-
payload: { RUBY_WASM_URL },
95+
payload: {},
10096
});
10197
}, []);
10298

@@ -112,32 +108,39 @@ export function RubyProvider({ children }: { children: ReactNode }) {
112108
};
113109
}, [initializeWorker]);
114110

115-
const interrupt = useCallback(async () => {
111+
const interrupt = useCallback(() => {
116112
// Terminate the current worker
117113
if (workerRef.current) {
118114
workerRef.current.terminate();
119115
}
120116

117+
// reject all pending messages
118+
for (const [, [, reject]] of messageCallbacks.current) {
119+
reject("Execution interrupted");
120+
}
121+
121122
// Mark as not ready during reinitialization
122123
setReady(false);
123124

124-
// Reinitialize the worker
125-
const { success } = await initializeWorker();
126-
127-
if (success) {
128-
// Re-execute all saved commands to restore state
129-
for (const cmd of commandHistory.current) {
130-
try {
131-
await postMessage<RunPayloadFromWorker>({
132-
type: "runRuby",
133-
payload: { code: cmd },
134-
});
135-
} catch (e) {
136-
console.error("Error restoring command:", cmd, e);
125+
void mutex.current.runExclusive(async () => {
126+
// Reinitialize the worker
127+
const { success } = await initializeWorker();
128+
129+
if (success) {
130+
// Re-execute all saved commands to restore state
131+
for (const cmd of commandHistory.current) {
132+
try {
133+
await postMessage<RunPayloadFromWorker>({
134+
type: "runRuby",
135+
payload: { code: cmd },
136+
});
137+
} catch (e) {
138+
console.error("Error restoring command:", cmd, e);
139+
}
137140
}
141+
setReady(true);
138142
}
139-
setReady(true);
140-
}
143+
});
141144
}, [initializeWorker]);
142145

143146
const runCommand = useCallback(
@@ -152,15 +155,22 @@ export function RubyProvider({ children }: { children: ReactNode }) {
152155
const { output, updatedFiles } = await postMessage<RunPayloadFromWorker>({
153156
type: "runRuby",
154157
payload: { code },
158+
}).catch((error) => {
159+
return {
160+
output: [
161+
{ type: "error", message: `Execution error: ${error}` },
162+
] as ReplOutput[],
163+
updatedFiles: [] as [string, string][],
164+
};
155165
});
156-
166+
157167
// Check if the command succeeded (no errors)
158168
const hasError = output.some((o) => o.type === "error");
159169
if (!hasError) {
160170
// Save successful command to history
161171
commandHistory.current.push(code);
162172
}
163-
173+
164174
for (const [name, content] of updatedFiles) {
165175
writeFile(name, content);
166176
}
@@ -201,6 +211,13 @@ export function RubyProvider({ children }: { children: ReactNode }) {
201211
await postMessage<RunPayloadFromWorker>({
202212
type: "runFile",
203213
payload: { name: filenames[0], files },
214+
}).catch((error) => {
215+
return {
216+
output: [
217+
{ type: "error", message: `Execution error: ${error}` },
218+
] as ReplOutput[],
219+
updatedFiles: [] as [string, string][],
220+
};
204221
});
205222
for (const [newName, content] of updatedFiles) {
206223
writeFile(newName, content);

app/terminal/tests.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function defineTests(
1212
(
1313
{
1414
python: 2000,
15-
ruby: 2000,
15+
ruby: 5000,
1616
cpp: 10000,
1717
} as Record<RuntimeLang, number>
1818
)[lang]
@@ -110,17 +110,26 @@ export function defineTests(
110110
if (!setIntVarCode || !infLoopCode || !printIntVarCode) {
111111
this.skip();
112112
}
113-
const result = await (
113+
const runPromise = (
114114
runtimeRef.current[lang].mutex || emptyMutex
115115
).runExclusive(async () => {
116116
await runtimeRef.current[lang].runCommand!(setIntVarCode);
117-
const runPromise = runtimeRef.current[lang].runCommand!(infLoopCode);
118-
// Wait a bit to ensure the infinite loop has started
119-
await new Promise((resolve) => setTimeout(resolve, 1000));
120-
runtimeRef.current[lang].interrupt!();
121-
await runPromise;
122-
return runtimeRef.current[lang].runCommand!(printIntVarCode);
117+
return runtimeRef.current[lang].runCommand!(infLoopCode);
123118
});
119+
// Wait a bit to ensure the infinite loop has started
120+
await new Promise((resolve) => setTimeout(resolve, 1000));
121+
runtimeRef.current[lang].interrupt!();
122+
await new Promise((resolve) => setTimeout(resolve, 100));
123+
await runPromise;
124+
while (!runtimeRef.current[lang].ready) {
125+
await new Promise((resolve) => setTimeout(resolve, 100));
126+
}
127+
await new Promise((resolve) => setTimeout(resolve, 100));
128+
const result = await (
129+
runtimeRef.current[lang].mutex || emptyMutex
130+
).runExclusive(() =>
131+
runtimeRef.current[lang].runCommand!(printIntVarCode)
132+
);
124133
console.log(`${lang} REPL interrupt recovery test: `, result);
125134
expect(result).to.be.deep.equal([
126135
{

0 commit comments

Comments
 (0)