Class: Kirby

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/kirby.rb

Overview

In-channel commands:

>> [string of code]

Evaluate some Ruby code.

reset_irb

Reset the irb session.

add_svn [repository_url]

Watch an svn repository for changes.

Constant Summary collapse

PATH =
Pathname.new(".").dirname.realpath.to_s
STORE =
PATH + '/kirby.repositories'
ATOM =
PATH + '/kirby.atoms'
PIDFILE =
PATH + '/kirby.pid'
NICK =
(ARGV[1] or "kirby-dev")
CHANNEL =
("#" + (ARGV[2] or "kirby-dev"))
SERVER =
(ARGV[3] or "irc.freenode.org")
SILENT =
ARGV[6] == "--silent"

Instance Method Summary collapse

Instance Method Details

#connectObject

Connect to the IRC server.



34
35
36
37
38
39
# File 'lib/kirby.rb', line 34

def connect
  @socket = TCPSocket.new(SERVER, 6667)
  write "USER #{[NICK]*3*" "} :#{NICK}"
  write "NICK #{NICK}"
  write "JOIN #{CHANNEL}"
end

#listenObject

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).



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/kirby.rb', line 42

def listen
  @socket.each do |line|
#      puts "GOT: #{line.inspect}"
    poll unless SILENT
    case line.strip
      when /^PING/ then write line.sub("PING", "PONG")[0..-3]
      when /^ERROR/, /KICK #{CHANNEL} #{NICK} / then restart unless line =~ /PRIVMSG/
      else 
        if msg = line[/ PRIVMSG #{CHANNEL} \:(.+)/, 1]
          case msg
            when /^>>\s*(.+)/ then try $1.chop
            when /^#{NICK}/ then say "Usage: '>> CODE'. Say 'reset_irb' for a clean session. Say 'add_svn [repository_url]' to watch an svn repository and add_atom [atom_feed_url] to watch an atom feed"
            when /^reset_irb/ then reset_irb
            when /^add_svn (.+?)(\s|\r|\n|$)/ then $store[$1] = 0 and say $store.inspect
            when /^add_atom (.+?)(\s|\r|\n|$)/ then $atom[$1] = '' and say $atom.inspect
          end unless SILENT
          post($1) if DELICIOUS_PASS and msg =~ /(http:\/\/.*?)(\s|\r|\n|$)/ 
        end
    end
  end
end

#pollObject

Look for svn changes.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/kirby.rb', line 98

def poll
  return unless (Time.now - $last_poll > 15 rescue true)
  $last_poll = Time.now    
  $store.each do |repo, last|
    (Hpricot(`svn log #{repo} -rHEAD:#{last} --limit 10 --xml`)/:logentry).reverse[1..-1].each do |ci|
      $store[repo] = rev = ci.attributes['revision'].to_i
      say "Commit #{rev} to #{repo.split("/").last} by #{(ci/:author).text}: #{(ci/:msg).text}"
    end rescue nil
  end
  File.open(STORE, 'w') {|f| f.puts YAML.dump($store)}
  
  $atom.each do |feed, last|
    begin
      e = (Hpricot(open(feed))/:entry).first
      $atom[feed] = link = e.at("link")['href']
      say "#{(e/:title).text} by #{((e/:author)/:name).text} : #{link}" unless link == last
    rescue
    end
  end
  File.open(ATOM, 'w') {|f| f.puts YAML.dump($atom)}
end

#post(url) ⇒ Object

Post a url to the del.icio.us account.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/kirby.rb', line 121

def post url
  query = {:url => url,
    :description => (((Hpricot(open(url))/:title).first.innerHTML or url) rescue url),
    :tags => (Hpricot(open("http://del.icio.us/url/check?url=#{CGI.escape(url)}"))/'.alphacloud'/:a).map{|s| s.innerHTML}.join(" "),
    :replace => 'yes' }
  begin
    http = Net::HTTP.new('api.del.icio.us', 443)         
    http.use_ssl = true      
    http.start do |http|
      req = Net::HTTP::Get.new('/v1/posts/add?' + query.map{|k,v| "#{k}=#{CGI.escape(v)}"}.join('&'))
      req.basic_auth DELICIOUS_USER, DELICIOUS_PASS
      http.request(req)
    end.body
  end
end

#reset_irbObject

Get a new irb session.



84
85
86
87
# File 'lib/kirby.rb', line 84

def reset_irb
  say "Began new irb session"
  $session = try_eval("!INIT!IRB!")
end

#restartObject

Connect and reconnect to the server



25
26
27
28
29
30
31
# File 'lib/kirby.rb', line 25

def restart
  $store = (YAML.load_file STORE rescue {})
  $atom  = (YAML.load_file ATOM rescue {})
  @socket.close if @socket
  connect
  listen
end

#say(s) ⇒ Object

Say something in the channel.



78
79
80
81
# File 'lib/kirby.rb', line 78

def say s
  write "PRIVMSG #{CHANNEL} :#{s[0..450]}"
  sleep 1
end

#try(s) ⇒ Object

Eval a piece of code in the irb environment.



72
73
74
75
# File 'lib/kirby.rb', line 72

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.



90
91
92
93
94
95
# File 'lib/kirby.rb', line 90

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.

Raises:

  • (RuntimeError)


65
66
67
68
69
# File 'lib/kirby.rb', line 65

def write s
  raise RuntimeError, "No socket" unless @socket
  @socket.puts s += "\r\n"
#    puts "WROTE: #{s.inspect}"
end