poefy 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00e0ad3b9108ce69d617edf3971dac999fad5094
4
- data.tar.gz: 6fda3f2e361c48616f3dfda503f86db91dc9130b
3
+ metadata.gz: 0defb6d9a94a5162826c5815c0f9f1aac7b98c91
4
+ data.tar.gz: a8c83d5c423ea918252c47a2aa74897d44ad2c72
5
5
  SHA512:
6
- metadata.gz: d0ad8d6d99227e14f058ed9821ff4b9c2a8e7ff579b1ab97650283e088452f4632a6c5bde8a680116e50a7572fe7e7b1ab97c3caba02902b3df55cbb70309629
7
- data.tar.gz: f14266288f23718113a20bc1b13f3d8848dd53d99f46c3a762994b3221cfc594e426de4af7b9839a67f11c1a05f138b8fc0b2b425fdc9fb77c9f002c2886c072
6
+ metadata.gz: a09920a71f8feced4ddd7a079c06f8ea2c763f7fa84adb47da81d075d993d94b4ba65e8e1889d3be57081c634f04edb77fee46a3beaf414cdf6ea58bf229eb09
7
+ data.tar.gz: 5ee1495dab167b26d4ec006b3fadd18e93a85d483e2730f061080dc6cd32988c0d50d5fca542b52d47b48a6abfc9b15e3c30939c477067a238097a525802f988
data/README.md CHANGED
@@ -38,7 +38,7 @@ The code rather hackily uses system to call `sqlite3`, so make sure you have tha
38
38
 
39
39
  Make a poefy database from a text file:
40
40
 
41
- $ poefy shakespeare < shakespeare_sonnets.txt
41
+ $ poefy shakespeare -o < shakespeare_sonnets.txt
42
42
 
43
43
  Now, whenever you want to make poems using Shakespeare's lines, you can just use `poefy shakespeare` and it will read from the already created database:
44
44
 
@@ -147,11 +147,11 @@ Specify syllable count allowed for each line. There's a few valid forms it can t
147
147
 
148
148
  If the string is just one number, all lines will be that number of syllables long.
149
149
 
150
- $ poefy whitman -s'10'
150
+ $ poefy whitman sonnet -s'10'
151
151
 
152
152
  If the string is comma delimited, all lines will be any of those numbers of syllables long.
153
153
 
154
- $ poefy whitman -s'9,10,11'
154
+ $ poefy whitman sonnet -s'9,10,11'
155
155
 
156
156
  If the string is an array, each element corresponds to a line in the output. This will skip blank lines.
157
157
 
@@ -164,7 +164,8 @@ If the string is a hash, the key will be used to match the line number.
164
164
 
165
165
  $ poefy whitman -r'aabba' -s'{1:8,2:8,3:5,4:5,5:8}'
166
166
  $ poefy whitman -r'aabba' -s'{1:[8,9],2:[8,9],3:[4,5,6],4:[4,5,6],5:[8,9]}'
167
- $ poefy whitman -r'aabba' -s'{0:[8,9],3:[4,5,6],4:[4,5,6]}'
167
+ $ poefy whitman -r'aabba' -s'{0: [8,9],3: [4,5,6],4: [4,5,6]}'
168
+ $ poefy whitman -r'aabba' -s'{0=>[8,9],3=>[4,5,6],4=>[4,5,6]}'
168
169
 
169
170
  In the hash form, any lines not explicitly specified will use the value of the '0' key. If there is no '0' key, the lines will be ignored.
170
171
 
@@ -188,7 +189,7 @@ If the string is just one regex, all lines will be forced to match that regex.
188
189
  $ poefy whitman sonnet -x'^[A-Z].*$'
189
190
  $ poefy whitman sonnet -x'^[^e]*$' -s0
190
191
 
191
- If the string is a hash, the key will be used to match the line number. Unlike in the `syllable` string, you must use ruby's `=>` key identifier. Also, you must put the regex inside `/slashes/`.
192
+ If the string is a hash, the key will be used to match the line number. Unlike in the `syllable` string, you must use ruby's `=>` key identifier, and not `:` as in JSON. Also, you must put the regex inside `/slashes/`.
192
193
 
193
194
  Example, to ensure the first line always starts with capitalisation:
194
195
 
@@ -213,7 +214,7 @@ You must also beware of repeated lines (uppercase letters in the rhyme string).
213
214
 
214
215
  #### Option `-A` or `--acrostic_x`
215
216
 
216
- This does the same as `-a`, but with special workarounds for 'x'. In the case that a line needs to match '^x', it will instead match '^ex' and replace with 'eX'. It will also use indentation to line-up the letters vertically:
217
+ This does the same as `-a`, but with special workarounds for 'x'. In the case that a line needs to match /^x/, it will instead match /^ex/ and replace with 'eX'. It will also use indentation to line-up the letters vertically:
217
218
 
218
219
  $ poefy whitman -s8 -r abcbdd -A taxman
219
220
 
@@ -269,12 +270,18 @@ You can do the same thing for the other keys: `rhyme`, `final_word`, and `syllab
269
270
 
270
271
  #### Special case: poetic form from text file
271
272
 
272
- If the second argument is a reference to a text file, then the output will be a poem with the same structure as the file.
273
+ If you pipe in text and don't use the `-o` option to create a database, then the output will be a poem with the same structure as the file. This can also be accomplished if the second argument is a reference to a text file. So, assuming you have a `lyrics` script that will return song lines for you:
274
+
275
+ $ lyrics 'carly rae jepsen' 'call me maybe' | tee jep.txt | poefy whitman
276
+ $ poefy whitman < jep.txt
277
+ $ poefy whitman jep.txt
273
278
 
274
279
  The program will scan by line, looking for rhyme, syllables and repeated lines. It will then build up a constraint hash and use that as the poetic form.
275
280
 
276
281
  Any line that is bracketed in `[square]` or `{curly}` braces will be duplicated exactly in the output. This is for lines such as "chorus" or "1st verse" descriptions. This seems to work nicely with lyrics from genius.com.
277
282
 
283
+ Also, any indentation will be preserved, assuming 2 spaces per "indent".
284
+
278
285
  Here's an example of a song that can be sung to the same tune as "[I Want to Hold Your Hand][1]", but using lyrics from all Beatles songs:
279
286
 
280
287
  ````
@@ -366,6 +373,8 @@ puts poefy.poem ({ form: :sonnet, regex: '^[A-Z].*$' })
366
373
  puts poefy.poem ({ form: :sonnet, acrostic: 'pauldpthompson' })
367
374
  puts poefy.poem ({ form: 'sonnet', indent: '01010101001101' })
368
375
  puts poefy.poem ({ form: 'sonnet', proper: false })
376
+ puts poefy.poem ({ form_from_text: 'how_do_i_love_thee.txt' })
377
+ puts poefy.poem ({ form_from_text: 'how_do_i_love_thee.txt', syllable: 0 })
369
378
  ```
370
379
 
371
380
  All options can be specified at object initialisation, and subsequent poems will use those options as default:
data/bin/poefy CHANGED
@@ -46,8 +46,11 @@ def parse_options
46
46
  poefy whitman -r 'A1bA2 abA1 abA2 abA1 abA2 abA1A2'
47
47
  ].gsub(' ',' ')
48
48
 
49
- databases = Poefy.all_databases.join("\n" + ' ' * 21)
50
- databases = "Databases available: " + databases
49
+ databases = (Poefy.all_databases - ['test'])
50
+ .each_slice(4).to_a
51
+ .map { |i| i.join ', ' }
52
+ .join("\n" + ' ' * 21)
53
+ databases = 'Databases available: ' + databases
51
54
 
52
55
  opts.banner = program_info + "\n" + usage + "\n" + databases + "\n\n"
53
56
 
@@ -93,6 +96,13 @@ def parse_options
93
96
  options[:proper] = false
94
97
  end
95
98
 
99
+ # Repeat options.
100
+ opts.separator nil
101
+ opts.on('-n', '--number INTEGER',
102
+ "Number of poems to generate") do |n|
103
+ options[:number] = n.to_i
104
+ end
105
+
96
106
  # Database options.
97
107
  opts.separator nil
98
108
  opts.on('-o', '--overwrite',
@@ -145,8 +155,8 @@ data = (not STDIN.tty? and not STDIN.closed?) ? STDIN.read : nil
145
155
  # Database is the first argument.
146
156
  first_arg = ARGV.first
147
157
  if first_arg.nil?
148
- puts "ERROR: Please specify a database to read from."
149
- exit 0
158
+ STDERR.puts "ERROR: Please specify a database to read from / to"
159
+ exit 1
150
160
  end
151
161
 
152
162
  # If the first argument is 'make_dbs', then make
@@ -179,34 +189,50 @@ end
179
189
 
180
190
  # Poetic form name is the second argument, if it exists.
181
191
  second_arg = (ARGV.length > 1) ? ARGV[1] : ''
182
- options[:form] = second_arg
183
-
184
- # Create poefy object.
185
- poefy = Poefy::PoefyGen.new first_arg, options
192
+ options[:form] = second_arg if second_arg != ''
193
+
194
+ # If we need to make a database.
195
+ # Exit the program after database is generated.
196
+ if options[:overwrite]
197
+ poefy = Poefy::PoefyGen.new first_arg
198
+ if data
199
+ poefy.make_database data, true
200
+ poefy.close
201
+ exit 0
202
+ else
203
+ STDERR.puts 'ERROR: Need text input to generate a database'
204
+ STDERR.puts ' Please pipe some data into the program'
205
+ exit 1
206
+ end
207
+ end
186
208
 
187
209
  # If the second argument is 'rhyme', then output all
188
210
  # lines that rhyme with the word.
189
211
  if second_arg == 'rhyme'
212
+ poefy = Poefy::PoefyGen.new first_arg
190
213
  third_arg = (ARGV.length > 2) ? ARGV[2] : nil
191
214
  fourth_arg = (ARGV.length > 3) ? ARGV[3] : nil
192
215
  puts poefy.rhymes(third_arg, fourth_arg)
193
216
  exit 0
194
217
  end
195
218
 
196
- # If the second argument is a file, then use that as the poetic_form.
197
- updated_poetic_form = {}
198
- if File.exists?(second_arg)
199
- updated_poetic_form = poefy.poetic_form_from_text(second_arg)
219
+ # If there is piped data, or the second argument is a file,
220
+ # then use that as the poetic_form.
221
+ if data or File.exists?(second_arg)
222
+ options[:form_from_text] = (data || second_arg)
200
223
  end
201
224
 
202
- # Create a database using input.
203
- if data
204
- poefy.make_database data, options[:overwrite]
225
+ # Create poefy object using the options.
226
+ poefy = Poefy::PoefyGen.new first_arg, options
205
227
 
206
- # Make a new poem, and output it.
207
- else
208
- poem = poefy.poem(updated_poetic_form)
209
- puts poem if poem
228
+ # Make the correct number of poems, and output them.
229
+ number = options[:number] || 1
230
+ number.times do |i|
231
+ poem = poefy.poem
232
+ if poem
233
+ puts poem
234
+ puts nil if i < number - 1
235
+ end
210
236
  end
211
237
 
212
238
  # Close the database connection.
data/lib/poefy.rb CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  require 'ruby_rhymes'
14
14
  require 'wordfilter'
15
+ require 'humanize'
15
16
  require 'tempfile'
16
17
  require 'sqlite3'
17
18
  require 'timeout'
@@ -26,6 +27,7 @@ require_relative 'poefy/string_manipulation.rb'
26
27
  require_relative 'poefy/handle_error.rb'
27
28
  require_relative 'poefy/database.rb'
28
29
  require_relative 'poefy/conditional_satisfaction.rb'
30
+ require_relative 'poefy/core_extensions/array.rb'
29
31
 
30
32
  ################################################################################
31
33
 
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: UTF-8
3
+
4
+ ################################################################################
5
+ # Monkey patch the Array class.
6
+ ################################################################################
7
+
8
+ # [array] is the same array as [self], but ordered by closeness to the index.
9
+ # Optionally pass an integer, for results for just that index element.
10
+ # Returns a Struct, or an array of Structs, in the form:
11
+ # .index => original index
12
+ # .value => original element
13
+ # .array => self array minus value, ordered by closeness to index
14
+ # Example usage:
15
+ # lines = (1..4).to_a * 2
16
+ # puts lines.by_distance
17
+ # puts lines.by_distance(3)
18
+ # lines.by_distance(3).each { ... }
19
+ module Poefy
20
+ module CoreExtensions
21
+
22
+ # Output struct for #by_distance method.
23
+ # Array is the most useful data, but index and value are also kept.
24
+ IndexValueArray = Struct.new(:index, :value, :array) do
25
+ alias_method :to_a, :array
26
+ include Enumerable
27
+ def each &block
28
+ array.each do |i|
29
+ block.call i
30
+ end
31
+ end
32
+ end
33
+
34
+ module Array
35
+
36
+ def by_distance index = nil
37
+ if index.nil?
38
+ self.map.with_index do |value, index|
39
+ self.by_distance index
40
+ end
41
+ else
42
+ others, counter = [], 0
43
+ loop do
44
+ counter += 1
45
+ below_index = index - counter
46
+ below_index = nil if below_index < 0
47
+ below = self[below_index] if below_index
48
+ above = self[index + counter]
49
+ others << below if below
50
+ others << above if above
51
+ break if !above and !below
52
+ end
53
+ IndexValueArray.new(index, self[index], others)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ class Array
61
+ include Poefy::CoreExtensions::Array
62
+ end
63
+
64
+ ################################################################################
@@ -158,17 +158,28 @@ module Poefy
158
158
  def save_sql_import_file lines
159
159
  sql_lines = []
160
160
  lines.map do |line|
161
+
162
+ # Don't add the line if it contains a blacklisted? substring.
161
163
  next if Wordfilter.blacklisted? line
164
+
165
+ # Format the line for SQL parsing.
162
166
  line_ = format_sql_string line
163
- final = line.to_phrase.last_word.downcase rescue ''
164
167
 
165
- final_ = format_sql_string final
166
- syll = syllables line
167
- get_rhymes(line).each do |rhyme|
168
+ # Get the phrase info for the line.
169
+ phrase = phrase_info line
170
+ syll = phrase[:syllables]
171
+ rhymes = phrase[:rhymes]
172
+ final_ = format_sql_string phrase[:last_word]
173
+
174
+ # There may be more than one rhyme, so add a database
175
+ # record for each rhyme.
176
+ rhymes.each do |rhyme|
168
177
  rhyme_ = format_sql_string rhyme
169
178
  sql_lines << "\"#{line_}\"\t#{syll}\t\"#{final_}\"\t\"#{rhyme_}\""
170
179
  end
171
180
  end
181
+
182
+ # Save the SQL spec to a temporary file, and return the filename.
172
183
  sql_file = tmpfile
173
184
  File.open(sql_file, 'w') { |fo| fo.puts sql_lines }
174
185
  sql_file
@@ -18,11 +18,13 @@ module Poefy
18
18
 
19
19
  # Make a database using the given lines.
20
20
  def make_database input, overwrite = @overwrite
21
+ lines = validate_lines input
22
+ lines.map(&:strip!)
21
23
  @db.close if @db
22
24
  if overwrite
23
- @db.make_new! validate_lines input
25
+ @db.make_new! lines
24
26
  else
25
- @db.make_new validate_lines input
27
+ @db.make_new lines
26
28
  end
27
29
  end
28
30
  def make_database! input
@@ -43,7 +45,6 @@ module Poefy
43
45
 
44
46
  # If lines is not an array, assume string and split on newlines.
45
47
  lines = lines.respond_to?(:each) ? lines : lines.split("\n")
46
- lines.map(&:strip!)
47
48
  lines
48
49
  end
49
50
 
@@ -77,6 +78,13 @@ module Poefy
77
78
  input, output = poetic_form, {}
78
79
  form_string = get_valid_form input[:form]
79
80
 
81
+ # Apply ':form_from_text' before any others.
82
+ if input[:form_from_text]
83
+ lines = validate_lines input[:form_from_text]
84
+ form = poetic_form_from_text lines
85
+ input = form.merge input
86
+ end
87
+
80
88
  # Handle obvious inputs.
81
89
  output[:form] = form_string if form_string
82
90
  output[:rhyme] = input[:rhyme] if input[:rhyme]
@@ -10,16 +10,29 @@ module Poefy
10
10
  module PoeticFormFromText
11
11
 
12
12
  # Read a song lyric file, output a poetic_form that matches its form.
13
- def poetic_form_from_text text_file
14
- lines = File.readlines(text_file).map(&:strip)
13
+ def poetic_form_from_text lines
14
+
15
+ # If lines is not an array, assume string and split on newlines.
16
+ lines = lines.respond_to?(:each) ? lines : lines.split("\n")
17
+
18
+ # Remove duplicate '' elements that are neighbours in the array.
19
+ # https://genius.com/The-monkees-im-a-believer-lyrics
20
+ prev_line = ''
21
+ lines.map! do |i|
22
+ out = (i == '' && prev_line == '') ? nil : i
23
+ prev_line = i
24
+ out
25
+ end
26
+ lines.compact!
15
27
 
16
28
  # For refrains, we don't care about the lines exactly, just
17
29
  # the structure. So we can delete punctuation and downcase.
18
30
  lines = lines.map do |line|
19
- {
20
- orig: line,
21
- downcase: line.gsub(/[[:punct:]]/, '').downcase
22
- }
31
+ hash = {}
32
+ hash[:orig] = line
33
+ hash[:strip] = line.strip
34
+ hash[:downcase] = line.strip.gsub(/[[:punct:]]/, '').downcase
35
+ hash
23
36
  end
24
37
 
25
38
  # Find all the lines that are duplicated.
@@ -38,27 +51,26 @@ module Poefy
38
51
  hash = {}
39
52
 
40
53
  # Text of the line.
41
- hash[:orig] = line[:orig]
54
+ hash[:strip] = line[:strip]
42
55
  hash[:downcase] = line[:downcase]
43
56
 
57
+ # Get the phrase info for the line.
58
+ phrase = phrase_info line[:strip]
59
+
44
60
  # Misc details.
45
61
  hash[:num] = index + 1
46
- hash[:syllable] = syllables(hash[:downcase])
47
- hash[:last_word] = (text.to_phrase.last_word rescue '')
62
+ hash[:syllable] = phrase[:syllables]
63
+ hash[:last_word] = phrase[:last_word]
64
+ hash[:indent] = (line[:orig].length - line[:orig].lstrip.length) / 2
48
65
 
49
- # The rhyme for the line.
50
- # ToDo: For now, just get the first rhyme of the tag array.
51
- rhyme_tag = get_rhymes(hash[:downcase]).first
52
- hash[:rhyme_tag] = rhyme_tag || ' '
53
- hash[:rhyme_letter] = rhyme_tag
54
- hash[:rhyme] = ' ' if hash[:downcase] == ''
66
+ # The rhyme tag array for the line.
67
+ hash[:rhyme_tags] = phrase[:rhymes]
55
68
 
56
69
  # Map [:refrain] and [:exact].
57
70
  # (They are mutually exclusive)
58
71
  # If it needs to be an exact line, we don't need rhyme tokens.
59
- if bracketed?(line[:orig].strip)
60
- hash[:exact] = line[:orig]
61
- hash[:rhyme] = ' '
72
+ if bracketed?(line[:strip])
73
+ hash[:exact] = line[:strip]
62
74
  hash[:rhyme_letter] = nil
63
75
  hash[:syllable] = 0
64
76
  elsif refrains.keys.include?(line[:downcase])
@@ -68,14 +80,32 @@ module Poefy
68
80
  hash
69
81
  end
70
82
 
71
- # puts '########################################'
72
- # lines.each { |i| puts i }
83
+ # [:rhyme_tags] may well contain more than one rhyme tag.
84
+ # e.g. 'wind' rhymes with 'sinned' and 'find'.
85
+ # So we will compare this array against the rhymes of each
86
+ # other line in the array, to find the correct one to use.
87
+ # We will work from the closest lines, until we find a match.
88
+ lines.each.with_index do |line, index|
89
+
90
+ # Compare each other rhyme tag, order by closeness.
91
+ found_rhyme = line[:rhyme_tags].first
92
+ if line[:rhyme_tags].length > 1
93
+ lines.by_distance(index).each do |i|
94
+ i[:rhyme_tags].each do |tag|
95
+ if line[:rhyme_tags].include?(tag)
96
+ found_rhyme = tag
97
+ break
98
+ end
99
+ end
100
+ end
101
+ end
73
102
 
74
- # # Compare each [:rhyme_tag] against the rest of the array.
75
- # lines_TODO = lines.map do |text|
76
- # remaining = lines - [text]
77
- # rhyme_tags = remaining.map { |i| i[:rhyme_tag] }
78
- # end
103
+ # If we haven't found the rhyme, then it doesn't matter,
104
+ # just use the first in the tag array.
105
+ lines[index][:rhyme_tags] = *found_rhyme
106
+ lines[index][:rhyme_tag] = found_rhyme
107
+ lines[index][:rhyme_letter] = found_rhyme
108
+ end
79
109
 
80
110
  # Split into separate sections, [:rhyme] and [:syllable].
81
111
  rhyme = lines.map do |line|
@@ -92,9 +122,15 @@ module Poefy
92
122
  syllable[index+1] = line[:syllable] if line[:syllable] > 0
93
123
  end
94
124
 
125
+ # Has to be a single character, so 9 is the maximum.
126
+ indent = lines.map do |line|
127
+ line[:indent] >= 9 ? 9 : line[:indent]
128
+ end.join
129
+
95
130
  poetic_form = {
96
131
  rhyme: rhyme,
97
- syllable: syllable
132
+ syllable: syllable,
133
+ indent: indent
98
134
  }
99
135
  poetic_form
100
136
  end
@@ -7,6 +7,7 @@
7
7
 
8
8
  require 'ruby_rhymes'
9
9
  require 'wordfilter'
10
+ require 'humanize'
10
11
 
11
12
  ################################################################################
12
13
 
@@ -27,14 +28,67 @@ module Poefy
27
28
  (text.gsub(/[[:punct:]]/,'').scan(/^[^ ]+/).first rescue '') || ''
28
29
  end
29
30
 
30
- # Uses 'ruby_rhymes' to find the rhyme key for a text.
31
- def get_rhymes text
32
- (numeric?(text[-1]) ? [] : text.to_phrase.rhymes.keys) rescue []
31
+ # Return info that is returned using 'ruby_rhymes' '#to_phrase'
32
+ # But also account for numbers and initialisms.
33
+ def phrase_info text
34
+ input = humanize_instr text
35
+ phrase = input.to_phrase rescue nil
36
+ return { rhymes: [], syllables: 0, last_word: '' } if phrase.nil?
37
+ last_word = phrase.last_word.downcase rescue ''
38
+ rhy = phrase.rhymes.keys rescue []
39
+ rhy = rhyme_initialism(input) if rhy.empty?
40
+ syl = syllables_correct text rescue 0
41
+ { rhymes: rhy, syllables: syl, last_word: last_word }
33
42
  end
34
43
 
35
- # The number of syllables in the text.
36
- def syllables text
37
- text.to_phrase.syllables rescue 0
44
+ # Humanize every number in the text.
45
+ # This will not work for floats.
46
+ # It will also break emoticons, but GIGO.
47
+ def humanize_instr text
48
+ output = text
49
+ loop do
50
+ num = output[/\d+/]
51
+ break if not num
52
+ output.sub!(num, num.to_i.humanize)
53
+ end
54
+ output
55
+ end
56
+
57
+ # We will only call this method if there are no dictionary rhymes.
58
+ # If the last word is uppercase, then assume it's an initialism.
59
+ # Get the last letter and rhyme that.
60
+ # Else, return an empty array, as normal.
61
+ def rhyme_initialism text
62
+ output = []
63
+ last_word = text.split.last
64
+ if last_word and last_word == last_word.upcase
65
+ letter = last_word.scan(/[A-Z]/).last
66
+ output = letter.to_phrase.rhymes.keys rescue []
67
+ end
68
+ output
69
+ end
70
+
71
+ # Get the correct syllable count, even for initialisms.
72
+ # e.g. "Flew in from Miami Beach BOAC"
73
+ # "I'm back in the U.S.S.R"
74
+ def syllables_correct text
75
+ syll_count = 0
76
+
77
+ # This is similar to how 'ruby_rhymes' splits to word.
78
+ # But that gem ignores case, which we need.
79
+ text.gsub(/[^A-Z ']/i,'').split.each do |word|
80
+
81
+ # If the word has no rhymes, and it is uppercase, then assume
82
+ # it's an initialism and count each letter's syllables.
83
+ if word.to_phrase.rhyme_keys.empty? and word == word.upcase
84
+ word.gsub(/[^A-Z]/,'').split('').each do |i|
85
+ syll_count += i.to_phrase.syllables
86
+ end
87
+ else
88
+ syll_count += word.to_phrase.syllables
89
+ end
90
+ end
91
+ syll_count
38
92
  end
39
93
 
40
94
  # Final line must close with sentence-end punctuation.
data/lib/poefy/version.rb CHANGED
@@ -12,13 +12,13 @@ module Poefy
12
12
  end
13
13
 
14
14
  def self.version_date
15
- '2017-06-02'
15
+ '2017-06-19'
16
16
  end
17
17
 
18
18
  module VERSION
19
19
  MAJOR = 0
20
20
  MINOR = 6
21
- TINY = 0
21
+ TINY = 1
22
22
  PRE = nil
23
23
 
24
24
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
data/poefy.gemspec CHANGED
@@ -30,4 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.add_runtime_dependency('sqlite3', '~> 1.3', '>= 1.3.13')
31
31
  s.add_runtime_dependency('ruby_rhymes', '~> 0.1', '>= 0.1.2')
32
32
  s.add_runtime_dependency('wordfilter', '~> 0.2', '>= 0.2.6')
33
+ s.add_runtime_dependency('humanize', '~> 1.4', '>= 1.4.0')
33
34
  end
data/spec/poefy_spec.rb CHANGED
@@ -618,6 +618,105 @@ describe Poefy::PoefyGen do
618
618
  end
619
619
  end
620
620
 
621
+ ##############################################################################
622
+
623
+ describe "using the form_from_text option" do
624
+ before(:all) do
625
+ @file = "#{@root}/data/i_want_to_hold_your_hand.txt"
626
+ end
627
+
628
+ it "should use the exact poetic form 1" do
629
+ poefy = Poefy::PoefyGen.new(:beatles, {
630
+ form_from_text: @file
631
+ })
632
+ poem = poefy.poem
633
+ expect(poem.count).to be 46
634
+ end
635
+
636
+ it "should use the exact poetic form 2" do
637
+ poefy = Poefy::PoefyGen.new :beatles
638
+ poem = poefy.poem({
639
+ form_from_text: @file
640
+ })
641
+ expect(poem.count).to be 46
642
+ end
643
+
644
+ it "should correctly modify the poetic form 1" do
645
+ poefy = Poefy::PoefyGen.new(:beatles, {
646
+ form_from_text: @file,
647
+ syllable: 6
648
+ })
649
+ poem = poefy.poem
650
+ expect(poem.count).to be 46
651
+ end
652
+
653
+ it "should correctly modify the poetic form 2" do
654
+ poefy = Poefy::PoefyGen.new :beatles
655
+ poem = poefy.poem({
656
+ form_from_text: @file,
657
+ syllable: 6
658
+ })
659
+ expect(poem.count).to be 46
660
+ end
661
+
662
+ it "should correctly modify the poetic form 3" do
663
+ poefy = Poefy::PoefyGen.new(:beatles, {
664
+ form_from_text: @file
665
+ })
666
+ poem = poefy.poem({
667
+ syllable: 6
668
+ })
669
+ expect(poem.count).to be 46
670
+ end
671
+
672
+ it "should correctly replace the poetic form" do
673
+ poefy = Poefy::PoefyGen.new(:beatles, {
674
+ syllable: 6
675
+ })
676
+ poem = poefy.poem({
677
+ form_from_text: @file
678
+ })
679
+ expect(poem.count).to be 46
680
+ end
681
+
682
+ ############################################################################
683
+
684
+ describe "private method #poetic_form_from_text" do
685
+
686
+ # Singleton which includes the method.
687
+ # Make the private methods public.
688
+ let(:obj) do
689
+ class Sing
690
+ include Poefy::PoeticFormFromText
691
+ include Poefy::StringManipulation
692
+ public *private_instance_methods
693
+ end.new
694
+ end
695
+
696
+ it "80 should rhyme with weighty" do
697
+ lines = ["Lorem ipsum dolor weighty", "Lorem ipsum dolor 80"]
698
+ form = obj.poetic_form_from_text(lines)
699
+ expect(form[:rhyme].uniq.count).to be 1
700
+ end
701
+ it "80 should not rhyme with shoe" do
702
+ lines = ["Lorem ipsum dolor shoe", "Lorem ipsum dolor 80"]
703
+ form = obj.poetic_form_from_text(lines)
704
+ expect(form[:rhyme].uniq.count).to_not be 1
705
+ end
706
+ it "2 should rhyme with shoe" do
707
+ lines = ["Lorem ipsum dolor shoe", "Lorem ipsum dolor 2"]
708
+ form = obj.poetic_form_from_text(lines)
709
+ expect(form[:rhyme].uniq.count).to be 1
710
+ end
711
+ it "2 should not rhyme with weighty" do
712
+ lines = ["Lorem ipsum dolor weighty", "Lorem ipsum dolor 2"]
713
+ form = obj.poetic_form_from_text(lines)
714
+ expect(form[:rhyme].uniq.count).to_not be 1
715
+ end
716
+ end
717
+
718
+ end
719
+
621
720
  end
622
721
 
623
722
  ################################################################################
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poefy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Thompson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-02 00:00:00.000000000 Z
11
+ date: 2017-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -112,6 +112,26 @@ dependencies:
112
112
  - - ">="
113
113
  - !ruby/object:Gem::Version
114
114
  version: 0.2.6
115
+ - !ruby/object:Gem::Dependency
116
+ name: humanize
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '1.4'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.4.0
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.4'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.4.0
115
135
  description: Create poems from an input text file, by generating and querying a SQLite
116
136
  database describing each line. Poems are created using a template to select lines
117
137
  from the database, according to closing rhyme, syllable count, and regex matching.
@@ -137,6 +157,7 @@ files:
137
157
  - data/whitman_leaves.txt
138
158
  - lib/poefy.rb
139
159
  - lib/poefy/conditional_satisfaction.rb
160
+ - lib/poefy/core_extensions/array.rb
140
161
  - lib/poefy/database.rb
141
162
  - lib/poefy/generation.rb
142
163
  - lib/poefy/handle_error.rb
@@ -169,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
190
  version: '0'
170
191
  requirements: []
171
192
  rubyforge_project:
172
- rubygems_version: 2.6.11
193
+ rubygems_version: 2.5.2
173
194
  signing_key:
174
195
  specification_version: 4
175
196
  summary: Create rhyming poetry by rearranging lines of text