ponder 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -66,13 +66,13 @@ Besides the configuration for nick, server and port as shown in the **Getting St
66
66
 
67
67
  * `logging`
68
68
 
69
- If `logging` is set to `true`, all incoming and outgoing traffic will be logged to logs/traffic.log and errors will be logged to logs/error.log. If you just want to log errors, you can manipulate the traffic logger in the configure block with `c.traffic_logger = c.empty_logger`. A logger set to `empty_logger` will not log anything.
69
+ If `logging` is set to `true`, all incoming and outgoing traffic and exceptions will be logged to logs/log.log.
70
70
 
71
- You can also define other loggers for traffic\_logger and error\_logger with `c.traffic_logger = @my_cool_logger` or `c.traffic_logger = Logger.new(...)`. Per default, there are just #info and #error called on the logger.
71
+ You can also define your own logger, use `c.logger = @my_cool_logger` or `c.logger = Logger.new(...)`. Ponder itself just uses the #info and #error methods on the logger.
72
72
 
73
- You can access the logger instances via `@ponder.traffic_logger` or `@ponder.error_logger`, so you could do: `@ponder.traffic_logger.info('I did this and that right now')`.
73
+ You can access the logger instance via `@ponder.logger`, so you could do: `@ponder.logger.info('I did this and that right now')`.
74
74
 
75
- It defaults to `false`. (TODO: write about "other" logger methods)
75
+ It defaults to `false`.
76
76
 
77
77
  * `reconnect`
78
78
 
@@ -266,6 +266,17 @@ You can have Before Filters! They are called before each event handling process
266
266
 
267
267
  This Before Filter will be called, if a channel message with the word "foo" gets in. You can use all other event types (like :query, :kick, ...) as well. Also possible is an array notation like `before_filter([:query, :channel], /foo/) ...`. If you want the filter to work an all event types, you can simply use `:all`. Filters will be called in defining order; first defined, first called. Event specific filters are called before `:all` filters.
268
268
 
269
+ You could use it for authentication/authorization. Example:
270
+
271
+ @ponder.before_filter :channel, // do |event_data|
272
+ if is_an_admin?(event_data[:nick])
273
+ event_data[:authorized_request] = true
274
+ else
275
+ event_data[:authorized_request] = false
276
+ end
277
+ end
278
+
279
+ Now, one can check for `event_data[:authorized_request]` in a callback.
269
280
  ### After Filters
270
281
  After Filters work the same way as Before Filters do, just after the actual event handling process. An After Filter does not hinder later After Filters to fire up if it returns `false`. Example:
271
282
 
@@ -322,7 +333,7 @@ The source can be found at GitHub: [tbuehlmann/ponder](http://github.com/tbuehlm
322
333
  You can contact me through [GitHub](http://github.com/tbuehlmann/ "GitHub") and IRC (named tbuehlmann in the Freenode network).
323
334
 
324
335
  ## Discworld Context
325
- So, why all that silly names? Ponder Stibbons? Thaum? Twoflogger (referring to Twoflower), BlindIO? What's the Mended Drum? Who's the Librarian? Simply put, I freaking enshrine Terry Pratchett's Discworld Novels and there were no better name for this project than Ponder. Ponder Stibbons is the Head of Inadvisably Applied Magic at the Unseen University of Ankh Morpork. He researched the Thaum, like the atom, just for magic. And I just love that character, so there we are. If you're a fan too or want to talk about the Discworld, the framework, whatever, don't hesitate to contact me.
336
+ So, why all that silly names? Ponder Stibbons? Thaum? Twoflogger (referring to Twoflower), BlindIo? What's the Mended Drum? Who's the Librarian? Simply put, I freaking enshrine Terry Pratchett's Discworld Novels and there were no better name for this project than Ponder. Ponder Stibbons is the Head of Inadvisably Applied Magic at the Unseen University of Ankh Morpork. He researched the Thaum, like the atom, just for magic. And I just love that character, so there we are. If you're a fan too or want to talk about the Discworld, the framework, whatever, don't hesitate to contact me.
326
337
 
327
338
  ## License
328
339
  Copyright (c) 2010, 2011 Tobias Bühlmann
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ task :test do
4
+ require 'test/test_async_irc.rb'
5
+ require 'test/test_callback.rb'
6
+ require 'test/test_irc.rb'
7
+ end
8
+
9
+ task :default => :test
10
+
data/examples/echo.rb CHANGED
@@ -1,5 +1,4 @@
1
- require 'pathname'
2
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path.join('..', 'lib')
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
2
 
4
3
  require 'ponder'
5
4
 
@@ -23,3 +22,4 @@ end
23
22
  end
24
23
 
25
24
  @ponder.connect
25
+
@@ -1,8 +1,7 @@
1
- require 'pathname'
2
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path.join('..', 'lib')
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
2
 
4
- require 'ponder'
5
3
  require 'rubygems'
4
+ require 'ponder'
6
5
  require 'nokogiri'
7
6
  require 'open-uri'
8
7
 
@@ -10,11 +9,11 @@ require 'open-uri'
10
9
  @ponder = Ponder::Thaum.new
11
10
 
12
11
  @ponder.configure do |c|
13
- c.server = 'chat.freenode.org'
14
- c.port = 6667
15
- c.nick = 'Ponder'
16
- c.verbose = true
17
- c.logging = false
12
+ c.server = 'chat.freenode.org'
13
+ c.port = 6667
14
+ c.nick = 'Ponder'
15
+ c.verbose = true
16
+ c.logging = false
18
17
  end
19
18
 
20
19
  @ponder.on :connect do
@@ -22,10 +21,11 @@ end
22
21
  end
23
22
 
24
23
  @ponder.on :channel, /^blog\?$/ do |event_data|
25
- doc = Nokogiri::HTML(open('http://github.com/blog'))
26
- title = doc.xpath('//html/body/div/div[2]/div/div/ul/li/h2/a')[0].text
27
-
24
+ doc = Nokogiri::HTML(open('https://github.com/blog'))
25
+ title = doc.xpath('/html/body/div/div[2]/div/div/ul/li/h2/a')[0].text
26
+
28
27
  @ponder.message event_data[:channel], "Newest Github Blog Post: #{title}"
29
28
  end
30
29
 
31
30
  @ponder.connect
31
+
@@ -3,10 +3,10 @@
3
3
  #
4
4
  # The redis server version needs to be >= 1.3.10 for hash support.
5
5
 
6
- require 'pathname'
7
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path.join('..', 'lib')
8
- require 'ponder'
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+
9
8
  require 'rubygems'
9
+ require 'ponder'
10
10
  require 'redis'
11
11
 
12
12
  FORMAT = '%Y-%m-%d %H:%M:%S'
@@ -17,28 +17,29 @@ class String
17
17
  end
18
18
  end
19
19
 
20
- @last_seen = Redis.new(:thread_safe => true)
20
+ @redis = Redis.new(:thread_safe => true)
21
21
 
22
22
  def remember(lowercase_nick, nick, user, host, channel, action,
23
23
  action_content)
24
- @last_seen.hmset(lowercase_nick,
25
- 'nick', nick,
26
- 'user', user,
27
- 'host', host,
28
- 'channel', channel,
29
- 'action', action,
30
- 'action_content', action_content,
31
- 'updated_at', Time.now.to_i)
24
+ @redis.hmset(
25
+ lowercase_nick,
26
+ 'nick', nick,
27
+ 'user', user,
28
+ 'host', host,
29
+ 'channel', channel,
30
+ 'action', action,
31
+ 'action_content', action_content,
32
+ 'updated_at', Time.now.to_i)
32
33
  end
33
34
 
34
35
  @ponder = Ponder::Thaum.new
35
36
 
36
37
  @ponder.configure do |c|
37
- c.server = 'chat.freenode.org'
38
- c.port = 6667
39
- c.nick = 'Ponder'
40
- c.verbose = true
41
- c.logging = false
38
+ c.server = 'chat.freenode.org'
39
+ c.port = 6667
40
+ c.nick = 'Ponder'
41
+ c.verbose = true
42
+ c.logging = false
42
43
  end
43
44
 
44
45
  @ponder.on :connect do
@@ -76,9 +77,9 @@ end
76
77
  "#{event_data[:nick]} #{event_data[:reason]}")
77
78
  end
78
79
 
79
- def last_seen(nick, event_data)
80
- data = @last_seen.hgetall nick
81
-
80
+ def last_seen(nick)
81
+ data = @redis.hgetall(nick)
82
+
82
83
  case data['action']
83
84
  when 'channel'
84
85
  "#{data['nick']} wrote something in #{data['channel']} at #{Time.at(data['updated_at'].to_i).strftime(FORMAT)}."
@@ -101,21 +102,21 @@ end
101
102
 
102
103
  @ponder.on :channel, /^!seen \S+$/ do |event_data|
103
104
  nick = event_data[:message].split(' ')[1].downcase
104
-
105
+
105
106
  # wildcards
106
107
  if nick =~ /\*/
107
- users = @last_seen.keys nick.escape_redis
108
+ users = @redis.keys nick.escape_redis
108
109
  results = users.length
109
-
110
+
110
111
  case results
111
112
  when 0
112
113
  @ponder.message event_data[:channel], 'No such nick found.'
113
114
  when 1
114
- @ponder.message last_seen(users[0])
115
+ @ponder.message event_data[:channel], last_seen(users[0])
115
116
  when 2..5
116
117
  nicks = []
117
118
  users.each do |user|
118
- nicks << @last_seen.hgetall(user)['nick']
119
+ nicks << @redis.hgetall(user)['nick']
119
120
  end
120
121
  nicks = nicks.join(', ')
121
122
  @ponder.message event_data[:channel], "#{results} nicks found (#{nicks})."
@@ -123,8 +124,8 @@ end
123
124
  @ponder.message event_data[:channel], "Too many results (#{results})."
124
125
  end
125
126
  # single search
126
- elsif @last_seen.exists nick
127
- msg = last_seen(nick, event_data)
127
+ elsif @redis.exists nick
128
+ msg = last_seen(nick)
128
129
  if online_nick = @ponder.whois(nick)
129
130
  msg = "#{online_nick[:nick]} is online. (#{msg})"
130
131
  end
data/lib/ponder.rb CHANGED
@@ -1,22 +1,11 @@
1
- require 'pathname'
2
- require 'rubygems'
3
-
4
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
2
 
6
3
  module Ponder
7
- def self.root
8
- Pathname.new($0).dirname.expand_path
9
- end
10
-
11
- require 'ponder/version'
12
- require 'ponder/thaum'
13
- require 'ponder/formatting'
14
- require 'ponder/logger/blind_io'
15
-
16
- if RUBY_VERSION < '1.9'
17
- require 'ruby/1.8/string'
18
- require 'ponder/logger/twoflogger18'
19
- else
20
- require 'ponder/logger/twoflogger'
21
- end
4
+ ROOT = File.dirname($0)
5
+
6
+ autoload :Filter, 'ponder/filter'
7
+ autoload :Formatting, 'ponder/formatting'
8
+ autoload :Thaum, 'ponder/thaum'
9
+ autoload :VERSION, 'ponder/version'
22
10
  end
11
+
@@ -1,37 +1,41 @@
1
+ require 'rubygems'
1
2
  require 'eventmachine'
2
3
 
3
4
  module Ponder
4
5
  class Connection < EventMachine::Connection
5
6
  include EventMachine::Protocols::LineText2
6
-
7
+
7
8
  def initialize(thaum)
8
9
  @thaum = thaum
9
10
  end
10
-
11
+
11
12
  def connection_completed
12
13
  @thaum.register
13
14
  end
14
-
15
+
15
16
  def unbind
16
17
  @thaum.connected = false
17
- @thaum.process_callbacks :disconnect
18
- @thaum.traffic_logger.info '-- Ponder disconnected'
18
+ @thaum.process_callbacks :disconnect, {}
19
+ @thaum.logger.info '-- Ponder disconnected'
19
20
  @thaum.console_logger.info '-- Ponder disconnected'
20
-
21
+
21
22
  if @thaum.config.reconnect
22
- @thaum.traffic_logger.info "-- Reconnecting in #{@thaum.config.reconnect_interval} seconds"
23
+ @thaum.logger.info "-- Reconnecting in #{@thaum.config.reconnect_interval} seconds"
23
24
  @thaum.console_logger.info "-- Reconnecting in #{@thaum.config.reconnect_interval} seconds"
24
-
25
+
25
26
  EventMachine::add_timer(@thaum.config.reconnect_interval) do
26
27
  reconnect @thaum.config.server, @thaum.config.port
27
28
  end
28
29
  else
29
30
  EventMachine::stop_event_loop
31
+ @thaum.logger.close
32
+ @thaum.console_logger.close
30
33
  end
31
34
  end
32
-
35
+
33
36
  def receive_line(line)
34
- @thaum.parse line.force_encoding('utf-8')
37
+ @thaum.parse line
35
38
  end
36
39
  end
37
40
  end
41
+
data/lib/ponder/irc.rb CHANGED
@@ -3,7 +3,7 @@ module Ponder
3
3
  # raw IRC messages
4
4
  def raw(message)
5
5
  @connection.send_data "#{message}\r\n"
6
- @traffic_logger.info ">> #{message}"
6
+ @logger.info ">> #{message}"
7
7
  @console_logger.info ">> #{message}"
8
8
  end
9
9
 
@@ -1,11 +1,25 @@
1
1
  module Ponder
2
- module Logger
3
- class BlindIo
4
- def initialize
5
- [:debug, :info, :warn, :error, :fatal, :unknown, :start_logging, :stop_logging].each do |method_name|
6
- self.class.send(:define_method, method_name, Proc.new { |*args| nil })
7
- end
8
- end
2
+ class BlindIo
3
+ def debug(*args, &block)
4
+ end
5
+
6
+ def info(*args, &block)
7
+ end
8
+
9
+ def warn(*args, &block)
10
+ end
11
+
12
+ def error(*args, &block)
13
+ end
14
+
15
+ def fatal(*args, &block)
16
+ end
17
+
18
+ def unknown(*args, &block)
19
+ end
20
+
21
+ def method_missing(*args, &block)
9
22
  end
10
23
  end
11
24
  end
25
+
@@ -1,93 +1,13 @@
1
- require 'pathname'
2
- require 'thread'
3
- autoload :FileUtils, 'fileutils'
1
+ require 'logger'
4
2
 
5
3
  module Ponder
6
- module Logger
7
- class Twoflogger
8
- attr_accessor :level, :levels, :time_format
9
-
10
- def initialize(destination = Ponder.root.join('logs', 'log.log'), level = :debug, time_format = '%Y-%m-%d %H:%M:%S', levels = {:debug => 0, :info => 1, :warn => 2, :error => 3, :fatal => 4, :unknown => 5})
11
- @level = level
12
- @time_format = time_format
13
- @levels = levels
14
- @queue = Queue.new
15
- @mutex = Mutex.new
16
- @running = false
17
-
18
- define_level_shorthand_methods
19
- self.log_dev = destination
20
- end
21
-
22
- def start_logging
23
- @running = true
24
- @thread = Thread.new do
25
- begin
26
- while @running do
27
- write(@queue.pop)
28
- end
29
- ensure
30
- @log_dev.close if @log_dev.is_a?(File)
31
- end
32
- end
33
- end
34
-
35
- def stop_logging
36
- @running = false
37
- end
38
-
39
- def log_dev=(destination)
40
- stop_logging
41
-
42
- if destination.is_a?(Pathname)
43
- unless destination.exist?
44
- unless destination.dirname.directory?
45
- FileUtils.mkdir_p destination.dirname
46
- end
47
-
48
- File.new(destination, 'w+')
49
- end
50
- @log_dev = File.open(destination, 'a+')
51
- @log_dev.sync = true
52
- elsif destination.is_a?(IO)
53
- @log_dev = destination
54
- else
55
- raise TypeError, 'need a Pathname or IO'
56
- end
57
- end
58
-
59
- private
60
-
61
- def define_level_shorthand_methods
62
- @levels.each_pair do |level_name, severity|
63
- self.class.send(:define_method, level_name, Proc.new { |*messages| queue(severity, *messages) })
64
- end
65
- end
66
-
67
- def queue(severity, *messages)
68
- raise(ArgumentError, 'Need a message') if messages.empty?
69
- raise(ArgumentError, 'Need messages that respond to #to_s') if messages.any? { |message| !message.respond_to?(:to_s) }
70
-
71
- if severity >= @levels[@level]
72
- message_hashes = messages.map { |message| {:severity => severity, :message => message} }
73
-
74
- @mutex.synchronize do
75
- message_hashes.each do |hash|
76
- @queue << hash
77
- end
78
- end
79
- end
80
- end
81
-
82
- def write(*message_hashes)
83
- begin
84
- message_hashes.each do |hash|
85
- @log_dev.puts "#{@levels.key(hash[:severity])} #{Time.now.strftime(@time_format)} #{hash[:message]}"
86
- end
87
- rescue => e
88
- puts e.message, *e.backtrace
89
- end
4
+ class Twoflogger < Logger
5
+ def initialize(*args)
6
+ super(*args)
7
+ self.formatter = proc do |severity, datetime, progname, msg|
8
+ "#{severity} #{datetime.strftime('%Y-%m-%d %H:%M:%S')} #{msg}\n"
90
9
  end
91
10
  end
92
11
  end
93
12
  end
13
+