Skip to content

Instantly share code, notes, and snippets.

@presidentbeef
Created June 8, 2009 12:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save presidentbeef/125781 to your computer and use it in GitHub Desktop.
Save presidentbeef/125781 to your computer and use it in GitHub Desktop.
#A little Twitter thing to post random quotes from Edsger Dijkstra
require 'yaml'
require 'open-uri'
require 'twitter' #twitter4r gem
require 'hpricot'
class DijkstraQuote
class << self
#Match the website's naming scheme
def random_ewd
(rand(1289) + 30).to_s.rjust(4, "0")
end
#Get a random quote
def get_quote
quote = nil
while quote.nil? do
quote = fetch random_ewd
end
quote
end
#Get a random quote from the specified set of notes
def fetch ewd
#Check if we've already retrieved this set of notes
if File.exists? "ewd#{ewd}"
quotes = YAML.load_file "ewd#{ewd}"
quotes[rand quotes.length]
else
$stderr.puts "Fetching EWD#{ewd}..." if $DEBUG
#Fetch a transcript of Dijkstra's notes
begin
file = open("http://www.cs.utexas.edu/~EWD/transcriptions/EWD#{ewd[0,2]}xx/EWD#{ewd}.html") { |f| Hpricot(f) }
rescue OpenURI::HTTPError
$stderr.puts "Not found" if $DEBUG
return nil
end
text = file.to_plain_text
#Pick some sentences that seem good
lines = text.split(/\.(?:\s+|\n+)/).map do |l|
l.gsub(/\t|\n|\r/, " ").squeeze(" ").strip
end.select do |l|
l.length > 40 and l.length < 140 and l[0,1] == l[0,1].upcase and l[-3, 3] != "viz"
end
#Cache them for later
File.open "ewd#{ewd}", "w" do |f|
YAML.dump lines, f
end
#Return a random sentence
lines[rand lines.length]
end
end
#(Very crudely) tries to find a quote that is related to the message.
#Note that this only searches the cache.
def find_related message
#Get the longer words
words = message.gsub(/[^a-zA-Z ]/, "").split.select { |w| w.length > 4 }
quote = nil
if words.length > 0
word = /#{Regexp.union(words)}/i
#Check local files for the search word
Dir.glob("ewd[0-9][0-9][0-9][0-9]").find do |f|
text = File.read f
if text =~ word
#Get the list of quotes and grab one
quotes = YAML.load_file f
matches = quotes.grep word
quote = matches[rand(matches.length)]
else
false
end
end
else
quote = get_quote
end
quote
end
end
end
#Post to Twitter
class DijkstraTwitter
def initialize
@twitter = Twitter::Client.new :login => "?", :password => "?"
end
#Post a random quote. If _ask_ is true, asks for approval first
def post_random ask = false
quote = DijkstraQuote.get_quote
if ask and ask_permission("Would you like to post this: \"#{quote}\"") or not ask
@twitter.status :post, quote
end
end
#Check unanswered @ewd messages and come up with responses
def post_replies ask = false
require 'set'
#Keep track of what has been replied to already
if File.exist? "ewdreplies"
replied = YAML.load_file "ewdreplies"
else
replied = Set.new
end
replies = @twitter.status(:replies)
replies.each do |status|
status_id = status.id.to_s
next if replied.include? status_id
message = status.text
user = status.user.screen_name
if reply_to message, user, ask
replied << status_id
end
end
File.open "ewdreplies", "w" do |f|
YAML.dump replied, f
end
end
#Send a reply if we can find one
def reply_to message, sender, ask = false
puts "Responding to \"#{message}\""
quote = DijkstraQuote.find_related message
if not quote
puts "Nothing related. Skipping."
return false
elsif ask and ask_permission("Would you like to post this: \"#{quote}\"") or not ask
response = "@#{sender} #{quote}"
if response.length > 140
response = response[0,140]
end
@twitter.status(:post, "@#{sender} #{quote}")
true
else
ask and ask_permission "Ignore this reply?"
end
end
#Ask the user a question
def ask_permission message
puts message
response = nil
until response =~ /^(y|n)/i
print "(Y/N): "
response = gets
end
$1.downcase == "y"
end
end
#Try it out
puts DijkstraQuote.get_quote
#dt = DijkstraTwitter.new
##dt.post_random true
##dt.post_replies true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment