Skip to content

Commit dcb2623

Browse files
committed
Pass customBundleGemfile from Ruby to VersionManager
Instead of having both Ruby and VersionManager independently read, expand, and resolve the bundleGemfile setting, Ruby now passes the resolved value down to VersionManager through the constructor.
1 parent 3e216b8 commit dcb2623

7 files changed

Lines changed: 83 additions & 81 deletions

File tree

vscode/src/common.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,6 @@ export const FEATURE_FLAGS = {
8888

8989
type FeatureFlagConfigurationKey = keyof typeof FEATURE_FLAGS | "all";
9090

91-
// Expands VS Code predefined variables (e.g., `${workspaceFolder}`) in a configuration string, since VS Code does not
92-
// automatically expand variables in extension settings retrieved via `getConfiguration()`
93-
export function expandPath(value: string, workspaceFolder: vscode.WorkspaceFolder): string {
94-
return value.replace(/\$\{workspaceFolder\}/g, workspaceFolder.uri.fsPath);
95-
}
96-
9791
// Creates a debounced version of a function with the specified delay. If the function is invoked before the delay runs
9892
// out, then the previous invocation of the function gets cancelled and a new one is scheduled.
9993
//

vscode/src/ruby.ts

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import os from "os";
33

44
import * as vscode from "vscode";
55

6-
import { asyncExec, expandPath, RubyInterface } from "./common";
6+
import { asyncExec, RubyInterface } from "./common";
77
import { WorkspaceChannel } from "./workspaceChannel";
88
import { Shadowenv, UntrustedWorkspaceError } from "./ruby/shadowenv";
99
import { Chruby } from "./ruby/chruby";
@@ -84,12 +84,10 @@ export class Ruby implements RubyInterface {
8484
this.telemetry = telemetry;
8585

8686
const rawBundleGemfile: string = vscode.workspace.getConfiguration("rubyLsp").get("bundleGemfile")!;
87-
const customBundleGemfile = expandPath(rawBundleGemfile, this.workspaceFolder);
87+
const customBundleGemfile = rawBundleGemfile.replace(/\$\{workspaceFolder\}/g, this.workspaceFolder.uri.fsPath);
8888

8989
if (customBundleGemfile.length > 0) {
90-
this.customBundleGemfile = path.isAbsolute(customBundleGemfile)
91-
? customBundleGemfile
92-
: path.resolve(path.join(this.workspaceFolder.uri.fsPath, customBundleGemfile));
90+
this.customBundleGemfile = path.resolve(this.workspaceFolder.uri.fsPath, customBundleGemfile);
9391
}
9492
}
9593

@@ -140,6 +138,7 @@ export class Ruby implements RubyInterface {
140138
this.context,
141139
this.manuallySelectRuby.bind(this),
142140
workspaceRubyPath,
141+
this.customBundleGemfile,
143142
),
144143
);
145144
} else {
@@ -174,6 +173,7 @@ export class Ruby implements RubyInterface {
174173
this.context,
175174
this.manuallySelectRuby.bind(this),
176175
globalRubyPath,
176+
this.customBundleGemfile,
177177
),
178178
);
179179
} else {
@@ -297,56 +297,54 @@ export class Ruby implements RubyInterface {
297297
}
298298

299299
private async runManagerActivation() {
300+
const manuallySelectRuby = this.manuallySelectRuby.bind(this);
301+
const args = [
302+
this.workspaceFolder,
303+
this.outputChannel,
304+
this.context,
305+
manuallySelectRuby,
306+
this.customBundleGemfile,
307+
] as const;
308+
300309
switch (this.versionManager.identifier) {
301310
case ManagerIdentifier.Asdf:
302-
await this.runActivation(
303-
new Asdf(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
304-
);
311+
await this.runActivation(new Asdf(...args));
305312
break;
306313
case ManagerIdentifier.Chruby:
307-
await this.runActivation(
308-
new Chruby(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
309-
);
314+
await this.runActivation(new Chruby(...args));
310315
break;
311316
case ManagerIdentifier.Rbenv:
312-
await this.runActivation(
313-
new Rbenv(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
314-
);
317+
await this.runActivation(new Rbenv(...args));
315318
break;
316319
case ManagerIdentifier.Rvm:
317-
await this.runActivation(
318-
new Rvm(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
319-
);
320+
await this.runActivation(new Rvm(...args));
320321
break;
321322
case ManagerIdentifier.Mise:
322-
await this.runActivation(
323-
new Mise(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
324-
);
323+
await this.runActivation(new Mise(...args));
325324
break;
326325
case ManagerIdentifier.Rv:
327-
await this.runActivation(
328-
new Rv(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
329-
);
326+
await this.runActivation(new Rv(...args));
330327
break;
331328
case ManagerIdentifier.RubyInstaller:
332-
await this.runActivation(
333-
new RubyInstaller(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
334-
);
329+
await this.runActivation(new RubyInstaller(...args));
335330
break;
336331
case ManagerIdentifier.Custom:
337-
await this.runActivation(
338-
new Custom(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
339-
);
332+
await this.runActivation(new Custom(...args));
340333
break;
341334
case ManagerIdentifier.None:
342335
await this.runActivation(
343-
new None(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
336+
new None(
337+
this.workspaceFolder,
338+
this.outputChannel,
339+
this.context,
340+
manuallySelectRuby,
341+
undefined,
342+
this.customBundleGemfile,
343+
),
344344
);
345345
break;
346346
default:
347-
await this.runActivation(
348-
new Shadowenv(this.workspaceFolder, this.outputChannel, this.context, this.manuallySelectRuby.bind(this)),
349-
);
347+
await this.runActivation(new Shadowenv(...args));
350348
break;
351349
}
352350
}

vscode/src/ruby/chruby.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export class Chruby extends VersionManager {
2828
outputChannel: WorkspaceChannel,
2929
context: vscode.ExtensionContext,
3030
manuallySelectRuby: () => Promise<void>,
31+
customBundleGemfile?: string,
3132
) {
32-
super(workspaceFolder, outputChannel, context, manuallySelectRuby);
33+
super(workspaceFolder, outputChannel, context, manuallySelectRuby, customBundleGemfile);
3334

3435
const configuredRubies = vscode.workspace
3536
.getConfiguration("rubyLsp")

vscode/src/ruby/none.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ export class None extends VersionManager {
2121
context: vscode.ExtensionContext,
2222
manuallySelectRuby: () => Promise<void>,
2323
rubyPath?: string,
24+
customBundleGemfile?: string,
2425
) {
25-
super(workspaceFolder, outputChannel, context, manuallySelectRuby);
26+
super(workspaceFolder, outputChannel, context, manuallySelectRuby, customBundleGemfile);
2627
this.rubyPath = rubyPath ?? "ruby";
2728
}
2829

vscode/src/ruby/versionManager.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import os from "os";
44
import * as vscode from "vscode";
55

66
import { WorkspaceChannel } from "../workspaceChannel";
7-
import { asyncExec, expandPath } from "../common";
7+
import { asyncExec } from "../common";
88

99
export interface ActivationResult {
1010
env: NodeJS.ProcessEnv;
@@ -31,19 +31,13 @@ export abstract class VersionManager {
3131
outputChannel: WorkspaceChannel,
3232
context: vscode.ExtensionContext,
3333
manuallySelectRuby: () => Promise<void>,
34+
customBundleGemfile?: string,
3435
) {
3536
this.workspaceFolder = workspaceFolder;
3637
this.outputChannel = outputChannel;
3738
this.context = context;
3839
this.manuallySelectRuby = manuallySelectRuby;
39-
const rawBundleGemfile: string = vscode.workspace.getConfiguration("rubyLsp").get("bundleGemfile")!;
40-
const customBundleGemfile = expandPath(rawBundleGemfile, this.workspaceFolder);
41-
42-
if (customBundleGemfile.length > 0) {
43-
this.customBundleGemfile = path.isAbsolute(customBundleGemfile)
44-
? customBundleGemfile
45-
: path.resolve(path.join(this.workspaceFolder.uri.fsPath, customBundleGemfile));
46-
}
40+
this.customBundleGemfile = customBundleGemfile;
4741

4842
this.bundleUri = this.customBundleGemfile
4943
? vscode.Uri.file(path.dirname(this.customBundleGemfile))

vscode/src/test/suite/common.test.ts

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,7 @@ import * as assert from "assert";
33
import * as vscode from "vscode";
44
import sinon from "sinon";
55

6-
import { expandPath, featureEnabled, FEATURE_FLAGS } from "../../common";
7-
8-
suite("expandPath", () => {
9-
const workspaceFolder: vscode.WorkspaceFolder = {
10-
uri: vscode.Uri.file("/home/user/project"),
11-
name: "project",
12-
index: 0,
13-
};
14-
15-
// eslint-disable-next-line no-template-curly-in-string
16-
test("replaces ${workspaceFolder} with the workspace folder path", () => {
17-
// eslint-disable-next-line no-template-curly-in-string
18-
const result = expandPath("${workspaceFolder}/Gemfile", workspaceFolder);
19-
assert.strictEqual(result, "/home/user/project/Gemfile");
20-
});
21-
22-
// eslint-disable-next-line no-template-curly-in-string
23-
test("replaces multiple occurrences of ${workspaceFolder}", () => {
24-
// eslint-disable-next-line no-template-curly-in-string
25-
const result = expandPath("${workspaceFolder}/a:${workspaceFolder}/b", workspaceFolder);
26-
assert.strictEqual(result, "/home/user/project/a:/home/user/project/b");
27-
});
28-
29-
test("returns the string unchanged when there is no variable", () => {
30-
assert.strictEqual(expandPath("Gemfile", workspaceFolder), "Gemfile");
31-
});
32-
33-
test("returns empty string unchanged", () => {
34-
assert.strictEqual(expandPath("", workspaceFolder), "");
35-
});
36-
});
6+
import { featureEnabled, FEATURE_FLAGS } from "../../common";
377

388
suite("featureEnabled", () => {
399
let sandbox: sinon.SinonSandbox;

vscode/src/test/suite/ruby.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,50 @@ suite("Ruby environment activation", () => {
172172
assert.strictEqual(context.workspaceState.get(`rubyLsp.workspaceRubyPath.${workspaceFolder.name}`), undefined);
173173
});
174174

175+
// eslint-disable-next-line no-template-curly-in-string
176+
test("Expands ${workspaceFolder} in bundleGemfile setting", async () => {
177+
const tmpPath = fs.mkdtempSync(path.join(os.tmpdir(), "ruby-lsp-test-"));
178+
const gemfilePath = path.resolve(tmpPath, "Gemfile");
179+
fs.writeFileSync(gemfilePath, "");
180+
181+
const tmpWorkspaceFolder: vscode.WorkspaceFolder = {
182+
uri: vscode.Uri.file(tmpPath),
183+
name: path.basename(tmpPath),
184+
index: 0,
185+
};
186+
187+
sandbox.stub(vscode.workspace, "getConfiguration").returns({
188+
get: (name: string) => {
189+
if (name === "rubyVersionManager") {
190+
return { identifier: ManagerIdentifier.None };
191+
} else if (name === "bundleGemfile") {
192+
// eslint-disable-next-line no-template-curly-in-string
193+
return "${workspaceFolder}/Gemfile";
194+
}
195+
196+
return undefined;
197+
},
198+
} as unknown as vscode.WorkspaceConfiguration);
199+
200+
const envStub = [
201+
"3.3.5",
202+
"~/.gem/ruby/3.3.5,/opt/rubies/3.3.5/lib/ruby/gems/3.3.0",
203+
"true",
204+
`ANY${VALUE_SEPARATOR}true`,
205+
].join(FIELD_SEPARATOR);
206+
207+
sandbox.stub(common, "asyncExec").resolves({
208+
stdout: "",
209+
stderr: `${ACTIVATION_SEPARATOR}${envStub}${ACTIVATION_SEPARATOR}`,
210+
});
211+
212+
const ruby = new Ruby(context, tmpWorkspaceFolder, outputChannel, FAKE_TELEMETRY);
213+
await ruby.activateRuby();
214+
215+
assert.strictEqual(ruby.env.BUNDLE_GEMFILE, gemfilePath);
216+
fs.rmSync(tmpPath, { recursive: true, force: true });
217+
});
218+
175219
test("Raises an error if the configured bundleGemfile does not exist", async () => {
176220
const tmpPath = fs.mkdtempSync(path.join(os.tmpdir(), "ruby-lsp-test-"));
177221
const tmpWorkspaceFolder: vscode.WorkspaceFolder = {

0 commit comments

Comments
 (0)