Class: Dicey::DieFoundry

Inherits:
Object
  • Object
show all
Includes:
Mixins::RationalToInteger
Defined in:
lib/dicey/die_foundry.rb

Overview

Helper to create dice from string definitions. See #call and constants for available formats.

Constant Summary collapse

SPECIAL =

Special characters disallowed in unquoted strings.

%{"',()+−-}
INTEGER =

Pattern for an integer number.

"(?:-?\\d++)"
NUMBER =

Pattern for a possibly fractional number.

"(?:-?\\d++(?:/\\d++|\\.\\d++)?)"
STRING =

Pattern for an "arbitrary" string or number.

%{(?:(?<string>[^#{SPECIAL}]++)|"(?<string>[^",]++)"|'(?<string>[^',]++)')}.freeze
VALUE =

Pattern for a number or string (allowing negative numbers).

"(?:#{NUMBER}(?=[,)+−-]|\\z)|#{STRING})".freeze
COUNT =

Pattern for matching a possible count.

"(?:(?<count>[1-9]\\d*+)?+[Dd])?+"
CONSTANT =

Pattern for matching an optional constant factor.

"(?<constant>(?<sign>[+−-])(?<constant_value>#{NUMBER})|" \
"(?<sign>\\+)(?<constant_value>#{STRING}))".freeze
MOLDS =

Possible molds for the dice. They are matched in the order as written.

[
  # Positive integer goes into the RegularDie mold.
  [/\A#{COUNT}(?<sides>[1-9]\d*+)#{CONSTANT}?\z/, :regular_mold],
  # Integer range goes into the NumericDie mold.
  [molder.("(?<begin>#{INTEGER})(?:[–—…]|\\.{2,3})(?<end>#{INTEGER})"), :range_mold],
  # List of numbers goes into the NumericDie mold.
  [molder.("(?<sides>#{INTEGER}(?:(?:,#{INTEGER})++,?+|,))"), :weirdly_shaped_mold],
  # Non-integers require special handling for precision.
  [molder.("(?<sides>#{NUMBER}(?:(?:,#{NUMBER})++,?+|,))"), :weirdly_precise_mold],
  # Lists of stuff are broken into AbstractDie.
  [molder.("(?<sides>#{VALUE}(?:(?:,#{VALUE})++,?+|,))"), :cursed_mold],
  # Sign-prefixed value goes into the StaticDie mold.
  [/\A#{COUNT}(?:#{CONSTANT}|\(#{CONSTANT}\))\z/, :static_mold],
  # Anything else is spilled on the floor.
].each(&:freeze).freeze

Instance Method Summary collapse

Instance Method Details

#call(definition) ⇒ AbstractDie+ Also known as: cast

Cast a die definition into a mold to make a die.

Following definitions are recognized:

  • positive integer (like "6" or "20"), which produces a RegularDie;
  • integer range (like "3—6" or "(-5..5)"), which produces a NumericDie;
  • list of integers (like "(3,4,5)", "-1,0,1", or "2,"), which produces a NumericDie;
  • list of decimal numbers (like "0.5,0.2,0.8" or "(2.0,)"), which produces a NumericDie, but uses Rational for values to maintain precise results;
  • list of strings, possibly mixed with numbers (like "0.5,asdf" or "(👑,♠️,♥️,♣️,♦️,⚓️)"), which produces an AbstractDie with numbers treated the same as in previous cases, and other or quoted values treated as Strings.
  • signed value (like "+3", "-3.6" or "(+ABC)"), which produces a StaticDie, non-numeric values are only allowed as positive values;

Any die definition can be prefixed with a count, like "2D6" or "1d1,3,5" to create an array. A plain "d"/"D" without an explicit count is ignored instead, creating a single die.

All die definitions (aside from plain signed value) can be suffixed with a signed value to add or subtract from the result, like "2D6+3" or "5dA,B,C+C". Only numbers can be subtracted.

Parameters:

  • definition (String) —

    die shape

Returns:

Raises:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/dicey/die_foundry.rb', line 78

def call(definition)
  matched, name =
    MOLDS.find do |(shape, mold)|
      match = shape.match(definition)
      break [match, mold] if match
    end
  raise DiceyError, "can not cast die from `#{definition}`!" unless name

  if matched[:constant] && name != :static_mold
    [__send__(name, matched), static_mold(matched, ignore_count: true)].flatten
  else
    __send__(name, matched)
  end
end