Andrew McDonough

London-based ruby developer, co-founder and CTO of Tribesports

Ruby Poetry

On Tuesday evening, I gave a 20 slide ‘lightning talk’ at the London Ruby Users Group (LRUG) entitled “Ruby Poetry”. Inspired by Murray Steele’s ”My First Ruby” talk at a previous LRUG, I decided to tell a story about a small progam I wrote about five years ago, when I was fairly new to Ruby. At the time, I had just made the transition to Ruby after years as Java developer, and I was amazed at how easy it was to solve problems without having to write very much code.

The story starts when I was invited to a party. The party was a themed Burns Night dinner. These celebrations are common in Scotland to celebrate the life and poetry of Robert Burns. I had been invited to the same party the previous year, and remembered back to enjoying the haggis and whisky. One thing I recalled that had not felt particularly comfortable with, is that I had been asked to bring a poem to read. On the evening, instead of bringing poems from books, most people had written their own, and I felt bad for lacking creativity. I decided that this time around, I would try to be creative in my own way, and wrote a Ruby program to generate some topical poetry from the day’s news headlines. I won’t go into too much detail here, as my five minute talk was kindly videoed by Skills Matter:

generate_topical_rhyming_couplets.rb

The code below is what I used to generate the couplets on the day. While I had been tuning my algorithm, I wrote the headlines to a file so I didn’t have to reload them each time. The full source is on github.

generate_topical_rhyming_couplets
1
2
3
4
5
6
7
8
9
10
11
12
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
#!/usr/bin/env ruby
require 'rss'
require 'open-uri'

# Open the list of feeds
fh = open("feeds.txt")
feeds = fh.read.split "\n"

# For each feed, get the headlines
headlines = []
feeds.each do |feed|
  begin
    file = open(feed)
    rss = RSS::Parser.parse(file.read)
    feed_headlines = rss.items.map {|i| i.title}
    headlines += feed_headlines
  rescue
    puts "Error with #{feed}"
  end
end

# Remove duplicates and strip some prefixes
headlines = headlines.uniq!
headlines = headlines.map {|h| h.gsub /^(AUDIO|VIDEO): /,""}

# Test for couplets
def couplet?(a,b)
  as = a.gsub /\W/,"" # Ignore punctuation
  bs = b.gsub /\W/,""
  as[-3,3] == bs[-3,3] &&
    !(as[-5,5] == bs[-5,5]) &&
    (as.length - bs.length).abs < 10 &&
    (as.length > 30 && as.length < 70) &&
    (bs.length > 30 && bs.length < 70)
end

# Sort the headlines by the last three letters
headlines.sort! {|a,b|  a[-3,3] <=> b[-3,3] }

# Iterate over the headlines, testing in pairs for couplets
i = 0
while (i < headlines.length-2) do
  a = headlines[i]
  b = headlines[i+1]
  if couplet?(a,b)
    i += 1
    puts "#{a}\n#{b}\n\n"
  end
  i += 1
end

As the couplet finding algorithm was fairly crude, only looking for matches of the last three letters, and not the phonetic representation, I allowed myself to pick the best couplets as generated on the day. To demonstrate my code, I reran the program on the day of my talk, and read the best couplets it generated at the end of my presentation:

The final poem, as generated on the day of the talk

Eurozone agrees second Greek bail-out Haye trainer rules out Chisora bout Man released after Sunday arrest South Sudan puts Beijing policies to the test Young carers need more support Green light for £100m golf resort Lord of the Flies redesigned ‘Typosquatting’ prize firms fined Football with history of conflict Travel by train though the Lake District Storm at C-word in BBC weather forecast Top Irish dancers set for Belfast Are there more strikes on the way? I love my ID card. Can they really be taking it away? London ‘second best study city’ Oil sector ‘needs tax stability’ Ants remember their enemy’s scent That’s enough ‘kicking ass’ Mr President One-minute World News Performance poetry - your reviews

I particularly like the last one, which like the others, was genuinely generated on the day.

So the two talks I have given at LRUG have been entitled Ruby Poetry and Ruby Golf. What Ruby <insert word here> should I do next?



Update 1: Matt Westcott uses the generated couplets as lyrics to a song. Amazing: http://fawm.org/songs/29365

Update 2: Sebastian Spier forked the code, wrote some documentation, refactored it, and wrote a script to output HTML with headlines linking to the original news sources.

Tribesports is hiring developers in London. Find out more here.

Comments