rpg_lib 1.0.0 → 1.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.
@@ -0,0 +1,29 @@
1
+ module RpgLib
2
+ module Parser
3
+ ##
4
+ # DiceParser
5
+ #
6
+ class DiceParser
7
+ attr_reader :parser
8
+
9
+ def initialize
10
+ @parser = DiceExpressionParser.new
11
+ @cache = {}
12
+ end
13
+
14
+ def parse(dice)
15
+ return @cache[dice] if @cache.key?(dice)
16
+ parse_new_dice(dice)
17
+ end
18
+
19
+ private
20
+
21
+ def parse_new_dice(dice)
22
+ tree = @parser.parse(dice)
23
+ raise Exception, "Parse error #{@parser.failure_reason} at offset: #{@parser.index}" if tree.nil?
24
+ @cache[dice] = tree
25
+ tree
26
+ end
27
+ end
28
+ end
29
+ end
@@ -16,5 +16,5 @@
16
16
  # along with RpgLib. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  module RpgLib
19
- VERSION = '1.0.0'.freeze
19
+ VERSION = '1.0.1'.freeze
20
20
  end
data/rpg_lib.gemspec CHANGED
@@ -35,6 +35,8 @@ Gem::Specification.new do |spec|
35
35
  spec.files = `git ls-files -z`.split("\x0")
36
36
  spec.require_paths = ['lib']
37
37
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
38
+
39
+ spec.add_dependency 'treetop', '~> 1.6'
38
40
  spec.add_development_dependency 'bundler', '~> 1.14'
39
41
  spec.add_development_dependency 'rake', '~> 12.0'
40
42
  spec.add_development_dependency 'rspec', '~> 3.5'
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module RpgLib
4
+ describe Api do
5
+ let(:api) { Class.new { include Api }.new }
6
+
7
+ describe 'roll' do
8
+ it 'returns Integer' do
9
+ expect(api.roll('3d6')).to be_instance_of(Integer)
10
+ end
11
+
12
+ it 'responds in the specified range' do
13
+ 20.times do
14
+ roll = api.roll('3d6')
15
+ expect(roll < 3).to be false
16
+ expect(roll > 18).to be false
17
+ end
18
+ end
19
+ end
20
+
21
+ describe 'roll_and_ignore' do
22
+ it 'returns Integer' do
23
+ expect(api.roll_and_ignore('3d6', 5)).to be_instance_of(Integer)
24
+ end
25
+
26
+ it 'response in the specified range' do
27
+ 20.times do
28
+ roll = api.roll_and_ignore('3d6', 5)
29
+ expect(roll < 3).to be false
30
+ expect(roll > 18).to be false
31
+ end
32
+ end
33
+
34
+ it 'ignores a passed number' do
35
+ 20.times do
36
+ roll = api.roll_and_ignore('3d6', 5)
37
+ expect(roll).not_to eq(5)
38
+ end
39
+ end
40
+
41
+ it 'ignores a passed range' do
42
+ 20.times do
43
+ roll = api.roll_and_ignore('3d6', 6..10)
44
+ expect(6..10).not_to include(roll)
45
+ end
46
+ end
47
+
48
+ it 'ignores a passed roll set' do
49
+ evens = RollSet.new(4, 6, 8, 10, 12, 14, 16, 18)
50
+ 20.times do
51
+ roll = api.roll_and_ignore('3d6', evens)
52
+ expect(roll).to be_odd
53
+ end
54
+ end
55
+ end
56
+
57
+ describe 'choose' do
58
+ let(:values) { [:foo, :bar, :baz, :stoo] }
59
+
60
+ it 'selects a single item from the list' do
61
+ 10.times do
62
+ expect(values).to include(api.choose(values))
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ module RpgLib
4
+ describe DiceRoller do
5
+ let(:roller) { DiceRoller.clone.instance }
6
+ let(:die_roller) { roller.roller }
7
+
8
+ it 'can be accessed' do
9
+ expect { DiceRoller.instance }.not_to raise_error
10
+ end
11
+
12
+ describe 'roll_die' do
13
+ before(:each) do
14
+ allow(die_roller).to receive(:roll) { 3 }
15
+ @value = roller.roll_die(6)
16
+ end
17
+
18
+ it 'defers to the roller' do
19
+ expect(die_roller).to have_received(:roll).with(6)
20
+ end
21
+
22
+ it 'relays the result' do
23
+ expect(@value).to eq(3)
24
+ end
25
+ end
26
+
27
+ describe 'roll' do
28
+ let(:parser) { roller.parser }
29
+ let(:tree) { double('tree') }
30
+
31
+ before(:each) do
32
+ allow(parser).to receive(:parse) { tree }
33
+ allow(tree).to receive(:eval) { 9 }
34
+ @value = roller.roll('3d6')
35
+ end
36
+
37
+ it 'defers to the parser' do
38
+ expect(parser).to have_received(:parse).with('3d6')
39
+ end
40
+
41
+ it 'evals the result from the parser' do
42
+ expect(tree).to have_received(:eval).with(die_roller)
43
+ end
44
+
45
+ it 'relays the result of eval' do
46
+ expect(@value).to eq(9)
47
+ end
48
+ end
49
+
50
+ describe 'roll_and_ignore' do
51
+ describe 'with no collision' do
52
+ before(:each) do
53
+ allow(roller).to receive(:roll) { 4 }
54
+ @value = roller.roll_and_ignore('d6', RollSet.new(0, 9, 100))
55
+ end
56
+
57
+ it 'rolls only once' do
58
+ expect(roller).to have_received(:roll).with('d6').once
59
+ end
60
+
61
+ it 'relays the roll' do
62
+ expect(@value).to eq(4)
63
+ end
64
+ end
65
+
66
+ describe 'with collisions' do
67
+ before(:each) do
68
+ allow(roller).to receive(:roll).and_return(1, 2, 3, 4)
69
+ @value = roller.roll_and_ignore('d6', RollSet.new(1..3))
70
+ end
71
+
72
+ it 'rolls multiple times until it finds a value that is not ignored' do
73
+ expect(roller).to have_received(:roll).exactly(4).times
74
+ end
75
+
76
+ it 'relays the roll' do
77
+ expect(@value).to eq(4)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module RpgLib
4
+ describe DieRoller do
5
+ it 'can be created' do
6
+ expect { DieRoller.new }.not_to raise_error
7
+ end
8
+
9
+ describe 'roll' do
10
+ let(:generator) { double('generator') }
11
+ let(:value) { 99 }
12
+ let(:roller) { DieRoller.new(generator) }
13
+
14
+ before(:each) do
15
+ allow(generator).to receive(:rand) { value }
16
+ @result = roller.roll(10)
17
+ end
18
+
19
+ it 'defers to the generator' do
20
+ expect(generator).to have_received(:rand).with(1..10)
21
+ end
22
+
23
+ it 'relays the generated value' do
24
+ expect(@result).to eq(value)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module RpgLib
4
+ module Parser
5
+ module DiceExpression
6
+ describe BinaryOperation do
7
+ it 'is touched when we parse a dice descriptor with an operator' do
8
+ expect(RpgLib::Parser::DiceParser.new.parse('3+4').eval(nil)).to eq(7)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ module RpgLib
4
+ module Parser
5
+ describe DiceParser do
6
+ it 'can be created' do
7
+ expect { DiceParser.new }.not_to raise_error
8
+ end
9
+
10
+ describe 'parse' do
11
+ let(:parser) { DiceParser.new }
12
+ let(:treetop) { parser.parser }
13
+ let(:tree) { double('tree') }
14
+
15
+ before(:each) do
16
+ allow(treetop).to receive(:parse) { tree }
17
+ end
18
+
19
+ describe 'uncached' do
20
+ before(:each) do
21
+ @value = parser.parse('3d6')
22
+ end
23
+
24
+ it 'defers to the treetop parser' do
25
+ expect(treetop).to have_received(:parse).with('3d6')
26
+ end
27
+
28
+ it 'relays the parsed tree' do
29
+ expect(@value).to eq(tree)
30
+ end
31
+ end
32
+
33
+ describe 'cached' do
34
+ before(:each) do
35
+ parser.parse('3d6')
36
+ parser.parse('3d6')
37
+ @value = parser.parse('3d6')
38
+ end
39
+
40
+ it 'uses the cached value' do
41
+ expect(treetop).to have_received(:parse).once
42
+ end
43
+
44
+ it 'relays the cached value' do
45
+ expect(@value).to eq(tree)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpg_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Hale
@@ -10,6 +10,20 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2015-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: treetop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -92,14 +106,23 @@ files:
92
106
  - Gemfile
93
107
  - Gemfile.lock
94
108
  - Rakefile
109
+ - grammar/dice_expression.treetop
95
110
  - lib/rpg_lib.rb
96
111
  - lib/rpg_lib/api.rb
97
112
  - lib/rpg_lib/dice_roller.rb
98
- - lib/rpg_lib/roll_descriptor.rb
113
+ - lib/rpg_lib/die_roller.rb
114
+ - lib/rpg_lib/parser/dice_expression_nodes.rb
115
+ - lib/rpg_lib/parser/dice_expression_parser.rb
116
+ - lib/rpg_lib/parser/dice_parser.rb
99
117
  - lib/rpg_lib/roll_set.rb
100
118
  - lib/rpg_lib/string.rb
101
119
  - lib/rpg_lib/version.rb
102
120
  - rpg_lib.gemspec
121
+ - spec/rpg_lib/api_spec.rb
122
+ - spec/rpg_lib/dice_roller_spec.rb
123
+ - spec/rpg_lib/die_roller_spec.rb
124
+ - spec/rpg_lib/parser/dice_expression_nodes_spec.rb
125
+ - spec/rpg_lib/parser/dice_parser_spec.rb
103
126
  - spec/rpg_lib/roll_set_spec.rb
104
127
  - spec/rpg_lib/string_spec.rb
105
128
  - spec/rpg_lib_spec.rb
@@ -1,54 +0,0 @@
1
- # Copyright 2017 Jamie Hale
2
- #
3
- # This file is part of the RpgLib gem.
4
- #
5
- # RpgLib is free software: you can redistribute it and/or modify
6
- # it under the terms of the GNU General Public License as published by
7
- # the Free Software Foundation, either version 3 of the License, or
8
- # (at your option) any later version.
9
- #
10
- # RpgLib is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- # GNU General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU General Public License
16
- # along with RpgLib. If not, see <http://www.gnu.org/licenses/>.
17
-
18
- module RpgLib
19
- ##
20
- # RollDescriptor
21
- #
22
- class RollDescriptor
23
- attr_reader :die, :count, :drop_lowest, :drop_highest
24
-
25
- def initialize(match)
26
- initialize_die(match)
27
- initialize_count(match)
28
- initialize_dropped_dice(match)
29
- end
30
-
31
- private
32
-
33
- def initialize_die(match)
34
- @die = match[2].to_i
35
- end
36
-
37
- def initialize_count(match)
38
- @count = 1
39
- @count = match[1].to_i unless match[1].empty?
40
- end
41
-
42
- def initialize_dropped_dice(match)
43
- @drop_lowest = 0
44
- @drop_highest = 0
45
- if match[4] == 'dl'
46
- @drop_lowest = 1
47
- @drop_lowest = match[5].to_i unless match[5].empty?
48
- elsif match[6] == 'dh'
49
- @drop_highest = 1
50
- @drop_highest = match[7].to_i unless match[7].empty?
51
- end
52
- end
53
- end
54
- end