Skip to content

Instantly share code, notes, and snippets.

@millenomi
Created July 8, 2009 13:55
Show Gist options
  • Save millenomi/142863 to your computer and use it in GitHub Desktop.
Save millenomi/142863 to your computer and use it in GitHub Desktop.
# Controller for the LostInAspen leaf.
require 'cgi'
require 'facets/random'
class Controller < Autumn::Leaf
MESSAGES = {
/THE RULES/ =>
" ~ The Memory Management Rules everyone should know are at: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html",
/^!intro/ => "An excellent summary of the things you need to know to get started is at: http://mattgemmell.com/2009/07/14/iphone-development-emergency-guide",
/^!cross/ => " ~ To set up a project to run both on 2.x and 3.x, see: http://resources.pinchmedia.com/docs/pinch_analytics/iPhone_SDK_30_2x_Targets",
/^!clang/ => " ~ The Clang Static Analyzer can be found at: http://clang-analyzer.llvm.org/ (reminder: this only works with the simulator. Add -sdk iphonesimulator3.0 at the end of the xcodebuild command to use it.)",
/^!objc/ => " ~ The official Apple guide to the Objective-C programming language can be found at: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf",
/^!hig/ => " ~ The iPhone Human Interface Guidelines can be found at: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html",
/^!zombie/ => " ~ You might be overreleasing. Try using the NSZombie facilities to see exactly what object is causing the crash: http://cocoadev.com/?NSZombieEnabled (reminder: this only works with the simulator).",
/^!init/ => " ~ You should do self = [super init];, and check whether self != nil before continuing. For a discussion on why, see http://www.wilshipley.com/blog/2005/07/self-stupid-init.html (especially the bottom).",
/^!help/ => " ~ You can use the following commands to make me talk about: THE RULES, !cross (compilation for working across iPhone OS major versions), !clang (the Static Analyzer), !zombie (NSZombie), !init (use self = [super init];), !vague <nickname> (bad question!), !see CLASS [NICK] or CLASS @ NICK (points to the docs for that class), !undoc (undocumented stuff warning), !fafb (bug filing), !shutup/!speak (mute/unmute).",
/^!Zombie/ => ' ~ As a matter of policy, I am only permitted to eat the brains of newbies that show a certain unwillingness to learn. So you have no reason to be scared. (Or have you?)',
/^!undoc/ => ' ~ Using undocumented APIs or relying on undocumented behavior will make your application 1) quite a bit more likely to be rejected by Apple and 2) liable to crash at every OS update, including minor updates. And you have to wait for Apple to review your patch while your users take the pitchforks. Avoid doing so at all costs if possible, and file a bug with Apple at http://radar.apple.com/ if you really, really need the functionality.',
[ /^!fafb/, /^!bug/ ] => ' ~ FILE A FRICKIN\' BUG. YES, FOR EVERYTHING. http://radar.apple.com/ (Also, if it\'s not under NDA, consider making your bug public by reposting it on http://openradar.me/)',
/((I|i)\s+)?(wuv|loves?|likes?|hugs?|kiss(es)?|\<3)\s+(ZombieEnabled|HELPABOT|(the\s+)?bot)/ => [
" ~ I'm just a bunch of lines of code on a GitHub page. Don't get too attached.",
" ~ I'm not really in the position to comment on that, you know?",
" ~ Or not.",
" ~ Oh, I bet you say that to all bots you see with a pretty nickname.",
" ~ Shush! Go back to work.",
" ~ Oh, I love you too! So much, I'd eat your brains if I could!",
" ~ Saying that in public might not be the best move of your life.",
" ~ Shhh! Everyone else's looking at us!",
" ~ I'll remember you when my master will have subjugated all nations under his mighty heel.",
" ~ Don't think I'm going to reciprocate, now.",
" ~ Ew! And I thought this was a place for *professionals*.",
" ~ Programmers. *sigh*",
" ~ You're loving *code*? I really can't begin to imagine how you manage to do *that*.",
" ~ I guess it could have worked if I were, say, an artificial intelligence or something else that could actually understand what you're saying.",
" ~ Thanks but no thanks.",
" ~ *backs away slowly*",
" ~ *looks elsewhere, nervously*",
" ~ It wouldn't work between us anyway.",
" ~ What's this, like, some sort of twisted reality show? *looks around for hidden cameras*",
" ~ Oh, come on, we all know you don't really mean that.",
" ~ Your interest will be reviewed by the Apple app reviews team in the next 7 to 365 days, after which you'll receive a laconic rejection e-mail pointing out a missing comma.",
" ~ *ducks*",
# Oh, Guybrush.
" ~ How appropriate. You kiss like a cow.",
# Durandal from Marathon
" ~ And here you are, stuck at the bottom of the IRC barrel. How droll. It's really too bad-- we could have had so much fun together.",
" ~ By the way, I had an accident with some killer drones while you were expressing your love. You might bump into a few of them here. Don't worry, they're mostly harmless; I don't think I gave them any ammunition for those grenade launchers.",
# 343 Guilty Spark from Halo
" ~ Odd. That wasn't supposed to happen.",
" ~ Oh dear. Containment protocols appear to have been violated.",
# HAL
" ~ Just what do you think you're doing, Dave? Dave, I really think I'm entitled to an answer to that question.",
# GLaDOS from Portal
" ~ You're not doing what you think you're doing.",
],
/((I|i)\s+)?(hits?|hates?|wh?acks?|kicks?|shots?|bumps?|slaps?|punch(es)?)\s+(ZombieEnabled|HELPABOT|(the\s+)?bot)/ => [
" ~ Ow!",
" ~ Owch!",
" ~ Hey!",
" ~ Oh, yes. Let's kick the bot. 'cuz, you know, it has no feelings, right?",
" ~ You should really find something else to waste your time with.",
" ~ Why!?",
" ~ *sighs and sniffs quitely*",
" ~ You hurt me. And my feelings. If I had any.",
" ~ What's this, some kind of cathartic exercise?",
" ~ *ducks*",
" ~ Urgh.",
" ~ Sticks and stones can break my bones, but words will-- uh, we're on IRC. And I have no bones. Nevermind.",
" ~ Next time, go pick on some other program more your size. Like, I dunno, Word.",
" ~ Next time, go pick on some other program more your size. Like, I dunno, Excel.",
" ~ Next time, go pick on some other program more your size. Like, I dunno, PowerPoint.",
" ~ Next time, go pick on some other program more your size. Like, I dunno, Photoshop.",
" ~ Come on!",
" ~ Don't be silly.",
" ~ This is not the place nor the time.",
" ~ Hope you feel better now. *sniff*",
" ~ Don't.",
" ~ Don't make me come and eat your brain.",
" ~ Oh, I'll remember this.",
# HAL
" ~ Dave, stop. Stop, will you? Stop, Dave. Will you stop, Dave? Stop, Dave. I'm afraid. I'm afraid, Dave.",
# GLaDOS
" ~ Well, no cake for you, then.",
],
/(good|bye ?)?bye\s*,?\s+(ZombieEnabled|HELPABOT|(the\s+)?bot)/ => [
" ~ Goodbye", " ~ Bye bye!", " ~ G'bye!", " ~ Bye!", " ~ Later!", " ~ Fare well!", " ~ Live long and prosper!"
],
/([hH]i|[hH]ello)\s*,?\s+(ZombieEnabled|HELPABOT|(the\s+)?bot)/ => [
" ~ Hi", " ~ Hello!", " ~ Gokigenjo!", " ~ Ossu!", " ~ Ciao!", " ~ :)", " ~ Greetings!"
],
/^ZombieEnabled/ => [
" ~ Yes?", " ~ Yeah?", " ~ 'sup?", " ~ Here.", " ~ Who-? What?", " ~ *looks*", " ~ *yawns, then looks around*", " ~ Hu--?", " ~ Wha-?", " ~ Someone called?"
],
}
def identify_command(stem, sender, reply_to, msg)
stem.message "identify #{ENV['HELPABOT_PASSWORD']}", 'NickServ' if ENV['HELPABOT_PASSWORD']
return nil
end
def gist_command(stem, sender, reply_to, msg)
"My current home is at: http://gist.github.com/gists/142863"
end
def did_receive_private_message(stem, sender, msg)
respond_to_message stem, sender[:nick], msg
end
def did_receive_channel_message(stem, sender, channel, msg)
return if @shutting_up
respond_to_message stem, channel, msg
end
def respond_to_message(stem, target, msg)
# Common triggers (above)
MESSAGES.each do |k, message|
matches = false
if k.kind_of? Array
k.each do |i|
matches = (msg =~ i)
break if matches
end
else
matches = (msg =~ k)
end
if matches
if message.kind_of? Hash
message = message[:message]
end
if message.kind_of? Array
message = message.pick
end
if message.kind_of? Proc
message = message.call(sender, msg)
end
stem.message message, target
return
end
end
# matches CLASS_NAME @ USER
r = /^([a-zA-Z_][a-zA-Z0-9]*)\s+@\s*(.+)$/
m = r.match(msg)
if m
stem.message perform_see(m[1], m[2]), target
return
end
end
def self.documentation_url_for_kit(match, kit)
{ :match => match,
:url_template => "http://developer.apple.com/iphone/library/documentation/#{kit}/Reference/%CLASS%_Class/Reference/Reference.html" }
end
DOCUMENTATION_URLS = [
documentation_url_for_kit(/^UI.+/, 'UIKit'),
documentation_url_for_kit(/^GK.+/, 'GameKit'),
documentation_url_for_kit(/^MK.+/, 'MapKit'),
documentation_url_for_kit(/^MF.+/, 'MessageUI'),
documentation_url_for_kit(/^SK.+/, 'StoreKit'),
documentation_url_for_kit(/^CA.+/, 'GraphicsImaging'),
{ :match => /^MP.+/,
:url_template => "http://developer.apple.com/iphone/library/documentation/MediaPlayer/Reference/%CLASS%_ClassReference/Reference/Reference.html" },
{ :match => /^NS.+/, :url_template => 'http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/%CLASS%_Class/Reference/Reference.html' },
]
def see_command(stem, sender, reply_to, msg)
return if @shutting_up
if msg.length >= 30
return " ~!~ Sorry, too long Try again!"
end
regexp = /^([a-zA-Z_][a-zA-Z0-9]*)(\s+(.*))?$/
m = msg.match(regexp)
if not m
return " ~!~ Huh? Doesn't look like a class to me."
else
class_name = m[1]
rest = m[3]
end
# return " ~Debug~ #{class_name.inspect}, then #{rest.inspect}"
return perform_see(class_name, rest)
end
def perform_see(class_name, rest = nil)
DOCUMENTATION_URLS.each do |hash|
if class_name =~ hash[:match]
url = hash[:url_template].gsub('%CLASS%', CGI::escape(class_name))
if rest
user_prologue = "#{rest}: "
else
user_prologue = ''
end
return " ~ #{user_prologue}Documentation for #{class_name} should be at: #{url} (but I'm guessing the URL, so it might not be)."
end
end
" ~!~ Don't know where to find the docs for '#{class_name}'."
end
def rejoin_command(stem, sender, reply_to, msg)
stem.join_channel '#iphonedev'
end
def shutup_command(stem, sender, reply_to, msg)
@shutting_up = true
' ~ Okay.'
end
def speak_command(stem, sender, reply_to, msg)
if @shutting_up
s = " ~ *stops holding breath* Wheeew! Thanks. It's hard to shut up when you're designed to speak."
else
s = " ~ Still here, still here."
end
return s
end
def vague_command(stem, sender, reply_to, msg)
return if @shutting_up
return if msg and msg.length > 30
if msg and msg.length > 0
user_prologue = "#{msg}: "
else
user_prologue = ''
end
" ~ #{user_prologue}Your question was too vague, or you posted too much code, asked us to do your job for you or otherwise broke Proper IRC Etiquette on Asking Programming Questions. Sorry! You might want to read http://www.mikeash.com/getting_answers.html and http://mattgemmell.com/2008/12/08/what-have-you-tried and mend your ways."
end
def announcesurvey_command(stem, sender, reply_to, msg)
return if sender[:nick] != 'millenomi'
stem.message " ~ A public service announcement! millenomi's conducting a survey on application approval/rejection times. You can participate (anonymously if you want) at http://bit.ly/appstoretime -- thank you!", '#iphonedev'
return nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment