def Password.phonemic(length=8, flags=nil)
pw = nil
ph_flags = flags
loop do
pw = ""
feature_flags = [ flags & ONE_DIGIT, flags & ONE_CASE ]
prev = []
first = true
desired = Password.get_vowel_or_consonant
phonemes = PHONEMES.keys.map { |ph| ph.to_s }
nr_phonemes = phonemes.size
while pw.length < length do
phoneme = phonemes[ rand( nr_phonemes ) ]
ph_len = phoneme.length
ph_flags = PHONEMES[ phoneme.to_sym ]
ph_flags = [ ph_flags & CONSONANT, ph_flags & VOWEL,
ph_flags & DIPHTHONG, ph_flags & NOT_FIRST ]
next if ph_flags.include? desired
next if first and ph_flags.include? NOT_FIRST
next if prev.include? VOWEL and ph_flags.include? VOWEL and
ph_flags.include? DIPHTHONG
next if ph_len > length - pw.length
pw << phoneme
if feature_flags.include? ONE_CASE
if (first or ph_flags.include? CONSONANT) and rand( 10 ) < 3
pw[-ph_len, 1] = pw[-ph_len, 1].upcase
feature_flags.delete ONE_CASE
end
end
break if pw.length >= length
if feature_flags.include? ONE_DIGIT
if ! first and rand( 10 ) < 3
pw << ( rand( 10 ) + ?0 ).chr
feature_flags.delete ONE_DIGIT
first = true
prev = []
desired = Password.get_vowel_or_consonant
next
end
end
if desired == CONSONANT
desired = VOWEL
elsif prev.include? VOWEL or ph_flags.include? DIPHTHONG or
rand(10) > 3
desired = CONSONANT
else
desired = VOWEL
end
prev = ph_flags
first = false
end
break unless feature_flags.include? ONE_CASE or
feature_flags.include? ONE_DIGIT
end
Password.new( pw )
end