bag_of_holding 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +37 -0
- data/Rakefile +17 -0
- data/bin/boh +28 -0
- data/lib/bag_of_holding/dice/addition_operation.rb +18 -0
- data/lib/bag_of_holding/dice/constant.rb +23 -0
- data/lib/bag_of_holding/dice/constant_result.rb +27 -0
- data/lib/bag_of_holding/dice/die.rb +39 -0
- data/lib/bag_of_holding/dice/die_result.rb +26 -0
- data/lib/bag_of_holding/dice/die_roller.rb +51 -0
- data/lib/bag_of_holding/dice/die_validator.rb +23 -0
- data/lib/bag_of_holding/dice/division_operation.rb +18 -0
- data/lib/bag_of_holding/dice/multiplication_operation.rb +18 -0
- data/lib/bag_of_holding/dice/operation.rb +45 -0
- data/lib/bag_of_holding/dice/operation_result.rb +38 -0
- data/lib/bag_of_holding/dice/parser.rb +50 -0
- data/lib/bag_of_holding/dice/pool.rb +58 -0
- data/lib/bag_of_holding/dice/pool_factory.rb +70 -0
- data/lib/bag_of_holding/dice/pool_result.rb +37 -0
- data/lib/bag_of_holding/dice/subtraction_operation.rb +18 -0
- data/lib/bag_of_holding/dice/transform.rb +59 -0
- data/lib/bag_of_holding/dice.rb +41 -0
- data/lib/bag_of_holding.rb +1 -0
- data/spec/dice/addition_operation_spec.rb +23 -0
- data/spec/dice/constant_result_spec.rb +48 -0
- data/spec/dice/constant_spec.rb +31 -0
- data/spec/dice/die_result_spec.rb +70 -0
- data/spec/dice/die_roller_spec.rb +76 -0
- data/spec/dice/die_spec.rb +111 -0
- data/spec/dice/die_validator_spec.rb +34 -0
- data/spec/dice/division_operation_spec.rb +35 -0
- data/spec/dice/multiplication_operation_spec.rb +27 -0
- data/spec/dice/operation_result_spec.rb +64 -0
- data/spec/dice/operation_spec.rb +55 -0
- data/spec/dice/parser_spec.rb +215 -0
- data/spec/dice/pool_factory_spec.rb +71 -0
- data/spec/dice/pool_result_spec.rb +63 -0
- data/spec/dice/pool_spec.rb +126 -0
- data/spec/dice/subtraction_operation_spec.rb +27 -0
- data/spec/dice/transform_spec.rb +237 -0
- data/spec/spec_helper.rb +24 -0
- metadata +186 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DieRoller do
|
2
|
+
let(:die) { BagOfHolding::Dice::Die.new sides: 20, explode: 19, reroll: 2 }
|
3
|
+
subject { BagOfHolding::Dice::DieRoller.new die: die }
|
4
|
+
|
5
|
+
# Spec ::build
|
6
|
+
describe '::roll' do
|
7
|
+
it 'passes the argument to new' do
|
8
|
+
klass = BagOfHolding::Dice::DieRoller
|
9
|
+
die = double('Die', roll: true)
|
10
|
+
expect(klass).to receive(:new).with(die: die).and_return(subject)
|
11
|
+
klass.roll die
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#roll' do
|
16
|
+
context 'with no options' do
|
17
|
+
it 'returns the roll' do
|
18
|
+
allow(subject).to receive(:rng).and_return(5)
|
19
|
+
expect(subject.roll).to eq(
|
20
|
+
BagOfHolding::Dice::DieResult.new rolls: [5],
|
21
|
+
value: 5,
|
22
|
+
die: subject
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with rerolling die' do
|
28
|
+
it 're-rolls and adds a number larger if we are equal to the reroll' do
|
29
|
+
allow(subject).to receive(:rng).and_return(2, 3)
|
30
|
+
expect(subject.roll).to eq(
|
31
|
+
BagOfHolding::Dice::DieResult.new rolls: [2, 3],
|
32
|
+
value: 3,
|
33
|
+
die: subject
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 're-rolls and adds a number larger if we are less than the reroll' do
|
38
|
+
allow(subject).to receive(:rng).and_return(1, 5)
|
39
|
+
expect(subject.roll).to eq(
|
40
|
+
BagOfHolding::Dice::DieResult.new rolls: [1, 5],
|
41
|
+
value: 5,
|
42
|
+
die: subject
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with an exploding die' do
|
48
|
+
it 'accumulates and re-rolls if we are equal to the explode number' do
|
49
|
+
allow(subject).to receive(:rng).and_return(19, 3)
|
50
|
+
expect(subject.roll).to eq(
|
51
|
+
BagOfHolding::Dice::DieResult.new rolls: [19, 3],
|
52
|
+
value: 22,
|
53
|
+
die: subject
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'accumulates and re-rolls if we are greater than the explode number' do
|
58
|
+
allow(subject).to receive(:rng).and_return(20, 5)
|
59
|
+
expect(subject.roll).to eq(
|
60
|
+
BagOfHolding::Dice::DieResult.new rolls: [20, 5],
|
61
|
+
value: 25,
|
62
|
+
die: subject
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'accumulates and re-rolls if we continue to explode' do
|
67
|
+
allow(subject).to receive(:rng).and_return(20, 20, 4)
|
68
|
+
expect(subject.roll).to eq(
|
69
|
+
BagOfHolding::Dice::DieResult.new rolls: [20, 20, 4],
|
70
|
+
value: 44,
|
71
|
+
die: subject
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Die do
|
2
|
+
subject { BagOfHolding::Dice::Die.new sides: 20, explode: 19, reroll: 2 }
|
3
|
+
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'sets the attributes on the class' do
|
6
|
+
die = BagOfHolding::Dice::Die.new sides: 8, explode: 20, reroll: 1
|
7
|
+
expect(die.sides).to eq(8)
|
8
|
+
expect(die.explode).to eq(20)
|
9
|
+
expect(die.reroll).to eq(1)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#sides=' do
|
14
|
+
it 'sets the number of sides on the die' do
|
15
|
+
subject.sides = 100
|
16
|
+
expect(subject.sides).to eq(100)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#sides' do
|
21
|
+
it 'returns the number of sides on the die' do
|
22
|
+
expect(subject.sides).to eq(20)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#explode=' do
|
27
|
+
it 'sets the number of explode on the die' do
|
28
|
+
subject.explode = 15
|
29
|
+
expect(subject.explode).to eq(15)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#explode' do
|
34
|
+
it 'returns the number of explode on the die' do
|
35
|
+
expect(subject.explode).to eq(19)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#reroll=' do
|
40
|
+
it 'sets the number of reroll on the die' do
|
41
|
+
subject.reroll = 2
|
42
|
+
expect(subject.reroll).to eq(2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#reroll' do
|
47
|
+
it 'returns the number of reroll on the die' do
|
48
|
+
expect(subject.reroll).to eq(2)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#==' do
|
53
|
+
let(:other) do
|
54
|
+
BagOfHolding::Dice::Die.new sides: subject.sides,
|
55
|
+
explode: subject.explode,
|
56
|
+
reroll: subject.reroll
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns true for a die with the same attributes' do
|
60
|
+
expect(subject == other).to eq(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns false for a die with different sides' do
|
64
|
+
other.sides = 10_000
|
65
|
+
expect(subject == other).to eq(false)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns false for a die with different explode' do
|
69
|
+
other.explode = 1
|
70
|
+
expect(subject == other).to eq(false)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns false for a die with different reroll' do
|
74
|
+
other.reroll = 4
|
75
|
+
expect(subject == other).to eq(false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#valid?' do
|
80
|
+
it 'passes itself to DieValidator' do
|
81
|
+
allow(BagOfHolding::Dice::DieValidator).to(
|
82
|
+
receive(:valid?).and_return(true)
|
83
|
+
)
|
84
|
+
|
85
|
+
expect(subject.valid?).to eq(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns true with a valid die' do
|
89
|
+
expect(subject.valid?).to eq(true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#roll' do
|
94
|
+
context 'with an invalid die' do
|
95
|
+
before { subject.sides = nil }
|
96
|
+
|
97
|
+
it 'raises a StandardError' do
|
98
|
+
allow(subject).to receive(:valid?).and_return(false)
|
99
|
+
expect { subject.roll }.to raise_error(StandardError)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'passes itself to DieRoller' do
|
104
|
+
result = BagOfHolding::Dice::DieResult.new rolls: [5],
|
105
|
+
value: 5,
|
106
|
+
die: subject
|
107
|
+
allow(BagOfHolding::Dice::DieRoller).to receive(:roll).and_return(result)
|
108
|
+
expect(subject.roll).to eq(result)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DieValidator do
|
2
|
+
let(:die) { BagOfHolding::Dice::Die.new sides: 20 }
|
3
|
+
subject { BagOfHolding::Dice::DieValidator.new die: die }
|
4
|
+
|
5
|
+
context 'with a reroll higher than explode' do
|
6
|
+
before do
|
7
|
+
die.explode = 10
|
8
|
+
die.reroll = 11
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns false' do
|
12
|
+
expect(subject.valid?).to eq(false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with an explode equal to reroll' do
|
17
|
+
before do
|
18
|
+
die.explode = 10
|
19
|
+
die.reroll = 10
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns false' do
|
23
|
+
expect(subject.valid?).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with no sides set' do
|
28
|
+
before { die.sides = nil }
|
29
|
+
|
30
|
+
it 'returns false' do
|
31
|
+
expect(subject.valid?).to eq(false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DivisionOperation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 4 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 2 }
|
4
|
+
|
5
|
+
subject do
|
6
|
+
BagOfHolding::Dice::DivisionOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '::operator' do
|
11
|
+
it 'returns /' do
|
12
|
+
expect(BagOfHolding::Dice::DivisionOperation.operator).to eq('/')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#value' do
|
17
|
+
it 'subtracts the right value from the left' do
|
18
|
+
expect(subject.value).to eq(2)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'rounds down any values' do
|
22
|
+
BagOfHolding::Dice::Constant.new value: 5
|
23
|
+
BagOfHolding::Dice::Constant.new value: 2
|
24
|
+
op = BagOfHolding::Dice::DivisionOperation.new left: left,
|
25
|
+
right: right
|
26
|
+
expect(op.value).to eq(2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#operator' do
|
31
|
+
it 'returns /' do
|
32
|
+
expect(subject.operator).to eq('/')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::MultiplicationOperation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 4 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 2 }
|
4
|
+
|
5
|
+
subject do
|
6
|
+
BagOfHolding::Dice::MultiplicationOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '::operator' do
|
11
|
+
it 'returns *' do
|
12
|
+
expect(BagOfHolding::Dice::MultiplicationOperation.operator).to eq('*')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#value' do
|
17
|
+
it 'subtracts the right value from the left' do
|
18
|
+
expect(subject.value).to eq(8)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#operator' do
|
23
|
+
it 'returns *' do
|
24
|
+
expect(subject.operator).to eq('*')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::OperationResult do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 3 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 5 }
|
4
|
+
|
5
|
+
let(:operation) do
|
6
|
+
BagOfHolding::Dice::AdditionOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
subject do
|
11
|
+
BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
12
|
+
operation: operation,
|
13
|
+
right_result: right.roll,
|
14
|
+
value: 8
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#initialize' do
|
18
|
+
it 'assigns the attributes that are passed' do
|
19
|
+
result = BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
20
|
+
operation: operation,
|
21
|
+
right_result: right.roll,
|
22
|
+
value: 8
|
23
|
+
expect(result.left_result).to eq(left.roll)
|
24
|
+
expect(result.operation).to eq(operation)
|
25
|
+
expect(result.right_result).to eq(right.roll)
|
26
|
+
expect(result.value).to eq(8)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#to_s' do
|
31
|
+
it 'returns a string with the left result, operator and right result' do
|
32
|
+
expect(subject.to_s).to eq('3 + 5')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#inspect' do
|
37
|
+
it 'returns the inspected left and right results and operator' do
|
38
|
+
expect(subject.to_s).to eq('3 + 5')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#==' do
|
43
|
+
let(:other) do
|
44
|
+
BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
45
|
+
operation: operation,
|
46
|
+
right_result: right.roll,
|
47
|
+
value: 8
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns true when other has matching attributes' do
|
51
|
+
expect(subject == other).to eq(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns false with a different left_result' do
|
55
|
+
other.left_result = right.roll
|
56
|
+
expect(subject == other).to eq(false)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns false with a different right_result' do
|
60
|
+
other.right_result = left.roll
|
61
|
+
expect(subject == other).to eq(false)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Operation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 3 }
|
3
|
+
let(:operator) { '+' }
|
4
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 5 }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
BagOfHolding::Dice::Operation.new left: left,
|
8
|
+
right: right
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it 'sets the attributes passed' do
|
13
|
+
op = BagOfHolding::Dice::Operation.new left: left,
|
14
|
+
right: right
|
15
|
+
expect(op.left).to eq(left)
|
16
|
+
expect(op.right).to eq(right)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#roll' do
|
21
|
+
it 'returns an OperationResult' do
|
22
|
+
allow(subject).to receive(:value).and_return(8)
|
23
|
+
|
24
|
+
expect(subject.roll).to eq(
|
25
|
+
BagOfHolding::Dice::OperationResult.new(
|
26
|
+
left_result: left.roll,
|
27
|
+
right_result: right.roll,
|
28
|
+
operation: subject,
|
29
|
+
value: 8
|
30
|
+
)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#==' do
|
36
|
+
let(:other) do
|
37
|
+
BagOfHolding::Dice::Operation.new left: left,
|
38
|
+
right: right
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns true when matching attributes' do
|
42
|
+
expect(subject == other).to eq(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns false with a different left' do
|
46
|
+
other.left = BagOfHolding::Dice::Constant.new value: 30
|
47
|
+
expect(subject == other).to eq(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns false with a different right' do
|
51
|
+
other.left = BagOfHolding::Dice::Constant.new value: 40
|
52
|
+
expect(subject == other).to eq(false)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Parser do
|
2
|
+
subject { BagOfHolding::Dice::Parser.new }
|
3
|
+
|
4
|
+
describe '#parse' do
|
5
|
+
it 'parses 5' do
|
6
|
+
tree = subject.parse '5'
|
7
|
+
expect(tree).to match(
|
8
|
+
[constant: '5']
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'parses 1d20' do
|
13
|
+
tree = subject.parse '1d20'
|
14
|
+
expect(tree).to match([
|
15
|
+
{ count: '1', die: [{ sides: '20' }] }
|
16
|
+
])
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'parses 2d20k' do
|
20
|
+
tree = subject.parse '2d20k'
|
21
|
+
expect(tree).to match([
|
22
|
+
{ count: '2', die: [{ sides: '20' }, { keep: nil }] }
|
23
|
+
])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'parses 3d20k2' do
|
27
|
+
tree = subject.parse '3d20k2'
|
28
|
+
expect(tree).to match([
|
29
|
+
{ count: '3', die: [{ sides: '20' }, { keep: '2' }] }
|
30
|
+
])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'parses 1d20,1d8' do
|
34
|
+
tree = subject.parse '1d20,1d8'
|
35
|
+
expect(tree).to match(
|
36
|
+
[
|
37
|
+
{ count: '1', die: [{ sides: '20' }] },
|
38
|
+
{ count: '1', die: [{ sides: '8' }] }
|
39
|
+
]
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'parses d20' do
|
44
|
+
tree = subject.parse 'd20'
|
45
|
+
expect(tree).to match([
|
46
|
+
die: [{ sides: '20' }]
|
47
|
+
])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'parses 3d8 (Attack)' do
|
51
|
+
tree = subject.parse '3d8 (Attack)'
|
52
|
+
expect(tree).to match([
|
53
|
+
{ count: '3', die: [{ sides: '8' }], label: 'Attack' }
|
54
|
+
])
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'parses 1d20r' do
|
58
|
+
tree = subject.parse '1d20r'
|
59
|
+
expect(tree).to match([
|
60
|
+
{ count: '1', die: [{ sides: '20' }, { reroll: nil }] }
|
61
|
+
])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'parses 5+6' do
|
65
|
+
tree = subject.parse '5+6'
|
66
|
+
expect(tree).to match([
|
67
|
+
{ left: { constant: '5' }, operator: '+', right: { constant: '6' } }
|
68
|
+
])
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'parses 5-2' do
|
72
|
+
tree = subject.parse '5-2'
|
73
|
+
expect(tree).to match([
|
74
|
+
{ left: { constant: '5' }, operator: '-', right: { constant: '2' } }
|
75
|
+
])
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'parses 4/2' do
|
79
|
+
tree = subject.parse '4/2'
|
80
|
+
expect(tree).to match([
|
81
|
+
{ left: { constant: '4' }, operator: '/', right: { constant: '2' } }
|
82
|
+
])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'parses 4*2' do
|
86
|
+
tree = subject.parse '4*2'
|
87
|
+
expect(tree).to match([
|
88
|
+
{ left: { constant: '4' }, operator: '*', right: { constant: '2' } }
|
89
|
+
])
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'parses 8, 9' do
|
93
|
+
tree = subject.parse '8, 9'
|
94
|
+
expect(tree).to match([
|
95
|
+
{ constant: '8' },
|
96
|
+
{ constant: '9' }
|
97
|
+
])
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'parses 1 + 2, 3' do
|
101
|
+
tree = subject.parse('1 + 2, 3')
|
102
|
+
expect(tree).to match([
|
103
|
+
{ left: { constant: '1' }, operator: '+', right: { constant: '2' } },
|
104
|
+
{ constant: '3' }
|
105
|
+
])
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'parses 1d20r (Defense)' do
|
109
|
+
tree = subject.parse('1d20r (Defense)')
|
110
|
+
expect(tree).to match([
|
111
|
+
{
|
112
|
+
count: '1',
|
113
|
+
die: [
|
114
|
+
{ sides: '20' },
|
115
|
+
{ reroll: nil }
|
116
|
+
],
|
117
|
+
label: 'Defense' }
|
118
|
+
])
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'parses 1d20r2' do
|
122
|
+
tree = subject.parse('1d20r2')
|
123
|
+
expect(tree).to match([
|
124
|
+
{ count: '1', die: [{ sides: '20' }, { reroll: '2' }] }
|
125
|
+
])
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'parses 1d20e' do
|
129
|
+
tree = subject.parse('1d20e')
|
130
|
+
expect(tree).to match([
|
131
|
+
{ count: '1', die: [{ sides: '20' }, { explode: nil }] }
|
132
|
+
])
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'parses 1d20e18' do
|
136
|
+
tree = subject.parse('1d20e18')
|
137
|
+
expect(tree).to match([
|
138
|
+
{ count: '1', die: [{ sides: '20' }, { explode: '18' }] }
|
139
|
+
])
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'parses 1d20e18r2' do
|
143
|
+
tree = subject.parse('1d20e18r2')
|
144
|
+
expect(tree).to match([
|
145
|
+
{
|
146
|
+
count: '1',
|
147
|
+
die: [
|
148
|
+
{ sides: '20' },
|
149
|
+
{ explode: '18' },
|
150
|
+
{ reroll: '2' }
|
151
|
+
]
|
152
|
+
}
|
153
|
+
])
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'parses 1d20r2e18' do
|
157
|
+
tree = subject.parse('1d20r2e18')
|
158
|
+
expect(tree).to match([
|
159
|
+
{
|
160
|
+
count: '1',
|
161
|
+
die: [
|
162
|
+
{ sides: '20' },
|
163
|
+
{ reroll: '2' },
|
164
|
+
{ explode: '18' }
|
165
|
+
]
|
166
|
+
}
|
167
|
+
])
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'parses 1d20 + 5' do
|
171
|
+
tree = subject.parse('1d20 + 5')
|
172
|
+
expect(tree).to match([
|
173
|
+
{
|
174
|
+
left: {
|
175
|
+
count: '1',
|
176
|
+
die: [
|
177
|
+
{ sides: '20' }
|
178
|
+
]
|
179
|
+
},
|
180
|
+
operator: '+',
|
181
|
+
right: {
|
182
|
+
constant: '5'
|
183
|
+
}
|
184
|
+
}
|
185
|
+
])
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'parses 2d6+ 1d4 + 2' do
|
189
|
+
tree = subject.parse('2d6+ 1d4 + 2')
|
190
|
+
expect(tree).to match([
|
191
|
+
{
|
192
|
+
left: {
|
193
|
+
count: '2',
|
194
|
+
die: [
|
195
|
+
{ sides: '6' }
|
196
|
+
]
|
197
|
+
},
|
198
|
+
operator: '+',
|
199
|
+
right: {
|
200
|
+
left: {
|
201
|
+
count: '1',
|
202
|
+
die: [
|
203
|
+
{ sides: '4' }
|
204
|
+
]
|
205
|
+
},
|
206
|
+
operator: '+',
|
207
|
+
right: {
|
208
|
+
constant: '2'
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|