Class: Kirby
- Inherits:
-
Object
- Object
- Kirby
- Defined in:
- lib/kirby.rb
Overview
In-channel commands:
>> CODE
-
evaluate code in IRB.
reset_irb
-
get a clean IRB session.
add_svn [repository_url]
-
watch an SVN repository.
add_atom [atom_feed_url]
-
watch an atom feed, such as a Git repository
To remove a repository, manually kill the bot and delete the line from nick.svns
or nick.atoms
in the bot’s working directory. Then restart the bot.
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
Instance Method Summary collapse
-
#connect ⇒ Object
Connect to the IRC server.
-
#initialize(opts = {}) ⇒ Kirby
constructor
Make a new Kirby.
-
#listen ⇒ Object
The event loop.
-
#log(s) ⇒ Object
Write a string to the log, if the logfile is open.
-
#poll ⇒ Object
Look for SVN changes.
-
#post(url) ⇒ Object
Post a url to the del.i cio.us account.
-
#reset_irb ⇒ Object
Get a new
irb
session. -
#restart ⇒ Object
Connect and reconnect to the server.
-
#say(s) ⇒ Object
Say something in the channel.
-
#try(s) ⇒ Object
Eval a piece of code in the
irb
environment. -
#try_eval(s) ⇒ Object
Inner loop of the try method.
-
#write(s) ⇒ Object
Send a raw string to the server.
Constructor Details
#initialize(opts = {}) ⇒ Kirby
Make a new Kirby. Will not connect to the server until you call connect().
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 |
# File 'lib/kirby.rb', line 18 def initialize(opts = {}) # Defaults path = File.(".").to_s nick = opts[:nick] || config[:nick] || "kirby-dev" @config ||= { :svns => "#{path}/#{nick}.svns", :atoms => "#{path}/#{nick}.atoms", :pidfile => "#{path}/#{nick}.pid", :nick => nick, :channel => 'kirby-dev', :server => "irc.freenode.org", :delicious_user => nil, :delicious_pass => nil, :silent => false, :log => false, :logfile => "#{path}/#{nick}.log", :time_format => '%Y/%m/%d %H:%M:%S', :debug => false } # Nicely merge current options opts.each do |key, value| config[key] = value if value end end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
15 16 17 |
# File 'lib/kirby.rb', line 15 def config @config end |
Instance Method Details
#connect ⇒ Object
Connect to the IRC server.
60 61 62 63 64 65 66 |
# File 'lib/kirby.rb', line 60 def connect log "Connecting" @socket = TCPSocket.new(config[:server], 6667) write "USER #{config[:nick]} #{config[:nick]} #{config[:nick]} :#{config[:nick]}" write "NICK #{config[:nick]}" write "JOIN ##{config[:channel]}" end |
#listen ⇒ Object
The event loop. Waits for socket traffic, and then responds to it. The server sends PING
every 3 minutes, which means we don’t need a separate thread to check for svn updates. All we do is wake on ping (or channel talking).
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 |
# File 'lib/kirby.rb', line 69 def listen @socket.each do |line| puts "GOT: #{line.inspect}" if config[:debug] poll if !config[:silent] case line.strip when /^PING/ write line.sub("PING", "PONG")[0..-3] when /^ERROR/, /KICK ##{config[:channel]} #{config[:nick]} / restart unless line =~ /PRIVMSG/ when /:(.+?)!.* PRIVMSG ##{config[:channel]} \:\001ACTION (.+)\001/ log "* #{$1} #{$2}" when /:(.+?)!.* PRIVMSG ##{config[:channel]} \:(.+)/ nick, msg = $1, $2 log "<#{nick}> #{msg}" if !config[:silent] case msg when /^>>\s*(.+)/ then try $1 when /^#{config[:nick]}:/ ["Usage:", " '>> CODE': evaluate code in IRB", " 'reset_irb': get a clean IRB session", " 'add_svn [repository_url]': watch an SVN repository", " 'add_atom [atom_feed_url]': watch an atom feed, such as a Git repository"].each {|s| say s} when /^reset_irb/ then reset_irb when /^add_svn (.+?)(\s|\r|\n|$)/ then @svns[$1] = 0 and say @svns.inspect when /^add_atom (.+?)(\s|\r|\n|$)/ then @atoms[$1] = '' and say @atoms.inspect when /(http(s|):\/\/.*?)(\s|\r|\n|$)/ then post($1) if config[:delicious_pass] end end end end end |
#log(s) ⇒ Object
Write a string to the log, if the logfile is open.
106 107 108 109 110 111 112 113 114 |
# File 'lib/kirby.rb', line 106 def log s # Open log, if necessary if config[:log] puts "LOG: #{s}" if config[:debug] File.open(config[:logfile], 'a') do |f| f.puts "#{Time.now.strftime(config[:time_format])} #{s}" end end end |
#poll ⇒ Object
Look for SVN changes. Note that Rubyforge polls much better if you use the http:// protocol instead of the svn:// protocol for your repository.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/kirby.rb', line 144 def poll return unless (Time.now - $last_poll > 60 rescue true) $last_poll = Time.now @svns.each do |repo, last| puts "POLL: #{repo}" if config[:debug] (Hpricot(`svn log #{repo} -rHEAD:#{last} --limit 10 --xml`)/:logentry).reverse[1..-1].each do |ci| @svns[repo] = rev = ci.attributes['revision'].to_i project = repo.split(/\.|\//).reject do |path| ['trunk', 'rubyforge', 'svn', 'org', 'com', 'net', 'http:', nil].include? path end.last say "Commit #{rev} to #{project || repo} by #{(ci/:author).text}: #{(ci/:msg).text}" end rescue nil end File.open(config[:svns], 'w') {|f| f.puts YAML.dump(@svns)} @atoms.each do |feed, last| puts "POLL: #{feed}" if config[:debug] begin e = (Hpricot(open(feed))/:entry).first @atoms[feed] = link = e.at("link")['href'] say "Commit #{link} by #{((e/:author)/:name).text}: #{(e/:title).text}" unless link == last rescue end end File.open(config[:atoms], 'w') {|f| f.puts YAML.dump(@atoms)} end |
#post(url) ⇒ Object
Post a url to the del.i cio.us account.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/kirby.rb', line 172 def post url Timeout.timeout(60) do puts "POST: #{url}" if config[:debug] = (Hpricot(open("http://del.icio.us/url/check?url=#{CGI.escape(url)}"))/ '#top-tags'/'li')[0..10].map do |li| (li/'span').innerHTML[/(.*?)<em/, 1] end.join(" ") puts "POST-TAGS: #{}" if config[:debug] description = begin Timeout.timeout(5) do (((Hpricot(open(url))/:title).first.innerHTML or url) rescue url) end rescue Timeout::Error puts "POST: URL timeout" if config[:debug] url end query = { :url => url, :description => description, :tags => , :replace => 'yes' } http = Net::HTTP.new('api.del.icio.us', 443) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE response = http.start do |http| post_url = '/v1/posts/add?' + query.map {|k,v| "#{k}=#{CGI.escape(v)}"}.join('&') puts "POST: post url #{post_url}" if config[:debug] req = Net::HTTP::Get.new(post_url, {"User-Agent" => "Kirby"}) req.basic_auth config[:delicious_user], config[:delicious_pass] http.request(req) end.body puts "POST: #{response.inspect}" if config[:debug] end rescue Exception => e puts "POST: #{e.inspect}" if config[:debug] end |
#reset_irb ⇒ Object
Get a new irb
session.
130 131 132 133 |
# File 'lib/kirby.rb', line 130 def reset_irb say "Began new irb session" @session = try_eval("!INIT!IRB!") end |
#restart ⇒ Object
Connect and reconnect to the server
47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/kirby.rb', line 47 def restart log "Restarting" puts config.inspect if config[:debug] @svns = (YAML.load_file config[:svns] rescue {}) @atoms = (YAML.load_file config[:atoms] rescue {}) @socket.close if @socket connect listen end |
#say(s) ⇒ Object
Say something in the channel.
123 124 125 126 127 |
# File 'lib/kirby.rb', line 123 def say s write "PRIVMSG ##{config[:channel]} :#{s[0..450]}" log "<#{config[:nick]}> #{s}" sleep 1 end |
#try(s) ⇒ Object
Eval a piece of code in the irb
environment.
117 118 119 120 |
# File 'lib/kirby.rb', line 117 def try s reset_irb unless @session try_eval(s).select{|e| e !~ /^\s+from .+\:\d+(\:|$)/}.each {|e| say e} rescue say "session error" end |
#try_eval(s) ⇒ Object
Inner loop of the try method.
136 137 138 139 140 141 |
# File 'lib/kirby.rb', line 136 def try_eval s reset_irb and return [] if s.strip == "exit" result = open("http://tryruby.hobix.com/irb?cmd=#{CGI.escape(s)}", {'Cookie' => "_session_id=#{@session}"}).read result[/^Your session has been closed/] ? (reset_irb and try_eval s) : result.split("\n") end |
#write(s) ⇒ Object
Send a raw string to the server.
99 100 101 102 103 |
# File 'lib/kirby.rb', line 99 def write s raise RuntimeError, "No socket" unless @socket @socket.puts s += "\r\n" puts "WROTE: #{s.inspect}" if config[:debug] end |