mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:47:44 +00:00
Spreadsheet: Improve R function to support all of the examples
This commit is contained in:
parent
93115ee044
commit
12ef20b869
2 changed files with 76 additions and 17 deletions
|
@ -277,10 +277,13 @@ class Range {
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
const endingRow = this.endingRow ?? "";
|
const endingRow = this.endingRow ?? "";
|
||||||
return `R\`${this.startingColumnName}${this.startingRow}:${this.endingColumnName}${endingRow}:${this.columnStep}:${this.rowStep}\``;
|
const showSteps = this.rowStep !== 1 || this.columnStep !== 1;
|
||||||
|
const steps = showSteps ? `:${this.columnStep}:${this.rowStep}` : "";
|
||||||
|
return `R\`${this.startingColumnName}${this.startingRow}:${this.endingColumnName}${endingRow}${steps}\``;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const R_FORMAT = /^([a-zA-Z_]+)(?:(\d+):([a-zA-Z_]+)(\d+)?(?::(\d+):(\d+))?)?$/;
|
||||||
function R(fmt, ...args) {
|
function R(fmt, ...args) {
|
||||||
if (args.length !== 0) throw new TypeError("R`` format must be a literal");
|
if (args.length !== 0) throw new TypeError("R`` format must be a literal");
|
||||||
// done because:
|
// done because:
|
||||||
|
@ -288,23 +291,20 @@ function R(fmt, ...args) {
|
||||||
// myFunc("ABC") => ""ABC""
|
// myFunc("ABC") => ""ABC""
|
||||||
// myFunc`ABC` => "["ABC"]"
|
// myFunc`ABC` => "["ABC"]"
|
||||||
if (Array.isArray(fmt)) fmt = fmt[0];
|
if (Array.isArray(fmt)) fmt = fmt[0];
|
||||||
const parts = fmt.split(":");
|
if (!R_FORMAT.test(fmt))
|
||||||
if (parts.length !== 2 && parts.length !== 4)
|
throw new Error("Invalid Format. Expected Format: R`A` or R`A0:A1` or R`A0:A2:1:2`");
|
||||||
throw new Error("Invalid Format. Expected Format: R`A0:A1` or R`A0:A2:1:2`");
|
// Format: Col(Row:Col(Row)?(:ColStep:RowStep)?)?
|
||||||
// ColRow:Col(Row)?(:ColStep:RowStep)?
|
// Ignore the first element of the match array as that will be the whole match.
|
||||||
const start = thisSheet.parse_cell_name(parts[0]);
|
const [, ...matches] = fmt.match(R_FORMAT);
|
||||||
let end = parts[1];
|
const [startCol, startRow, endCol, endRow, colStep, rowStep] = matches;
|
||||||
if (/^[a-zA-Z_]+$/.test(end)) end = { column: end, row: undefined };
|
|
||||||
else end = thisSheet.parse_cell_name(parts[1]);
|
|
||||||
parts[2] ??= 1;
|
|
||||||
parts[3] ??= 1;
|
|
||||||
return new Range(
|
return new Range(
|
||||||
start.column,
|
startCol,
|
||||||
end.column,
|
endCol ?? startCol,
|
||||||
start.row,
|
integer(startRow ?? 0),
|
||||||
end.row,
|
// Don't make undefined an integer, because then it becomes 0.
|
||||||
integer(parts[2]),
|
!!endRow ? integer(endRow) : endRow,
|
||||||
integer(parts[3])
|
integer(colStep ?? 1),
|
||||||
|
integer(rowStep ?? 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,3 +145,62 @@ describe("Range", () => {
|
||||||
).toEqual("<Cell at A0>,<Cell at A1>,<Cell at A2>,<Cell at B0>,<Cell at B1>,<Cell at B2>");
|
).toEqual("<Cell at A0>,<Cell at A1>,<Cell at A2>,<Cell at B0>,<Cell at B1>,<Cell at B2>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("R function", () => {
|
||||||
|
const workbook = createWorkbook();
|
||||||
|
const sheet = createSheet(workbook, "Sheet 1");
|
||||||
|
sheet.makeCurrent();
|
||||||
|
/*
|
||||||
|
A B
|
||||||
|
+++
|
||||||
|
0+1 1
|
||||||
|
1+2 4
|
||||||
|
2+3 9
|
||||||
|
*/
|
||||||
|
for (const row of ["A", "B"]) {
|
||||||
|
for (let col of [0, 1, 2]) {
|
||||||
|
sheet.setCell(row, col++, row === "A" ? col : Math.pow(col, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sheet.focusCell("A", 0);
|
||||||
|
|
||||||
|
test("Check for correctness: R`A0:A`", () => {
|
||||||
|
const range = R`A0:A`;
|
||||||
|
expect(range.toString()).toEqual("R`A0:A`");
|
||||||
|
expect(count(range)).toEqual(3);
|
||||||
|
expect(sum(range)).toEqual(6);
|
||||||
|
});
|
||||||
|
test("Check for correctness: R`A`", () => {
|
||||||
|
const range = R`A`;
|
||||||
|
expect(range.toString()).toEqual("R`A0:A`");
|
||||||
|
expect(count(range)).toEqual(3);
|
||||||
|
expect(sum(range)).toEqual(6);
|
||||||
|
});
|
||||||
|
test("Check for correctness: R`A0:B`", () => {
|
||||||
|
const range = R`A0:B`;
|
||||||
|
expect(range.toString()).toEqual("R`A0:B`");
|
||||||
|
expect(count(range)).toEqual(6);
|
||||||
|
expect(sum(range)).toEqual(20);
|
||||||
|
});
|
||||||
|
test("Check for correctness: R`A0:B0`", () => {
|
||||||
|
const range = R`A0:B0`;
|
||||||
|
expect(range.toString()).toEqual("R`A0:B0`");
|
||||||
|
expect(count(range)).toEqual(2);
|
||||||
|
expect(sum(range)).toEqual(2);
|
||||||
|
});
|
||||||
|
test("Check for correctness: R`A0:B:2:1`", () => {
|
||||||
|
const range = R`A0:B2:1:2`;
|
||||||
|
expect(range.toString()).toEqual("R`A0:B2:1:2`");
|
||||||
|
expect(range.toArray().toString()).toEqual(
|
||||||
|
"<Cell at A0>,<Cell at A2>,<Cell at B0>,<Cell at B2>"
|
||||||
|
);
|
||||||
|
expect(count(range)).toEqual(4);
|
||||||
|
expect(sum(range)).toEqual(14);
|
||||||
|
});
|
||||||
|
test("R`B`", () => {
|
||||||
|
const range = R`B`;
|
||||||
|
expect(range.toString()).toEqual("R`B0:B`");
|
||||||
|
expect(count(range)).toEqual(3);
|
||||||
|
expect(sum(range)).toEqual(14);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue