alxndr/fake_british_toponym

View on GitHub
lib/fake_british_toponym.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "probability"
require "fake_british_toponym/corpus"

# Ruby gem that generates fake British-sounding place names.
# @author alxndr aka drwxrxrx

class FakeBritishToponym < String

  # Make a String instance that sounds like a British place name.
  # @param opts [Hash{Symbol: Number, Boolean}] optional configuration data.
  #          available options:
  #          use_modifier [Boolean] whether or not to use an ante/suffix.
  #          true is considered a suggestion; false always omits one.
  #          min_syllables: [Integer] lower bound on how long name should be.
  def initialize(**opts)
    opts[:use_modifier] = true unless opts.has_key? :use_modifier
    opts[:min_syllables] ||= 3

    super build_name(opts[:min_syllables], opts[:use_modifier])
  end

  private

  def build_name(min_syllables, use_modifier)
    # @todo bless syllables into an object
    syllables = [ CORPUS.random_prefix.capitalize ]
    (min_syllables-1).times do
      syllables.push pick_infix(syllables)
    end
    add_suffix(syllables) if syllables.length == 1 || 3.in(10)
    add_decoration(syllables) if use_modifier && 1.in(2)

    syllables.join
  end

  def add_antefix(list)
    list.unshift "#{CORPUS.random_antefix.capitalize} "
  end

  def add_suffix(list)
    list.push pick_suffix(list)
  end

  def add_postfix(list)
    postfix = CORPUS.random_postfix
    case postfix
    when /^-/ # "-on-the-", "-upon-", etc
      list.push postfix
      list.push new_decoration_toponym
    when "of"
      list.push " #{postfix} "
      list.push new_decoration_toponym
    when "'s"
      list.push "#{postfix} "
      list.push new_decoration_toponym
    else
      list.push " #{postfix.capitalize}"
    end
  end

  def add_decoration(list)
    if 1.in(2)
      add_antefix(list)
    else
      add_postfix(list)
    end
  end

  def pick_infix(list)
    begin
      infix = CORPUS.random_infix
    end while infix == list.last # try not to double up syllables
    double_last_letter!(list) if doubled_last_letter_needed?(list, infix)
    infix
  end

  def pick_suffix(list)
    suffix = CORPUS.random_suffix
    double_last_letter!(list) if doubled_last_letter_needed?(list, suffix)
    suffix
  end

  def new_decoration_toponym
    self.class.new use_modifier: false
  end

  def doubled_last_letter_needed?(list, syllable)
    return false unless begins_with_vowel? syllable
    return false if ends_with_vowel? list.last
    return false if ends_with_doubled_letters? list.last
    true
  end

  def begins_with_vowel?(word)
    word.match %r{^[aeiou]}
  end

  def ends_with_vowel?(word)
    word.match %r{[aeiou]$}
  end

  def ends_with_doubled_letters?(word)
    word[-1] == word[-2]
  end

  def double_last_letter!(list)
    last_piece = list.pop
    last_piece_doubled = last_piece + last_piece[-1]
    list.push last_piece_doubled
  end

end