tablescript 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rubocop.yml +9 -0
  4. data/Gemfile +20 -0
  5. data/README.md +55 -44
  6. data/Rakefile +27 -3
  7. data/examples/namespaces.rb +33 -0
  8. data/examples/wandering_monsters.rb +15 -0
  9. data/lib/tablescript.rb +22 -66
  10. data/lib/tablescript/api.rb +50 -0
  11. data/lib/tablescript/exception.rb +24 -0
  12. data/lib/tablescript/library.rb +44 -0
  13. data/lib/tablescript/library_dumper.rb +42 -0
  14. data/lib/tablescript/lookup_strategy.rb +41 -0
  15. data/lib/tablescript/namespace.rb +85 -0
  16. data/lib/tablescript/namespace_generator.rb +20 -0
  17. data/lib/tablescript/roll_and_ignore_duplicates_strategy.rb +69 -0
  18. data/lib/tablescript/roll_and_ignore_strategy.rb +49 -0
  19. data/lib/tablescript/roll_context.rb +51 -0
  20. data/lib/tablescript/roll_strategy.rb +48 -0
  21. data/lib/tablescript/table.rb +54 -32
  22. data/lib/tablescript/table_entries.rb +66 -0
  23. data/lib/tablescript/table_entry.rb +18 -14
  24. data/lib/tablescript/version.rb +8 -8
  25. data/spec/spec_helper.rb +4 -0
  26. data/spec/tablescript/api_spec.rb +66 -0
  27. data/spec/tablescript/library_spec.rb +13 -0
  28. data/spec/tablescript/lookup_strategy_spec.rb +35 -0
  29. data/spec/tablescript/namespace_spec.rb +25 -0
  30. data/spec/tablescript/roll_and_ignore_strategy_spec.rb +57 -0
  31. data/spec/tablescript/roll_strategy_spec.rb +56 -0
  32. data/spec/tablescript/table_entry_spec.rb +42 -0
  33. data/spec/tablescript/table_spec.rb +88 -0
  34. data/spec/tablescript_spec.rb +7 -0
  35. data/tablescript.gemspec +26 -20
  36. metadata +112 -5
  37. data/lib/tablescript/dice_roller.rb +0 -94
  38. data/lib/tablescript/roll_descriptor.rb +0 -55
  39. data/lib/tablescript/table_entry_environment.rb +0 -124
@@ -1,53 +1,75 @@
1
- # Copyright 2015 Jamie Hale
1
+ # Copyright 2017 Jamie Hale
2
2
  #
3
- # This file is part of the Tablescript.rb gem.
3
+ # This file is part of the Tablescript gem.
4
4
  #
5
- # Tablescript.rb is free software: you can redistribute it and/or modify
5
+ # Tablescript is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
7
7
  # the Free Software Foundation, either version 3 of the License, or
8
8
  # (at your option) any later version.
9
9
  #
10
- # Tablescript.rb is distributed in the hope that it will be useful,
10
+ # Tablescript is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
14
  #
15
15
  # You should have received a copy of the GNU General Public License
16
- # along with Foobar. If not, see <http://www.gnu.org/licenses/>.
17
-
18
- module TableScript
19
-
16
+ # along with Tablescript. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Tablescript
19
+ ##
20
+ # Table
21
+ #
20
22
  class Table
21
-
22
- attr_reader :entries
23
-
24
- def initialize( name, roller )
23
+ attr_reader :name, :entries
24
+
25
+ def initialize(name, namespace, &blk)
25
26
  @name = name
26
- @roller = roller
27
- @entries = nil
27
+ @namespace = namespace
28
+ @entries = TableEntries.new
29
+ instance_eval(&blk)
28
30
  end
29
-
30
- def build( &blk )
31
- @entries = TableEntryEnvironment.new( @name, @roller )
32
- @entries.instance_eval( &blk )
31
+
32
+ def f(roll = nil, &blk)
33
+ @entries.add_fixed(roll, &blk)
33
34
  end
34
-
35
- def random_entry
36
- @roller.rollD( @entries.die_to_roll )
35
+
36
+ def d(count = 1, &blk)
37
+ @entries.add_dynamic(count, &blk)
37
38
  end
38
-
39
- def lookup( index )
40
- @entries.lookup( index )
39
+
40
+ def lookup(roll)
41
+ @entries.lookup(roll).evaluate(roll, self)
41
42
  end
42
-
43
- def roll
44
- @entries.reroll
43
+
44
+ def lookup_on(path, roll)
45
+ LookupStrategy.new(resolve(path.to_s), roll).value
45
46
  end
46
-
47
- def roll_and_ignore_duplicates( times, args )
48
- @entries.reroll_and_ignore_duplicates( times, args )
47
+
48
+ def dice_to_roll
49
+ "d#{@entries.size}"
49
50
  end
50
-
51
- end
52
51
 
52
+ def roll_on(path)
53
+ RollStrategy.new(resolve(path.to_s)).value
54
+ end
55
+
56
+ def roll_on_and_ignore(path, *args)
57
+ RollAndIgnoreStrategy.new(resolve(path.to_s), RpgLib::RollSet.new(*args)).value
58
+ end
59
+
60
+ def roll_on_and_ignore_duplicates(path, times)
61
+ RollAndIgnoreDuplicatesStrategy.new(resolve(path.to_s), times).value
62
+ end
63
+
64
+ private
65
+
66
+ def resolve(path)
67
+ namespace = @namespace
68
+ until namespace.nil?
69
+ return namespace.resolve(path) if namespace.resolve?(path)
70
+ namespace = namespace.parent
71
+ end
72
+ raise Exception, "No such table #{path}"
73
+ end
74
+ end
53
75
  end
@@ -0,0 +1,66 @@
1
+ module Tablescript
2
+ ##
3
+ # TableEntries
4
+ #
5
+ class TableEntries
6
+ def initialize
7
+ @entries = []
8
+ @next_id = 0
9
+ end
10
+
11
+ def size
12
+ @entries.size
13
+ end
14
+
15
+ def entry(index)
16
+ @entries[index]
17
+ end
18
+
19
+ def lookup(roll)
20
+ entry(roll - 1)
21
+ end
22
+
23
+ def add_fixed(roll, &blk)
24
+ if roll.nil?
25
+ add_entry(blk)
26
+ elsif roll.is_a?(Integer)
27
+ set_entry(roll, blk)
28
+ elsif roll.is_a?(Range)
29
+ set_range(roll, blk)
30
+ else
31
+ raise Exception, "Unrecognized parameter type (#{roll.class}) for fixed roll definition"
32
+ end
33
+ end
34
+
35
+ def add_dynamic(count, &blk)
36
+ range = next_single_roll..(next_single_roll + count - 1)
37
+ entry = TableEntry.new(next_id, range, blk)
38
+ count.times { @entries << entry }
39
+ end
40
+
41
+ private
42
+
43
+ def next_id
44
+ id = @next_id
45
+ @next_id += 1
46
+ id
47
+ end
48
+
49
+ def next_single_roll
50
+ @entries.size + 1
51
+ end
52
+
53
+ def add_entry(blk)
54
+ @entries << TableEntry.new(next_id, next_single_roll, blk)
55
+ end
56
+
57
+ def set_entry(roll, blk)
58
+ @entries[roll - 1] = TableEntry.new(next_id, roll, blk)
59
+ end
60
+
61
+ def set_range(range, blk)
62
+ entry = TableEntry.new(next_id, range, blk)
63
+ range.each { |r| @entries[r - 1] = entry }
64
+ end
65
+ end
66
+ end
@@ -1,31 +1,35 @@
1
- # Copyright 2015 Jamie Hale
1
+ # Copyright 2017 Jamie Hale
2
2
  #
3
- # This file is part of the Tablescript.rb gem.
3
+ # This file is part of the Tablescript gem.
4
4
  #
5
- # Tablescript.rb is free software: you can redistribute it and/or modify
5
+ # Tablescript is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
7
7
  # the Free Software Foundation, either version 3 of the License, or
8
8
  # (at your option) any later version.
9
9
  #
10
- # Tablescript.rb is distributed in the hope that it will be useful,
10
+ # Tablescript is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
14
  #
15
15
  # You should have received a copy of the GNU General Public License
16
- # along with Foobar. If not, see <http://www.gnu.org/licenses/>.
17
-
18
- module TableScript
19
-
16
+ # along with Tablescript. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Tablescript
19
+ ##
20
+ # TableEntry
21
+ #
20
22
  class TableEntry
21
-
22
- def initialize( blk )
23
+ attr_reader :id, :roll, :blk
24
+
25
+ def initialize(id, roll, blk)
26
+ @id = id
27
+ @roll = roll
23
28
  @blk = blk
24
29
  end
25
-
26
- def evaluate( roll )
27
- @blk.call( roll )
30
+
31
+ def evaluate(roll, table)
32
+ table.instance_exec(RollContext.new(roll, table, self), &@blk)
28
33
  end
29
34
  end
30
-
31
35
  end
@@ -1,20 +1,20 @@
1
- # Copyright 2015 Jamie Hale
1
+ # Copyright 2017 Jamie Hale
2
2
  #
3
- # This file is part of the Tablescript.rb gem.
3
+ # This file is part of the Tablescript gem.
4
4
  #
5
- # Tablescript.rb is free software: you can redistribute it and/or modify
5
+ # Tablescript is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
7
7
  # the Free Software Foundation, either version 3 of the License, or
8
8
  # (at your option) any later version.
9
9
  #
10
- # Tablescript.rb is distributed in the hope that it will be useful,
10
+ # Tablescript is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
14
  #
15
15
  # You should have received a copy of the GNU General Public License
16
- # along with Foobar. If not, see <http://www.gnu.org/licenses/>.
17
-
18
- module TableScript
19
- VERSION = "0.0.4"
16
+ # along with Tablescript. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Tablescript
19
+ VERSION = '1.0.0'.freeze
20
20
  end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ require 'tablescript'
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ module Tablescript
4
+ describe Api do
5
+ let(:api) { Class.new { include Api }.new }
6
+
7
+ describe 'table' do
8
+ end
9
+
10
+ describe 'rolling' do
11
+ let(:values) { %w(red green blue) }
12
+
13
+ before(:each) do
14
+ Library.instance = Library.new
15
+ api.table :colours do
16
+ f { 'red' }
17
+ f { 'green' }
18
+ f { 'blue' }
19
+ end
20
+ end
21
+
22
+ describe 'roll_on' do
23
+ it 'rolls on the table' do
24
+ 10.times do
25
+ expect(values).to include(api.roll_on(:colours))
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'roll_on_and_ignore' do
31
+ it 'rolls on the table and ignores certain rolls' do
32
+ 10.times do
33
+ expect(%w(red blue)).to include(api.roll_on_and_ignore(:colours, 2))
34
+ end
35
+ end
36
+ end
37
+
38
+ describe 'roll_on_and_ignore_duplicates' do
39
+ before(:each) do
40
+ @results = []
41
+ 10.times do
42
+ @results << api.roll_on_and_ignore_duplicates(:colours, 2)
43
+ end
44
+ end
45
+
46
+ it 'returns the expected number of results' do
47
+ @results.each do |roll_results|
48
+ expect(roll_results.size).to eq(2)
49
+ end
50
+ end
51
+
52
+ it 'ignores duplicate rolls' do
53
+ @results.each do |roll_results|
54
+ expect(roll_results[0]).not_to eq(roll_results[1])
55
+ end
56
+ end
57
+ end
58
+
59
+ describe 'lookup' do
60
+ it 'returns the specified entry' do
61
+ expect(api.lookup(:colours, 2)).to eq('green')
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module Tablescript
4
+ describe Library do
5
+ it 'is a singleton' do
6
+ expect { Library.instance }.not_to raise_error
7
+ end
8
+
9
+ it 'knows its root namespace' do
10
+ expect(Library.instance.root).to be_a(Namespace)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ module Tablescript
4
+ describe LookupStrategy do
5
+ it 'can be created' do
6
+ expect { LookupStrategy.new(:table, :roll) }.not_to raise_error
7
+ end
8
+
9
+ describe 'value' do
10
+ let(:table) { double('table') }
11
+ let(:roll) { 6 }
12
+ let(:value) { 'Vorpal sword' }
13
+ let(:strategy) { LookupStrategy.new(table, roll) }
14
+
15
+ before(:each) do
16
+ allow(table).to receive(:evaluate) { value }
17
+ @value = strategy.value
18
+ end
19
+
20
+ it 'defers to the table' do
21
+ expect(table).to have_received(:evaluate).with(roll)
22
+ end
23
+
24
+ it 'provides the tables result' do
25
+ expect(@value).to eq(value)
26
+ end
27
+
28
+ it 'does not evaluate twice' do
29
+ strategy.value
30
+ strategy.value
31
+ expect(table).to have_received(:evaluate).once
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module Tablescript
2
+ describe Namespace do
3
+ describe 'add' do
4
+ let(:table) { double('table', name: :table) }
5
+ let(:namespace) { Namespace.new }
6
+
7
+ it 'knows it has added table' do
8
+ namespace.add(table)
9
+ expect(namespace.table?(:table)).to be true
10
+ end
11
+
12
+ it 'retrieves the table' do
13
+ namespace.add(table)
14
+ expect(namespace.table(:table)).to eq(table)
15
+ end
16
+
17
+ describe 'duplicates' do
18
+ it 'throws when trying to add a duplicate' do
19
+ namespace.add(table)
20
+ expect { namespace.add(table) }.to raise_error(Exception)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ module Tablescript
4
+ describe RollAndIgnoreStrategy do
5
+ it 'can be created' do
6
+ expect { RollAndIgnoreStrategy.new(:table, :rollset) }.not_to raise_error
7
+ end
8
+
9
+ describe 'evaluate' do
10
+ let(:dice) { 'd20' }
11
+ let(:table) { double('table', dice_to_roll: dice) }
12
+ let(:rollset) { double('rollset') }
13
+ let(:roll) { 6 }
14
+ let(:value) { 'Vorpal sword' }
15
+ let(:roller) { RpgLib::DiceRoller.clone.instance }
16
+ let(:strategy) { RollAndIgnoreStrategy.new(table, rollset, roller) }
17
+
18
+ before(:each) do
19
+ allow(roller).to receive(:roll_and_ignore) { roll }
20
+ allow(table).to receive(:evaluate) { value }
21
+ @value = strategy.value
22
+ end
23
+
24
+ it 'defers to the roller' do
25
+ expect(roller).to have_received(:roll_and_ignore).with(dice, rollset)
26
+ end
27
+
28
+ it 'defers to the table' do
29
+ expect(table).to have_received(:evaluate).with(roll)
30
+ end
31
+
32
+ describe 'value' do
33
+ it 'provides the tables result' do
34
+ expect(@value).to eq(value)
35
+ end
36
+
37
+ it 'only evaluates once' do
38
+ strategy.value
39
+ strategy.value
40
+ expect(table).to have_received(:evaluate).once
41
+ end
42
+ end
43
+
44
+ describe 'roll' do
45
+ it 'knows its roll' do
46
+ expect(strategy.roll).to eq(roll)
47
+ end
48
+
49
+ it 'only evaluates once' do
50
+ strategy.roll
51
+ strategy.roll
52
+ expect(table).to have_received(:evaluate).once
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end