├── LICENSE
├── README.md
├── Rakefile
├── lib
├── rpg_tools.rb
└── rpg_tools
│ ├── coin.rb
│ ├── dice.rb
│ ├── dice
│ ├── bag.rb
│ ├── base.rb
│ ├── fudge.rb
│ ├── numerical.rb
│ ├── percentile.rb
│ └── utils
│ │ ├── modifier_calculator.rb
│ │ └── parser.rb
│ └── playing_card_deck.rb
├── rpg_tools.gemspec
└── spec
├── coin_spec.rb
├── dice
├── bag_spec.rb
├── base_spec.rb
├── fudge_spec.rb
├── numerical_spec.rb
├── percentile_spec.rb
└── utils
│ ├── modifier_calculator_spec.rb
│ └── parser_spec.rb
├── playing_card_deck_spec.rb
└── spec_helper.rb
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Yohan Piron
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | rpg_tools [](https://gemnasium.com/Yinfei/rpg_tools) 
2 | =======
3 |
4 | A gem that gives you tools for your RPGs : dices, coins and playing cards !
5 |
6 | ## Usage
7 |
8 | ### Coins
9 |
10 | `RpgTools::Coin.new`
11 |
12 | * The `flip` method set its value to a `heads` or `tails` string.
13 |
14 | ### Dices
15 |
16 | `RpgTools.roll_dice(arg)` (`arg` is case insensitive).
17 |
18 | This returns a plain integer result based on the `arg` parameter.
19 |
20 | * It can be a stardard dice like `"1dX"` for a X sided dice.
21 |
22 | * It can be a fudge dice `"df"` : a three sided dice (-1, 0, +1).
23 |
24 | * It can also be a percentile dice `"d%"` : a ten sided dice (from 10 to 100).
25 |
26 | You can also add multiple chained modifiers like "+X", "-X", "*X" or "/X", to alter the roll result. `RpgTools.roll_dice("4d6+2")` will create 4 6-sided dices, roll them and add 2 to the sum of the roll result.
27 |
28 | You can also manipulate all those dice types as objects :
29 |
30 | * `RpgTools::Dice::Numerical`
31 | * `RpgTools::Dice::Fudge`
32 | * `RpgTools::Dice::Percentile`
33 |
34 | All those classes take two args: a mandatory side number and an optional modifier.
35 | They respond to the `.roll` or `.roll!` methods to update their `value` to the result of the roll.
36 |
37 | `RpgTools::Dice::Numerical.new(6, '+4').roll` will roll a six sided dice and add 4 to the roll result.
38 |
39 | ### Dice Bags
40 |
41 | `RpgTools::Dice::Bag.new(arg)` (`arg` is case insensitive).
42 |
43 | * It works the same way `RpgTools.roll_dice` does but will give you a `RpgTools::Dice::Bag` object instead of a plain integer. `RpgTools::Dice::Bag.new("4d6-2")` will create a bag of four 6 sided dices with a -2 modifier to the sum of all rolls.
44 |
45 | ### Playing card deck
46 | `RpgTools::PlayingCardDeck.new(arg)` (`arg` can only be 32 or 52).
47 |
48 | * The `card` method returns a card of a 32 or 52 cards deck + 2 jokers, depending
49 | of `arg` value.
50 | * The `hand` method return an array of 5 `card` calls.
51 |
52 | ## Contributing
53 |
54 | 1. Fork it
55 | 2. Create your feature branch (`git checkout -b my-new-feature`)
56 | 3. Commit your changes (`git commit -am 'Added some feature'`)
57 | 4. Push to the branch (`git push origin my-new-feature`)
58 | 5. Create new Pull Request
59 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rspec/core/rake_task'
2 |
3 | RSpec::Core::RakeTask.new('spec')
4 |
--------------------------------------------------------------------------------
/lib/rpg_tools.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools/coin'
2 | require 'rpg_tools/dice'
3 | require 'rpg_tools/playing_card_deck'
4 |
5 | module RpgTools
6 | def roll_dice(dice)
7 | Dice::Bag.new(dice).roll
8 | end
9 | module_function :roll_dice
10 | end
11 |
--------------------------------------------------------------------------------
/lib/rpg_tools/coin.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | class Coin
3 | attr_accessor :value, :flips, :heads, :tails
4 |
5 | def initialize
6 | @value, @flips, @heads, @tails = nil, 0, 0, 0
7 | end
8 |
9 | def flip
10 | @flips += 1
11 | @value = rand(2) == 1 ? 'Heads' : 'Tails'
12 | save_result
13 | @value
14 | end
15 | alias_method :flip!, :flip
16 |
17 | private
18 |
19 | def save_result
20 | @heads += 1 if heads?
21 | @tails += 1 if tails?
22 | end
23 |
24 | def heads?
25 | @value == 'Heads'
26 | end
27 |
28 | def tails?
29 | @value == 'Tails'
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools/dice/utils/modifier_calculator'
2 | require 'rpg_tools/dice/utils/parser'
3 |
4 | require 'rpg_tools/dice/base'
5 | require 'rpg_tools/dice/fudge'
6 | require 'rpg_tools/dice/numerical'
7 | require 'rpg_tools/dice/percentile'
8 | require 'rpg_tools/dice/bag'
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/bag.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | class Bag
4 | NOTATIONS ||= {
5 | 'D' => Numerical,
6 | 'D%' => Percentile,
7 | 'DF' => Fudge
8 | }.freeze
9 |
10 | attr_accessor :dice_hash, :content, :modifiers, :value
11 |
12 | def initialize(base)
13 | @dice_hash = Utils::Parser.new(base).handle
14 | @content = []
15 | @modifiers = dice_hash[:modifiers]
16 | @value = 0
17 | end
18 |
19 | def roll
20 | invalid_dice! if dice_klass.nil?
21 |
22 | fill_bag!
23 |
24 | roll_bag_content!
25 |
26 | return @total if modifiers.empty?
27 |
28 | @total = Utils::ModifierCalculator.new(@total, modifiers).recalculate
29 | end
30 | alias roll! roll
31 |
32 | private
33 |
34 | def fill_bag!
35 | quantity.times { @content << dice_klass.new(sides) }
36 | end
37 |
38 | def roll_bag_content!
39 | @content.map(&:roll)
40 |
41 | @total = @content.map(&:value).inject(0, :+)
42 | end
43 |
44 | def dice_klass
45 | NOTATIONS[type]
46 | end
47 |
48 | def type
49 | dice_hash[:type]
50 | end
51 |
52 | def sides
53 | dice_hash[:sides]
54 | end
55 |
56 | def quantity
57 | dice_hash[:quantity]
58 | end
59 |
60 | def invalid_dice!
61 | raise ArgumentError, 'Unsupported dice type.'
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/base.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | class Base
4 | attr_accessor :sides, :modifiers, :value, :rolls
5 |
6 | def initialize(sides = 0, modifiers = '')
7 | @sides = sides.zero? ? sides_count : sides
8 | @modifiers = modifiers
9 | @value = 0
10 | @rolls = 0
11 |
12 | check_sides
13 | end
14 |
15 | def roll
16 | @rolls += 1
17 |
18 | @value = perform_roll
19 | end
20 |
21 | private
22 |
23 | def perform_roll
24 | return roll_calculation if @modifiers.empty?
25 |
26 | roll_with_modifiers
27 | end
28 |
29 | def roll_with_modifiers
30 | Utils::ModifierCalculator.new(roll_calculation, @modifiers).recalculate
31 | end
32 |
33 | def roll_calculation
34 | raise NotImplementedError
35 | end
36 |
37 | def sides_count
38 | 0
39 | end
40 |
41 | def check_sides
42 | if not_enough_sides
43 | raise ArgumentError, 'Your dice must have at least three sides.'
44 | end
45 | end
46 |
47 | def not_enough_sides
48 | @sides < 3
49 | end
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/fudge.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | class Fudge < Base
4 | def roll_calculation
5 | rand(-1..1)
6 | end
7 |
8 | private
9 |
10 | def sides_count
11 | 3
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/numerical.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | class Numerical < Base
4 | def roll_calculation
5 | rand(1..sides)
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/percentile.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | class Percentile < Base
4 | def roll_calculation
5 | (rand(1..10) * 10)
6 | end
7 |
8 | private
9 |
10 | def sides_count
11 | 10
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/utils/modifier_calculator.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | module Utils
4 | class ModifierCalculator
5 | attr_accessor :total, :modifiers
6 |
7 | def initialize(total, modifiers)
8 | @total = total
9 | @modifiers = modifiers
10 |
11 | unprocessable_modifiers if malformed_modifiers?
12 | end
13 |
14 | def recalculate
15 | modifier_operations.each do |operator, value|
16 | @total = @total.send(operator, value.to_i)
17 | end
18 |
19 | @total
20 | end
21 |
22 | private
23 |
24 | def modifier_operations
25 | @modifiers.scan(/(\D)(\d+)/)
26 | end
27 |
28 | def unprocessable_modifiers
29 | raise ArgumentError,
30 | 'Modifiers require both an operator and a numerical value.'
31 | end
32 |
33 | def malformed_modifiers?
34 | no_operator_at_modifier_beginning? ||
35 | no_number_at_modifier_end? ||
36 | multiple_successive_operators?
37 | end
38 |
39 | def no_operator_at_modifier_beginning?
40 | @modifiers.match(/^\D/).nil?
41 | end
42 |
43 | def no_number_at_modifier_end?
44 | @modifiers.match(/\d+$/).nil?
45 | end
46 |
47 | def multiple_successive_operators?
48 | !@modifiers.match(/\d?([^0-9]{2,})\d?$/).nil?
49 | end
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/rpg_tools/dice/utils/parser.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | module Dice
3 | module Utils
4 | class Parser
5 | attr_reader :dice
6 |
7 | def initialize(dice)
8 | @dice = dice.upcase.match(/^(\d+)([A-Z%]+)(\d*)(.*)$/)
9 |
10 | quantity_error! if @dice.nil?
11 | end
12 |
13 | def handle
14 | {
15 | quantity: quantity,
16 | type: type,
17 | sides: sides,
18 | modifiers: modifiers
19 | }
20 | end
21 |
22 | private
23 |
24 | def quantity
25 | @dice[1].to_i
26 | end
27 |
28 | def type
29 | @dice[2]
30 | end
31 |
32 | def sides
33 | @dice[3].to_i
34 | end
35 |
36 | def modifiers
37 | @dice[4]
38 | end
39 |
40 | def quantity_error!
41 | raise ArgumentError, 'You must specify a dice quantity.'
42 | end
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/rpg_tools/playing_card_deck.rb:
--------------------------------------------------------------------------------
1 | module RpgTools
2 | class PlayingCardDeck
3 | attr_accessor :type, :card_picks, :value
4 |
5 | def initialize(type)
6 | @type = type
7 | type_check
8 | @card_picks = 0
9 | @value = nil
10 | end
11 |
12 | def card
13 | @card_picks += 1
14 |
15 | @value =
16 | if @type == 52
17 | joker_picked? ? 'Joker' : standard_card
18 | else
19 | standard_card
20 | end
21 | end
22 |
23 | def hand
24 | [].tap do |hand|
25 | until hand.count == 5
26 | card = standard_card
27 |
28 | unless hand.include?(card) || hand.count('Joker') == 2
29 | hand << card
30 | @card_picks += 1
31 | end
32 | end
33 | end
34 | end
35 |
36 | private
37 |
38 | def type_check
39 | unless [32, 52].include?(@type)
40 | raise ArgumentError.new('A playing card deck contains 32 or 52 cards only.')
41 | end
42 | end
43 |
44 | def joker_picked?
45 | [0, 1].include?((0..54).to_a.sample(1).first)
46 | end
47 |
48 | def number
49 | if @type == 32
50 | [(7..10).to_a, 'Jack', 'Queen', 'King'].flatten.sample(1)
51 | else
52 | [(1..10).to_a, 'Jack', 'Queen', 'King'].flatten.sample(1)
53 | end
54 | end
55 |
56 | def color
57 | ['Clubs', 'Hearts', 'Diamonds', 'Spades'].sample(1)
58 | end
59 |
60 | def standard_card
61 | @value = [number, color].join(' of ')
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/rpg_tools.gemspec:
--------------------------------------------------------------------------------
1 | Gem::Specification.new do |s|
2 | s.name = %q{rpg_tools}
3 | s.version = '1.0.0'
4 | s.author = 'Yohan Piron'
5 | s.email = 'yinfei84@gmail.com'
6 | s.date = '2015-08-03'
7 | s.summary = 'rpg_tools is a toolbox for tabletop games and RPGs'
8 | s.description = 'rpg_tools gives you tools for your RPGs : dices, coins, cards...'
9 | s.homepage = 'https://github.com/Yinfei/rpg_tools.git'
10 | s.license = 'MIT'
11 | s.files = `git ls-files`.split("\n")
12 | s.test_files = s.files.grep(%r{^(spec)/})
13 | s.require_paths = ['lib']
14 | s.add_development_dependency 'rake', '~> 10.4'
15 | s.add_development_dependency 'rspec', '~> 3.0'
16 | end
17 |
--------------------------------------------------------------------------------
/spec/coin_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Coin do
5 | it "can't return anything else than 'Heads' or 'Tails'" do
6 | expect(['Heads', 'Tails'].include?(described_class.new.flip)).to eq(true)
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/dice/bag_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Bag do
5 | describe '#roll' do
6 | it "doesn't roll a dice without quantity" do
7 | expect { described_class.new('d10').roll }.to raise_error(ArgumentError)
8 | end
9 |
10 | it "doesn't roll a 'd0' dice" do
11 | expect { described_class.new('1d0').roll }.to raise_error(ArgumentError)
12 | end
13 |
14 | it "doesn't roll a 'd1' dice" do
15 | expect { described_class.new('1d1').roll }.to raise_error(ArgumentError)
16 | end
17 |
18 | it "doesn't roll a 'd2' dice" do
19 | expect { described_class.new('1d2').roll }.to raise_error(ArgumentError)
20 | end
21 |
22 | it 'rolls fudge dices' do
23 | expect { described_class.new('1df').roll }.not_to raise_error
24 | end
25 |
26 | it "rolls a dice may the 'd' char be capitalized or not" do
27 | expect { described_class.new('1d6').roll }.not_to raise_error
28 | expect { described_class.new('1D6').roll }.not_to raise_error
29 | end
30 |
31 | it "rolls a dice may the 'f' char be capitalized or not" do
32 | expect { described_class.new('1dF').roll }.not_to raise_error
33 | expect { described_class.new('1Df').roll }.not_to raise_error
34 | end
35 |
36 | it 'rolls a dice with a bonus' do
37 | expect { described_class.new('1d6+2').roll }.not_to raise_error
38 | end
39 |
40 | it 'rolls a dice with a malus' do
41 | expect { described_class.new('1D6-2').roll }.not_to raise_error
42 | end
43 |
44 | it 'rolls a dice with a multiple modifiers' do
45 | expect { described_class.new('1D6-2+4/8').roll }.not_to raise_error
46 | end
47 |
48 | it 'does not roll a dice with bad modifiers' do
49 | expect { described_class.new('1D6-+2').roll }.to raise_error(ArgumentError)
50 | expect { described_class.new('1D6-+2+').roll }.to raise_error(ArgumentError)
51 | end
52 |
53 | it "doesn't roll very odd dices" do
54 | expect { described_class.new('1dDOGE').roll }.to raise_error(ArgumentError)
55 | expect { described_class.new('1dfoo').roll }.to raise_error(ArgumentError)
56 | expect { described_class.new('1foobarbaz').roll }.to raise_error(ArgumentError)
57 | end
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/spec/dice/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Base do
5 | let(:dice) { described_class.new(10) }
6 | let(:dice_with_modifier) { described_class.new(10, '+2') }
7 |
8 | describe '#initialize' do
9 | it 'creates a basic dice' do
10 | expect { described_class.new(10) }.not_to raise_error
11 | end
12 |
13 | it 'creates a basic dice with a modifier' do
14 | expect { described_class.new(10, '+2') }.not_to raise_error
15 | end
16 |
17 | it 'falls back on sides_count method if no sides arg is provided' do
18 | allow_any_instance_of(described_class).to receive(:sides_count).and_return(7)
19 |
20 | new_dice = described_class.new
21 |
22 | expect(new_dice.sides).to eq(7)
23 | end
24 | end
25 |
26 | describe '#roll' do
27 | before do
28 | allow(dice).to receive(:roll_calculation).and_return(10)
29 | allow(dice_with_modifier).to receive(:roll_calculation).and_return(10)
30 | end
31 |
32 | context 'no modifier' do
33 | it 'returns an integer based on a basic roll calculation' do
34 | expect(dice.roll).to eq(10)
35 | end
36 |
37 | it 'does not call the #roll_with_modifiers method' do
38 | expect(dice).not_to receive(:roll_with_modifiers)
39 |
40 | dice.roll
41 | end
42 | end
43 |
44 | context 'modifier present' do
45 | it 'returns an integer based on a roll calulation plus modifier applied' do
46 | expect(dice_with_modifier.roll).to eq(12)
47 | end
48 |
49 | it 'calls the #roll_with_modifiers method' do
50 | expect(dice_with_modifier).to receive(:roll_with_modifiers)
51 |
52 | dice_with_modifier.roll
53 | end
54 | end
55 |
56 | it 'updates a dice value attribute' do
57 | dice.roll
58 |
59 | expect(dice.value).to eq(10)
60 | end
61 |
62 | it 'increments to dice roll count' do
63 | dice.roll
64 |
65 | expect(dice.rolls).to eq(1)
66 |
67 | dice.roll
68 |
69 | expect(dice.rolls).to eq(2)
70 | end
71 | end
72 |
73 | describe '#sides_count' do
74 | it 'returns zero' do
75 | expect(dice.send(:sides_count)).to eq(0)
76 | end
77 | end
78 |
79 | describe '#roll_calculation' do
80 | it 'raises a NotImplementedError' do
81 | expect { dice.send(:roll_calculation) }.to raise_error(NotImplementedError)
82 | end
83 | end
84 |
85 | describe 'not_enough_sides' do
86 | it 'returns true if dice sides is less than three' do
87 | dice.sides = 2
88 |
89 | expect(dice.send(:not_enough_sides)).to be(true)
90 | end
91 |
92 | it 'returns false otherwise' do
93 | expect(dice.send(:not_enough_sides)).to be(false)
94 | end
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/spec/dice/fudge_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Fudge do
5 | let(:dice) { described_class.new }
6 |
7 | describe '#roll_calculation' do
8 | it 'rolls a value between -1 and 1' do
9 | 10.times do
10 | dice.roll
11 |
12 | expect(dice.value.between?(-1, 1)).to be(true)
13 | end
14 | end
15 | end
16 |
17 | describe '#sides_count' do
18 | it 'returns 3' do
19 | expect(dice.send(:sides_count)).to eq(3)
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/dice/numerical_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Numerical do
5 | let(:dice) { described_class.new(10) }
6 |
7 | describe '#roll_calculation' do
8 | it 'rolls a value between 1 and the sides value' do
9 | 10.times do
10 | dice.roll
11 |
12 | expect(dice.value.between?(1, dice.sides)).to be(true)
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/dice/percentile_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Percentile do
5 | let(:dice) { described_class.new }
6 |
7 | describe '#roll_calculation' do
8 | it 'rolls a value between 10 and 100' do
9 | 10.times do
10 | dice.roll
11 |
12 | expect(dice.value.between?(10, 100)).to be(true)
13 | end
14 | end
15 |
16 | it 'rolls only round values' do
17 | 10.times do
18 | dice.roll
19 |
20 | expect(dice.value[-1]).to eq(0)
21 | end
22 | end
23 | end
24 |
25 | describe '#sides_count' do
26 | it 'returns 10' do
27 | expect(dice.send(:sides_count)).to eq(10)
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/dice/utils/modifier_calculator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Utils::ModifierCalculator do
5 | let(:dice) { described_class.new(10, '+1') }
6 |
7 | describe '#initialize' do
8 | it 'raises an error for malformed modifiers' do
9 | expect { described_class.new(10, '+3+') }.to raise_error(ArgumentError)
10 | end
11 |
12 | it 'does not otherwise' do
13 | expect { described_class.new(10, '+5-3/10') }.not_to raise_error
14 | end
15 | end
16 |
17 | describe '#recalculate' do
18 | it 'applies a simple modifier to the total attribute' do
19 | dice = described_class.new(10, '+5')
20 |
21 | dice.recalculate
22 |
23 | expect(dice.total).to eq(15)
24 | end
25 |
26 | it 'applies multiple modifiers to the total attribute' do
27 | dice = described_class.new(10, '+5-1/2')
28 |
29 | dice.recalculate
30 |
31 | expect(dice.total).to eq(7)
32 | end
33 | end
34 |
35 | describe '#malformed_modifiers?' do
36 | it 'returns true if there is not operator at modifiers beginning' do
37 | dice.modifiers = '4'
38 |
39 | expect(dice.send(:malformed_modifiers?)).to be(true)
40 | end
41 |
42 | it 'returns true if there is no number at modifiers end' do
43 | dice.modifiers = '+3-'
44 |
45 | expect(dice.send(:malformed_modifiers?)).to be(true)
46 | end
47 |
48 | it 'returns true if multiple succesive operators are present in the modifiers' do
49 | dice.modifiers = '+-3'
50 |
51 | expect(dice.send(:malformed_modifiers?)).to be(true)
52 | end
53 |
54 | it 'returns false otherwise' do
55 | dice.modifiers = '+4-5/8'
56 |
57 | expect(dice.send(:malformed_modifiers?)).to be(false)
58 | end
59 | end
60 |
61 | describe '#no_operator_at_modifier_beginning?' do
62 | it 'returns true if there is not operator at modifiers beginning' do
63 | dice.modifiers = '4'
64 |
65 | expect(dice.send(:no_operator_at_modifier_beginning?)).to be(true)
66 | end
67 |
68 | it 'returs false otherwise' do
69 | expect(dice.send(:no_operator_at_modifier_beginning?)).to be(false)
70 | end
71 | end
72 |
73 | describe '#no_number_at_modifier_end?' do
74 | it 'returns true if there is no number at modifiers end' do
75 | dice.modifiers = '+3-'
76 |
77 | expect(dice.send(:no_number_at_modifier_end?)).to be(true)
78 | end
79 |
80 | it 'returs false otherwise' do
81 | expect(dice.send(:no_number_at_modifier_end?)).to be(false)
82 | end
83 | end
84 |
85 | describe '#multiple_successive_operators?' do
86 | it 'returns true if multiple succesive operators are present in the modifiers' do
87 | dice.modifiers = '+-3'
88 |
89 | expect(dice.send(:multiple_successive_operators?)).to be(true)
90 | end
91 |
92 | it 'returs false otherwise' do
93 | expect(dice.send(:multiple_successive_operators?)).to be(false)
94 | end
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/spec/dice/utils/parser_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::Dice::Utils::Parser do
5 | describe '#initialize' do
6 | it 'raises an error when no matching pattern is found' do
7 | expect { described_class.new('DOGE') }.to raise_error(ArgumentError)
8 | end
9 |
10 | it 'does not otherwise' do
11 | expect { described_class.new('1DF') }.not_to raise_error
12 | expect { described_class.new('1D10') }.not_to raise_error
13 | expect { described_class.new('1D10+12') }.not_to raise_error
14 | expect { described_class.new('1D%') }.not_to raise_error
15 | end
16 | end
17 |
18 | describe '#handle' do
19 | it 'builds a hash based on a matching pattern' do
20 | hash = described_class.new('3DF+4').handle
21 |
22 | expect(hash[:quantity]).to eq(3)
23 | expect(hash[:type]).to eq('DF')
24 | expect(hash[:sides]).to eq(0)
25 | expect(hash[:modifiers]).to eq('+4')
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/playing_card_deck_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rpg_tools'
2 | require 'spec_helper'
3 |
4 | describe RpgTools::PlayingCardDeck do
5 | it 'must return a card name' do
6 | expect(described_class.new(32).card).not_to eq(true)
7 | expect(described_class.new(32).card).not_to eq(false)
8 | expect(described_class.new(32).card).not_to eq(nil)
9 | expect(described_class.new(52).card).not_to eq(true)
10 | expect(described_class.new(52).card).not_to eq(false)
11 | expect(described_class.new(52).card).not_to eq(nil)
12 | end
13 |
14 | it 'must return 5 cards for a full hand' do
15 | expect(described_class.new(32).hand.count).to eq(5)
16 | expect(described_class.new(52).hand.count).to eq(5)
17 | end
18 |
19 | it "can't pick the same card twice" do
20 | expect(described_class.new(32).hand.uniq.count).to eq(5)
21 | expect(described_class.new(52).hand.uniq.count).to eq(5)
22 | end
23 |
24 | it "can't use anything else than a 32 or 52 cards deck" do
25 | expect { described_class.new(42) }.to raise_error(ArgumentError)
26 | expect { described_class.new(666) }.to raise_error(ArgumentError)
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.color = true
3 | config.tty = true
4 | config.formatter = :documentation
5 |
6 | config.mock_with :rspec do |c|
7 | c.syntax = [:should, :expect]
8 | end
9 |
10 | config.expect_with :rspec do |c|
11 | c.syntax = [:should, :expect]
12 | end
13 | end
14 |
--------------------------------------------------------------------------------