Module: Poefy::PoeticFormFromText
- Included in:
- PoefyGen
- Defined in:
- lib/poefy/poetic_form_from_text.rb
Instance Method Summary collapse
-
#poetic_form_from_text(lines) ⇒ Object
Read a song lyric file, output a poetic_form that matches its form.
Instance Method Details
#poetic_form_from_text(lines) ⇒ Object
Read a song lyric file, output a poetic_form that matches its form.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/poefy/poetic_form_from_text.rb', line 13 def poetic_form_from_text lines # If lines is not an array, assume string and split on newlines. lines = lines.respond_to?(:each) ? lines : lines.split("\n") # Remove duplicate '' elements that are neighbours in the array. # https://genius.com/The-monkees-im-a-believer-lyrics prev_line = '' lines.map! do |i| out = (i == '' && prev_line == '') ? nil : i prev_line = i out end lines.compact! # For refrains, we don't care about the lines exactly, just # the structure. So we can delete punctuation and downcase. lines = lines.map do |line| hash = {} hash[:orig] = line hash[:strip] = line.strip hash[:downcase] = line.strip.gsub(/[[:punct:]]/, '').downcase hash end # Find all the lines that are duplicated. # These will be the refrain lines. refrains = lines.map { |i| i[:downcase] } refrains = refrains.inject(Hash.new(0)) { |h, e| h[e] += 1 ; h } refrains = refrains.select { |k, v| v > 1 && k != '' }.keys # Give each a unique refrain ID. buffer = {} refrains.each.with_index { |line, id| buffer[line] = id } refrains = buffer # Loop through and describe each line. lines = lines.map.with_index do |line, index| hash = {} # Text of the line. hash[:strip] = line[:strip] hash[:downcase] = line[:downcase] # Get the phrase info for the line. phrase = phrase_info line[:strip] # Misc details. hash[:num] = index + 1 hash[:syllable] = phrase[:syllables] hash[:last_word] = phrase[:last_word] hash[:indent] = (line[:orig].length - line[:orig].lstrip.length) / 2 # The rhyme tag array for the line. hash[:rhyme_tags] = phrase[:rhymes] # Map [:refrain] and [:exact]. # (They are mutually exclusive) # If it needs to be an exact line, we don't need rhyme tokens. if bracketed?(line[:strip]) hash[:exact] = line[:strip] hash[:rhyme_letter] = nil hash[:syllable] = 0 elsif refrains.keys.include?(line[:downcase]) hash[:refrain] = refrains[line[:downcase]] end hash end # [:rhyme_tags] may well contain more than one rhyme tag. # e.g. 'wind' rhymes with 'sinned' and 'find'. # So we will compare this array against the rhymes of each # other line in the array, to find the correct one to use. # We will work from the closest lines, until we find a match. lines.each.with_index do |line, index| # Compare each other rhyme tag, order by closeness. found_rhyme = line[:rhyme_tags].first if line[:rhyme_tags].length > 1 lines.by_distance(index).each do |i| i[:rhyme_tags].each do |tag| if line[:rhyme_tags].include?(tag) found_rhyme = tag break end end end end # If we haven't found the rhyme, then it doesn't matter, # just use the first in the tag array. lines[index][:rhyme_tags] = *found_rhyme lines[index][:rhyme_tag] = found_rhyme lines[index][:rhyme_letter] = found_rhyme end # Split into separate sections, [:rhyme] and [:syllable]. rhyme = lines.map do |line| hash = {} hash[:token] = line[:rhyme_letter] || ' ' hash[:rhyme_letter] = hash[:token] hash[:refrain] = line[:refrain] if line[:refrain] hash[:exact] = line[:exact] if line[:exact] hash end syllable = {} lines.map.with_index do |line, index| syllable[index+1] = line[:syllable] if line[:syllable] > 0 end # Has to be a single character, so 9 is the maximum. indent = lines.map do |line| line[:indent] >= 9 ? 9 : line[:indent] end.join poetic_form = { rhyme: rhyme, syllable: syllable, indent: indent } poetic_form end |