Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed app/.gitkeep
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ export default class ComposerValidRoll extends Component {
.filter(Boolean);
rolls.forEach((roll) => {
try {
// TODO: Handle descriptions separately. parser won't be able to handle 2d20+4 // test
// see https://github.com/dice-roller/rpg-dice-roller/issues/287
rpgDiceRoller.Parser.parse(roll);
} catch (err) {
this.errors.push(err);
// eslint-disable-next-line no-console
console.warn("Rollmaster: Error parsing notation", roll, err);
}
});
});
Expand Down
63 changes: 62 additions & 1 deletion lib/rollmaster/dice_engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,81 @@ def self.roll(*diceRolls)
result
end

# Formats the notation of the dice rolls.
# Note: this does not actually reorder the dice rolls, it just formats them by removing
# whitespace and ensuring the notation is valid.
def self.format_notation(*diceRolls)
result = nil
protect do
context = v8
result = context.call("formatNotation", *diceRolls)
end
if result.is_a?(Hash) && result["type"] == "error"
raise Rollmaster::DiceEngine::RollError.new(result["msg"])
end
result
end

def self.attach_function(ctx)
ctx.eval <<~JS
function roll(...diceRolls) {
const roller = new rpgDiceRoller.DiceRoller;
try {
roller.roll(...diceRolls);
return JSON.parse(JSON.stringify(roller.log))
return roller.log.map((r) => {
const output = r.output;
const start = output.lastIndexOf(': ');
return output.substring(start + 2);
});
} catch (e) {
return {
type: "error",
name: e.name,
msg: e.message,
};
}
}

function formatNotation(...diceRolls) {
const parse = rpgDiceRoller.Parser.parse;
const formatted = [];
try {
diceRolls.forEach((notation) => {
const parsed = parse(notation);
formatted.push(format(parsed));
});
} catch (e) {
return {
type: "error",
name: e.name,
msg: e.message,
};
}
return formatted;
}

function format(expressions) {
removeDescription(expressions);
return expressions
.map((e) => {
if (typeof e === "string" || typeof e === "number") {
return e;
}
return e.notation;
})
.join("");
}

function removeDescription(exp) {
exp.forEach((e) => {
if (typeof e === "object" && e.description) {
e.description = null;
if (e.expressions) {
e.expressions.forEach((subExp) => removeDescription(subExp));
}
}
});
return exp;
}
JS
end
Expand Down
21 changes: 20 additions & 1 deletion spec/lib/rollmaster/dice_engine_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
expect(result).not_to be_nil
expect(result).to be_a(Array)
expect(result.size).to eq(dice_rolls.size)
expect(result.all? { |r| r.is_a?(Hash) }).to be(true)
expect(result.all? { |r| r.is_a?(String) }).to be(true)
end

it "raises a RollError for invalid dice rolls" do
Expand All @@ -33,6 +33,25 @@
end
end

describe ".format_notation" do
it "formats the notation of the dice rolls" do
dice_rolls = ["{3d8 * 2, 20 / 2d10, 2d10 - d4} // testing"]
formatted_result = described_class.format_notation(*dice_rolls)

expect(formatted_result).not_to be_nil
expect(formatted_result).to be_a(Array)
expect(formatted_result.first).to eq("{3d8*2, 20/2d10, 2d10-1d4}") # has stripped whitespace and comments
end

it "raises a RollError for invalid notation" do
dice_rolls = ["invalid_notation"]

expect { described_class.format_notation(*dice_rolls) }.to raise_error(
Rollmaster::DiceEngine::RollError,
)
end
end

describe ".reset_context" do
it "resets the V8 context" do
initial_context = described_class.v8
Expand Down