Skip to content

Commit 3db2a3a

Browse files
committed
Add min notation formatter
1 parent bde69a0 commit 3db2a3a

4 files changed

Lines changed: 102 additions & 2 deletions

File tree

app/.gitkeep

Whitespace-only changes.

assets/javascripts/discourse/components/composer-valid-roll.gjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,13 @@ export default class ComposerValidRoll extends Component {
9494
.filter(Boolean);
9595
rolls.forEach((roll) => {
9696
try {
97+
// TODO: Handle descriptions separately. parser won't be able to handle 2d20+4 // test
98+
// see https://github.com/dice-roller/rpg-dice-roller/issues/287
9799
rpgDiceRoller.Parser.parse(roll);
98100
} catch (err) {
99101
this.errors.push(err);
102+
// eslint-disable-next-line no-console
103+
console.warn("Rollmaster: Error parsing notation", roll, err);
100104
}
101105
});
102106
});

lib/rollmaster/dice_engine.rb

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,81 @@ def self.roll(*diceRolls)
2929
result
3030
end
3131

32+
# Formats the notation of the dice rolls.
33+
# Note: this does not actually reorder the dice rolls, it just formats them by removing
34+
# whitespace and ensuring the notation is valid.
35+
def self.format_notation(*diceRolls)
36+
result = nil
37+
protect do
38+
context = v8
39+
result = context.call("formatNotation", *diceRolls)
40+
end
41+
if result.is_a?(Hash) && result["type"] == "error"
42+
raise Rollmaster::DiceEngine::RollError.new(result["msg"])
43+
end
44+
result
45+
end
46+
3247
def self.attach_function(ctx)
3348
ctx.eval <<~JS
3449
function roll(...diceRolls) {
3550
const roller = new rpgDiceRoller.DiceRoller;
3651
try {
3752
roller.roll(...diceRolls);
38-
return JSON.parse(JSON.stringify(roller.log))
53+
return roller.log.map((r) => {
54+
const output = r.output;
55+
const start = output.lastIndexOf(': ');
56+
return output.substring(start + 2);
57+
});
58+
} catch (e) {
59+
return {
60+
type: "error",
61+
name: e.name,
62+
msg: e.message,
63+
};
64+
}
65+
}
66+
67+
function formatNotation(...diceRolls) {
68+
const parse = rpgDiceRoller.Parser.parse;
69+
const formatted = [];
70+
try {
71+
diceRolls.forEach((notation) => {
72+
const parsed = parse(notation);
73+
formatted.push(format(parsed));
74+
});
3975
} catch (e) {
4076
return {
4177
type: "error",
4278
name: e.name,
4379
msg: e.message,
4480
};
4581
}
82+
return formatted;
83+
}
84+
85+
function format(expressions) {
86+
removeDescription(expressions);
87+
return expressions
88+
.map((e) => {
89+
if (typeof e === "string" || typeof e === "number") {
90+
return e;
91+
}
92+
return e.notation;
93+
})
94+
.join("");
95+
}
96+
97+
function removeDescription(exp) {
98+
exp.forEach((e) => {
99+
if (typeof e === "object" && e.description) {
100+
e.description = null;
101+
if (e.expressions) {
102+
e.expressions.forEach((subExp) => removeDescription(subExp));
103+
}
104+
}
105+
});
106+
return exp;
46107
}
47108
JS
48109
end

spec/lib/rollmaster/dice_engine_spec.rb

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
expect(result).not_to be_nil
1212
expect(result).to be_a(Array)
1313
expect(result.size).to eq(dice_rolls.size)
14-
expect(result.all? { |r| r.is_a?(Hash) }).to be(true)
14+
expect(result.all? { |r| r.is_a?(String) }).to be(true)
1515
end
1616

1717
it "raises a RollError for invalid dice rolls" do
@@ -33,6 +33,41 @@
3333
end
3434
end
3535

36+
describe ".format_notation" do
37+
it "formats the notation of the dice rolls" do
38+
dice_rolls = ["{3d8 * 2, 20 / 2d10, 2d10 - d4} // testing"]
39+
formatted_result = described_class.format_notation(*dice_rolls)
40+
41+
expect(formatted_result).not_to be_nil
42+
expect(formatted_result).to be_a(String)
43+
expect(formatted_result).to eq("{3d8*2, 20/2d10, 2d10-1d4}") # has stripped whitespace and comments
44+
end
45+
46+
it "raises a RollError for invalid notation" do
47+
dice_rolls = ["invalid_notation"]
48+
49+
expect { described_class.format_notation(*dice_rolls) }.to raise_error(
50+
Rollmaster::DiceEngine::RollError,
51+
)
52+
end
53+
54+
it "raises a RollError for empty notation" do
55+
dice_rolls = []
56+
57+
expect { described_class.format_notation(*dice_rolls) }.to raise_error(
58+
Rollmaster::DiceEngine::RollError,
59+
)
60+
end
61+
62+
it "raises a RollError for nil notation" do
63+
dice_rolls = nil
64+
65+
expect { described_class.format_notation(*dice_rolls) }.to raise_error(
66+
Rollmaster::DiceEngine::RollError,
67+
)
68+
end
69+
end
70+
3671
describe ".reset_context" do
3772
it "resets the V8 context" do
3873
initial_context = described_class.v8

0 commit comments

Comments
 (0)