module NerdDice
Nerd dice allows you to roll polyhedral dice and add bonuses as you would in a tabletop roleplaying game. You can choose to roll multiple dice and keep a specified number of dice such as rolling 4d6 and dropping the lowest for ability scores or rolling with advantage and disadvantage if those mechanics exist in your game.
This module is broken down into multiple source files:
The class_methods file has all of the module_level methods called by NerdDice.method_name
See the README for overall usage for the module
NerdDice
class methods This file contains module-level attribute readers and writers and includes the other files that provide the class method functionality.
PUBLIC METHODS NerdDice.configure
=> ./class_methods/configure.rb NerdDice.configuration
=> ./class_methods/configure.rb NerdDice.refresh_seed => ./class_methods/refresh_seed.rb NerdDice.execute_die_roll
=> ./class_methods/execute_die_roll.rb NerdDice.total_dice
=> ./class_methods/total_dice.rb NerdDice.roll_dice
=> ./class_methods/roll_dice.rb NerdDice.roll_ability_scores
=> ./class_methods/roll_ability_scores.rb
Configuration
class methods
Usage:
NerdDice.configure takes a block and yields the NerdDice::Configuration properties: If you wanted to configure several properties in a block: <tt> NerdDice.configure do |config| config.randomization_technique = :randomized config.die_background_color = "#FF0000" end </tt> NerdDice.configuration returns the NerdDice::Configuration object and lets you set properties on the NerdDice::Configuration object without using a block: <tt> config = NerdDice.configuration config.randomization_technique = :randomized config.die_background_color = "#FF0000" </tt>
execute_die_roll
class method
Usage:
If you wanted to execute a single d4 die roll without a Die object, you would execute: <tt>NerdDice.execute_die_roll(4)</tt> If you wanted to execute a die roll with a different randomization technique than the one in NerdDice.configuration, you can supply an optional second argument <tt>NerdDice.execute_die_roll(4, :randomized)</tt>
harvest_totals
method
Usage:
This method will take any collection of objects where each element responds to :total and return an array of the results of the total method. Example <tt> ability_score_array = NerdDice.roll_ability_scores => Array of 6 DiceSet objects totals_array = NerdDice.harvest_totals(totals_array) => [15, 14, 13, 12, 10, 8] # yes, it just happened to be the standard array by amazing coincidence </tt>
refresh_seed! class method
Usage:
NerdDice.refresh_seed! by default will refresh the seed for the generator configured in NerdDice.configuration. It can also be used with arguments to set a particular seed for use with deterministic testing. It sets the count_since_last_refresh to 0 whenever called. It cannot refresh or manipulate the seed for SecureRandom <tt>NerdDice.refresh_seed!</tt> With options <tt> previous_seed_data = NerdDice.refresh_seed!( randomization_technique: :randomized, random_rand_seed: 1337, random_object_seed: 24601 ) </tt>
roll_ability_scores
method
Usage:
If you wanted to get an array of DiceSet objects with your ability scores and default configuration you would execute: <tt>ability_score_array = NerdDice.roll_ability_scores</tt> If you wanted to specify configuration for the current operation without modifying the NerdDice.configuration, you can supply options for both the ability_score configuration and the properties of the DiceSet objects returned. Properties are specified in the method comment <tt> ability_score_array = NerdDice.roll_ability_scores( ability_score_array_size: 7, ability_score_number_of_sides: 8, ability_score_dice_rolled: 5, ability_score_dice_kept: 4, randomization_technique: :randomized, foreground_color: "#FF0000", background_color: "#FFFFFF" ) </tt>
roll_dice
class method
Usage:
If you wanted to roll a single d4, you would execute: <tt>dice_set = NerdDice.roll_dice(4)</tt> If you wanted to roll 3d6, you would execute <tt>dice_set = NerdDice.roll_dice(6, 3)</tt> If you wanted to roll a d20 and add 5 to the value, you would execute <tt>dice_set = NerdDice.roll_dice(20, 1, bonus: 5)</tt> Since this method returns a DiceSet, you can call any of the DiceSet methods on the result. See the README for more details and options
total_ability_scores
method
Usage:
If you wanted to get an array of only the values of ability scores and default configuration you would execute: <tt>ability_score_array = NerdDice.total_ability_scores</tt> => [15, 14, 13, 12, 10, 8] If you wanted to specify configuration for the current operation without modifying the NerdDice.configuration, you can supply options for both the ability_score configuration and the properties of the DiceSet objects returned. Many of the properties available in roll_ability_scores will not be relevant to total_ability_scores but the method delegates all options passed without filtering. <tt> ability_score_array = NerdDice.total_ability_scores( ability_score_array_size: 7, ability_score_number_of_sides: 8, ability_score_dice_rolled: 5, ability_score_dice_kept: 4, randomization_technique: :randomized ) => [27, 22, 13, 23, 20, 24, 23] </tt>
total_dice
class method
Usage:
If you wanted to roll a single d4, you would execute: <tt>NerdDice.total_dice(4)</tt> If you wanted to roll 3d6, you would execute <tt>NerdDice.total_dice(6, 3)</tt> If you wanted to roll a d20 and add 5 to the value, you would execute <tt>NerdDice.total_dice(20, 1, bonus: 5)</tt> The bonus in the options hash must be an Integer duck type or nil
Constants
- ABILITY_SCORE_KEYS
- RANDOMIZATION_TECHNIQUES
- VERSION
Attributes
Public Class Methods
configuration class method
Arguments: None Provides the lazy-loaded class instance variable @configuration Return (NerdDice::Configuration
) the Configuration
object tied to the
@configuration class instance variable
# File lib/nerd_dice/class_methods/configure.rb, line 46 def configuration @configuration ||= Configuration.new end
configure class method
Arguments: None Expects and yields to a block where configuration is specified. See README and NerdDice::Configuration
class for config options Return (NerdDice::Configuration
) the Configuration
object tied to the
@configuration class instance variable
# File lib/nerd_dice/class_methods/configure.rb, line 34 def configure yield configuration configuration end
Arguments:
number_of_sides (Integer) => the number of sides of the die to roll using_generator (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES or nil
Return (Integer) => Value of the single die rolled
# File lib/nerd_dice/class_methods/execute_die_roll.rb, line 21 def execute_die_roll(number_of_sides, using_generator = nil) @count_since_last_refresh ||= 0 gen = get_number_generator(using_generator) result = gen.rand(number_of_sides) + 1 increment_and_evalutate_refresh_seed result end
Arguments:
collection (Enumerable) a collection where each element responds to total
Return (Array) => Data type of each element will be whatever is returned by total method
# File lib/nerd_dice/class_methods/harvest_totals.rb, line 24 def harvest_totals(collection) collection.map(&:total) rescue NoMethodError => e specific_message = case e.message when /`total'/ then "Each element must respond to :total." when /`map'/ then "Argument must respond to :map." end specific_message ? raise(ArgumentError, "You must provide a valid collection. #{specific_message}") : raise end
Options: (none required)
randomization_technique (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES if specified random_rand_seed (Integer) => Seed to set for Random random_object_seed (Integer) => Seed to set for new Random object
Return (Hash or nil) => Previous values of generator seeds that were refreshed
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 32 def refresh_seed!(**opts) technique, random_rand_new_seed, random_object_new_seed = parse_refresh_options(opts) @count_since_last_refresh = 0 return nil if technique == :securerandom reset_appropriate_seeds!(technique, random_rand_new_seed, random_object_new_seed) end
Arguments:
opts (options Hash, DEFAULT: {}) any options you wish to include ABILITY SCORE OPTIONS :ability_score_array_size DEFAULT NerdDice.configuration.ability_score_array_size :ability_score_number_of_sides DEFAULT NerdDice.configuration.ability_score_number_of_sides :ability_score_dice_rolled DEFAULT NerdDice.configuration.ability_score_dice_rolled :ability_score_dice_kept DEFAULT NerdDice.configuration.ability_score_dice_kept DICE SET OPTIONS :randomization_technique (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES or nil :foreground_color (String) => should resolve to a valid CSS color (format flexible) :background_color (String) => should resolve to a valid CSS color (format flexible)
Return (Array of NerdDice::DiceSet
) => One NerdDice::DiceSet
element for each ability score rubocop:disable Metrics/MethodLength
# File lib/nerd_dice/class_methods/roll_ability_scores.rb, line 44 def roll_ability_scores(**opts) dice_opts = opts.reject { |key, _value| key.to_s.match?(/\Aability_score_[a-z_]+\z/) } ability_score_options = interpret_ability_score_options(opts) ability_score_array = [] ability_score_options[:ability_score_array_size].times do ability_score_array << roll_dice( ability_score_options[:ability_score_number_of_sides], ability_score_options[:ability_score_dice_rolled], **dice_opts ).highest( ability_score_options[:ability_score_dice_kept] ) end ability_score_array end
roll_dice
class method
Arguments:
number_of_sides (Integer) => the number of sides of the dice to roll number_of_dice (Integer, DEFAULT: 1) => the quantity to roll of the type of die specified in the number_of_sides argument. opts (options Hash, DEFAULT: {}) any additional options you wish to include :bonus (Integer) => The total bonus (positive integer) or penalty (negative integer) to modify the total by. Is added to the total of all dice after they are totaled, not to each die rolled :randomization_technique (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES or nil :foreground_color (String) => should resolve to a valid CSS color (format flexible) :background_color (String) => should resolve to a valid CSS color (format flexible) :damage_type: (String) => damage type for the dice set, if applicable
Return (NerdDice::DiceSet
) => Collection object with one or more Die
objects
You can call roll_dice
().total to get similar functionality to total_dice
or you can chain methods together roll_dice
(6, 4, bonus: 3).with_advantage(3).total
# File lib/nerd_dice/class_methods/roll_dice.rb, line 41 def roll_dice(number_of_sides, number_of_dice = 1, **opts) DiceSet.new(number_of_sides, number_of_dice, **opts) end
Arguments:
opts (options Hash, DEFAULT: {}) any options you wish to include ABILITY SCORE OPTIONS :ability_score_array_size DEFAULT NerdDice.configuration.ability_score_array_size :ability_score_number_of_sides DEFAULT NerdDice.configuration.ability_score_number_of_sides :ability_score_dice_rolled DEFAULT NerdDice.configuration.ability_score_dice_rolled :ability_score_dice_kept DEFAULT NerdDice.configuration.ability_score_dice_kept DICE SET OPTIONS :randomization_technique (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES or nil ARGUMENTS PASSED ON THAT DO NOT REALLY MATTER :foreground_color (String) => should resolve to a valid CSS color (format flexible) :background_color (String) => should resolve to a valid CSS color (format flexible)
Return (Array of Integers) => One Integer element for each ability score
# File lib/nerd_dice/class_methods/total_ability_scores.rb, line 48 def total_ability_scores(**opts) harvest_totals(roll_ability_scores(**opts)) end
Arguments:
number_of_sides (Integer) => the number of sides of the dice to roll number_of_dice (Integer, DEFAULT: 1) => the quantity to roll of the type of die specified in the number_of_sides argument. opts (options Hash, DEFAULT: {}) any additional options you wish to include :bonus (Integer) => The total bonus (positive integer) or penalty (negative integer) to modify the total by. Is added to the total of all dice after they are totaled, not to each die rolled :randomization_technique (Symbol) => must be one of the symbols in RANDOMIZATION_TECHNIQUES or nil
Return (Integer) => Total of the dice rolled, plus modifier if applicable
# File lib/nerd_dice/class_methods/total_dice.rb, line 31 def total_dice(number_of_sides, number_of_dice = 1, **opts) total = 0 number_of_dice.times do total += execute_die_roll(number_of_sides, opts[:randomization_technique]) end begin total += opts[:bonus].to_i rescue NoMethodError raise ArgumentError, "Bonus must be a value that responds to :to_i" end total end
Private Class Methods
# File lib/nerd_dice/class_methods/execute_die_roll.rb, line 31 def get_number_generator(using_generator = nil) using_generator ||= configuration.randomization_technique case using_generator when :securerandom then SecureRandom when :random_rand then Random when :random_object then @random_object ||= Random.new when :randomized then random_generator else raise ArgumentError, "Unrecognized generator. Must be one of #{RANDOMIZATION_TECHNIQUES.join(', ')}" end end
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 76 def increment_and_evalutate_refresh_seed @count_since_last_refresh += 1 return unless configuration.refresh_seed_interval refresh_seed! if @count_since_last_refresh >= configuration.refresh_seed_interval end
rubocop:enable Metrics/MethodLength
# File lib/nerd_dice/class_methods/roll_ability_scores.rb, line 63 def interpret_ability_score_options(opts) return_hash = {} ABILITY_SCORE_KEYS.each { |key| return_hash[key] = parse_ability_score_option(opts, key) } return_hash end
# File lib/nerd_dice/class_methods/roll_ability_scores.rb, line 69 def parse_ability_score_option(option_hash, option_key) option_hash[option_key] || configuration.send(option_key.to_s) end
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 42 def parse_refresh_options(opts) [ opts[:randomization_technique] || configuration.randomization_technique, opts[:random_rand_seed], opts[:random_object_seed] ] end
# File lib/nerd_dice/class_methods/execute_die_roll.rb, line 42 def random_generator gen = RANDOMIZATION_TECHNIQUES.reject { |el| el == :randomized }.sample get_number_generator(gen) end
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 70 def refresh_random_object_seed!(new_seed) old_seed = @random_object&.seed @random_object = new_seed ? Random.new(new_seed) : Random.new old_seed end
rubocop:enable Metrics/MethodLength
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 66 def refresh_random_rand_seed!(new_seed) new_seed ? Random.srand(new_seed) : Random.srand end
rubocop:disable Metrics/MethodLength
# File lib/nerd_dice/class_methods/refresh_seed.rb, line 51 def reset_appropriate_seeds!(technique, random_rand_new_seed, random_object_new_seed) return_hash = {} case technique when :random_rand return_hash[:random_rand_prior_seed] = refresh_random_rand_seed!(random_rand_new_seed) when :random_object return_hash[:random_object_prior_seed] = refresh_random_object_seed!(random_object_new_seed) when :randomized return_hash[:random_rand_prior_seed] = refresh_random_rand_seed!(random_rand_new_seed) return_hash[:random_object_prior_seed] = refresh_random_object_seed!(random_object_new_seed) end return_hash end