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/lib/ponder/thaum.rb CHANGED
@@ -1,83 +1,88 @@
1
+ require 'ponder/async_irc'
1
2
  require 'ponder/callback'
2
3
  require 'ponder/connection'
3
4
  require 'ponder/irc'
4
- require 'ponder/async_irc'
5
- require 'ponder/filter'
5
+ require 'ponder/logger/twoflogger'
6
+ require 'ponder/logger/blind_io'
6
7
  require 'ostruct'
8
+ autoload :FileUtils, 'fileutils'
7
9
 
8
10
  module Ponder
9
11
  class Thaum
10
12
  include IRC
11
13
  include AsyncIRC
12
-
13
- if RUBY_VERSION >= '1.9'
14
- require 'ponder/delegate'
15
- include Delegate
16
- end
17
-
14
+
18
15
  attr_reader :config
19
- attr_accessor :connected, :traffic_logger, :error_logger, :console_logger, :empty_logger
20
-
16
+ attr_accessor :connected, :logger, :console_logger
17
+
21
18
  def initialize
22
- @config = OpenStruct.new(:server => 'localhost',
23
- :port => 6667,
24
- :nick => 'Ponder',
25
- :username => 'Ponder',
26
- :real_name => 'Ponder',
27
- :verbose => true,
28
- :logging => false,
29
- :reconnect => true,
30
- :reconnect_interval => 30
31
- )
32
-
33
- @empty_logger = Logger::BlindIo.new
34
- @traffic_logger = @empty_logger
35
- @error_logger = @empty_logger
36
- @console_logger = Logger::Twoflogger.new($stdout)
37
-
19
+ @config = OpenStruct.new(
20
+ :server => 'localhost',
21
+ :port => 6667,
22
+ :nick => 'Ponder',
23
+ :username => 'Ponder',
24
+ :real_name => 'Ponder',
25
+ :verbose => true,
26
+ :logging => false,
27
+ :reconnect => true,
28
+ :reconnect_interval => 30
29
+ )
30
+
31
+ @logger = BlindIo.new
32
+ @console_logger = Twoflogger.new($stdout)
33
+
38
34
  @observer_queues = {}
39
-
35
+
40
36
  @connected = false
41
37
  @reloading = false
42
-
38
+
43
39
  # user callbacks
44
40
  @callbacks = Hash.new { |hash, key| hash[key] = [] }
45
-
41
+
46
42
  # standard callbacks for PING, VERSION, TIME and Nickname is already in use
47
- on :query, /^\001PING \d+\001$/ do |env|
48
- time = env[:message].scan(/\d+/)[0]
49
- notice env[:nick], "\001PING #{time}\001"
43
+ on :query, /^\001PING \d+\001$/ do |event_data|
44
+ time = event_data[:message].scan(/\d+/)[0]
45
+ notice event_data[:nick], "\001PING #{time}\001"
50
46
  end
51
-
52
- on :query, /^\001VERSION\001$/ do |env|
53
- notice env[:nick], "\001VERSION Ponder #{Ponder::VERSION} (http://github.com/tbuehlmann/ponder)\001"
47
+
48
+ on :query, /^\001VERSION\001$/ do |event_data|
49
+ notice event_data[:nick], "\001VERSION Ponder #{Ponder::VERSION} (http://github.com/tbuehlmann/ponder)\001"
54
50
  end
55
-
56
- on :query, /^\001TIME\001$/ do |env|
57
- notice env[:nick], "\001TIME #{Time.now.strftime('%a %b %d %H:%M:%S %Y')}\001"
51
+
52
+ on :query, /^\001TIME\001$/ do |event_data|
53
+ notice event_data[:nick], "\001TIME #{Time.now.strftime('%a %b %d %H:%M:%S %Y')}\001"
58
54
  end
59
-
55
+
60
56
  # before and after filter
61
57
  @before_filters = Hash.new { |hash, key| hash[key] = [] }
62
58
  @after_filters = Hash.new { |hash, key| hash[key] = [] }
63
59
  end
64
-
60
+
65
61
  def configure(&block)
66
62
  unless @reloading
67
63
  block.call(@config)
68
-
64
+
69
65
  # logger changes (if differing from initialize)
70
- if @config.logging
71
- @traffic_logger = @config.traffic_logger ? @config.traffic_logger : Logger::Twoflogger.new(Ponder.root.join('logs', 'traffic.log'))
72
- @error_logger = @config.error_logger ? @config.error_logger : Logger::Twoflogger.new(Ponder.root.join('logs', 'error.log'))
66
+ if @config.verbose
67
+ @console_logger = @config.console_logger if @config.console_logger
68
+ else
69
+ @console_logger = BlindIo.new
73
70
  end
74
-
75
- unless @config.verbose
76
- @console_logger = @empty_logger
71
+
72
+ if @config.logging
73
+ log_path = @config.log_path || File.join(ROOT, 'logs', 'log.log')
74
+ log_dir = File.dirname(log_path)
75
+ FileUtils.mkdir_p(log_dir) unless File.exist?(log_dir)
76
+
77
+ if @config.logger
78
+ @logger = @config.logger
79
+ else
80
+ @logger = Twoflogger.new(log_path, File::WRONLY | File::APPEND)
81
+ end
77
82
  end
78
83
  end
79
84
  end
80
-
85
+
81
86
  def on(event_types = [:channel], match = //, &block)
82
87
  if event_types.is_a?(Array)
83
88
  callbacks = event_types.map { |event_type| Callback.new(event_type, match, block) }
@@ -85,77 +90,73 @@ module Ponder
85
90
  callbacks = [Callback.new(event_types, match, block)]
86
91
  event_types = [event_types]
87
92
  end
88
-
93
+
89
94
  callbacks.each_with_index do |callback, index|
90
95
  @callbacks[event_types[index]] << callback
91
96
  end
92
97
  end
93
-
98
+
94
99
  def connect
95
100
  unless @reloading
96
- @traffic_logger.start_logging
97
- @error_logger.start_logging
98
- @console_logger.start_logging
99
-
100
- @traffic_logger.info '-- Starting Ponder'
101
+ @logger.info '-- Starting Ponder'
101
102
  @console_logger.info '-- Starting Ponder'
102
-
103
+
103
104
  EventMachine::run do
104
105
  @connection = EventMachine::connect(@config.server, @config.port, Connection, self)
105
106
  end
106
107
  end
107
108
  end
108
-
109
+
109
110
  def reload!
110
111
  @reloading = true
111
112
  @callbacks.clear
112
113
  load $0
113
114
  @reloading = false
114
115
  end
115
-
116
+
116
117
  def reloading?
117
118
  @reloading
118
119
  end
119
-
120
+
120
121
  # parsing incoming traffic
121
122
  def parse(message)
122
123
  message.chomp!
123
- @traffic_logger.info "<< #{message}"
124
+ @logger.info "<< #{message}"
124
125
  @console_logger.info "<< #{message}"
125
-
126
+
126
127
  case message
127
128
  when /^PING \S+$/
128
129
  raw message.sub(/PING/, 'PONG')
129
-
130
+
130
131
  when /^:\S+ (\d\d\d) /
131
132
  number = $1.to_i
132
133
  parse_event(number, :type => number, :params => $')
133
-
134
+
134
135
  when /^:(\S+)!(\S+)@(\S+) PRIVMSG #(\S+) :/
135
136
  parse_event(:channel, :type => :channel, :nick => $1, :user => $2, :host => $3, :channel => "##{$4}", :message => $')
136
-
137
+
137
138
  when /^:(\S+)!(\S+)@(\S+) PRIVMSG \S+ :/
138
139
  parse_event(:query, :type => :query, :nick => $1, :user => $2, :host => $3, :message => $')
139
-
140
+
140
141
  when /^:(\S+)!(\S+)@(\S+) JOIN :*(\S+)$/
141
142
  parse_event(:join, :type => :join, :nick => $1, :user => $2, :host => $3, :channel => $4)
142
-
143
+
143
144
  when /^:(\S+)!(\S+)@(\S+) PART (\S+)/
144
145
  parse_event(:part, :type => :part, :nick => $1, :user => $2, :host => $3, :channel => $4, :message => $'.sub(/ :/, ''))
145
-
146
+
146
147
  when /^:(\S+)!(\S+)@(\S+) QUIT/
147
148
  parse_event(:quit, :type => :quit, :nick => $1, :user => $2, :host => $3, :message => $'.sub(/ :/, ''))
148
-
149
+
149
150
  when /^:(\S+)!(\S+)@(\S+) NICK :/
150
151
  parse_event(:nickchange, :type => :nickchange, :nick => $1, :user => $2, :host => $3, :new_nick => $')
151
-
152
+
152
153
  when /^:(\S+)!(\S+)@(\S+) KICK (\S+) (\S+) :/
153
154
  parse_event(:kick, :type => :kick, :nick => $1, :user => $2, :host => $3, :channel => $4, :victim => $5, :reason => $')
154
-
155
+
155
156
  when /^:(\S+)!(\S+)@(\S+) TOPIC (\S+) :/
156
157
  parse_event(:topic, :type => :topic, :nick => $1, :user => $2, :host => $3, :channel => $4, :topic => $')
157
158
  end
158
-
159
+
159
160
  @observer_queues.each do |queue, regexps|
160
161
  regexps.each do |regexp|
161
162
  if message =~ regexp
@@ -164,7 +165,7 @@ module Ponder
164
165
  end
165
166
  end
166
167
  end
167
-
168
+
168
169
  # process callbacks with its begin; rescue; end
169
170
  def process_callbacks(event_type, event_data)
170
171
  @callbacks[event_type].each do |callback|
@@ -172,7 +173,7 @@ module Ponder
172
173
  Proc.new do
173
174
  begin
174
175
  stop_running = false
175
-
176
+
176
177
  # before filters (specific filters first, then :all)
177
178
  (@before_filters[event_type] + @before_filters[:all]).each do |filter|
178
179
  if filter.call(event_type, event_data) == false
@@ -180,19 +181,21 @@ module Ponder
180
181
  break
181
182
  end
182
183
  end
183
-
184
+
184
185
  unless stop_running
185
186
  # handling
186
187
  callback.call(event_type, event_data)
187
-
188
+
188
189
  # after filters (specific filters first, then :all)
189
190
  (@after_filters[event_type] + @after_filters[:all]).each do |filter|
190
191
  filter.call(event_type, event_data)
191
192
  end
192
193
  end
193
194
  rescue => e
194
- @error_logger.error(e.message, *e.backtrace)
195
- @console_logger.error(e.message, *e.backtrace)
195
+ [@logger, @console_logger].each do |logger|
196
+ logger.error("-- #{e.class}: #{e.message}")
197
+ e.backtrace.each { |line| logger.error("-- #{line}") }
198
+ end
196
199
  end
197
200
  end
198
201
  )
@@ -202,24 +205,24 @@ module Ponder
202
205
  def before_filter(event_types = :all, match = //, &block)
203
206
  filter(@before_filters, event_types, match, block)
204
207
  end
205
-
208
+
206
209
  def after_filter(event_types = :all, match = //, &block)
207
210
  filter(@after_filters, event_types, match, block)
208
211
  end
209
-
212
+
210
213
  private
211
-
214
+
212
215
  # parses incoming traffic (types)
213
216
  def parse_event(event_type, event_data = {})
214
217
  if ((event_type == 376) || (event_type == 422)) && !@connected
215
218
  @connected = true
216
219
  process_callbacks(:connect, event_data)
217
220
  end
218
-
221
+
219
222
  process_callbacks(event_type, event_data)
220
223
  end
221
-
222
- def filter(filter_type, event_types = :all, match = //, &block)
224
+
225
+ def filter(filter_type, event_types = :all, match = //, block = Proc.new)
223
226
  if event_types.is_a?(Array)
224
227
  event_types.each do |event_type|
225
228
  filter_type[event_type] << Filter.new(event_type, match, block)
@@ -1,3 +1,4 @@
1
1
  module Ponder
2
- VERSION = '0.0.2'
2
+ VERSION = '0.1.0'
3
3
  end
4
+
data/ponder.gemspec CHANGED
@@ -1,39 +1,43 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'lib/ponder/version'
4
+
1
5
  Gem::Specification.new do |s|
2
6
  s.name = 'ponder'
3
- s.version = '0.0.2'
7
+ s.version = Ponder::VERSION
8
+ s.date = '2011-01-29'
4
9
  s.summary = 'IRC bot framework'
5
10
  s.description = 'Ponder (Stibbons) is a Domain Specific Language for writing IRC Bots using the EventMachine library.'
6
-
11
+
7
12
  s.author = 'Tobias Bühlmann'
8
13
  s.email = 'tobias.buehlmann@gmx.de'
9
14
  s.homepage = 'http://github.com/tbuehlmann/ponder'
10
-
15
+
11
16
  s.required_ruby_version = '>= 1.8.6'
12
17
  s.add_dependency('eventmachine', '>= 0.12.10')
13
- s.files = ['examples/echo.rb',
14
- 'examples/github_blog.rb',
15
- 'examples/redis_last_seen.rb',
16
- 'lib/ponder/async_irc.rb',
17
- 'lib/ponder/callback.rb',
18
- 'lib/ponder/connection.rb',
19
- 'lib/ponder/delegate.rb',
20
- 'lib/ponder/filter.rb',
21
- 'lib/ponder/formatting.rb',
22
- 'lib/ponder/irc.rb',
23
- 'lib/ponder/logger',
24
- 'lib/ponder/thaum.rb',
25
- 'lib/ponder/version.rb',
26
- 'lib/ponder/logger/blind_io.rb',
27
- 'lib/ponder/logger/twoflogger.rb',
28
- 'lib/ponder/logger/twoflogger18.rb',
29
- 'lib/ruby/1.8/string.rb',
30
- 'lib/ponder.rb',
31
- 'test/test_async_irc.rb',
32
- 'test/test_callback.rb',
33
- 'test/test_helper.rb',
34
- 'test/test_irc.rb',
35
- 'LICENSE',
36
- 'ponder.gemspec',
37
- 'README.md']
18
+ s.files = %w[
19
+ LICENSE
20
+ README.md
21
+ Rakefile
22
+ examples/echo.rb
23
+ examples/github_blog.rb
24
+ examples/redis_last_seen.rb
25
+ lib/ponder.rb
26
+ lib/ponder/async_irc.rb
27
+ lib/ponder/callback.rb
28
+ lib/ponder/connection.rb
29
+ lib/ponder/filter.rb
30
+ lib/ponder/formatting.rb
31
+ lib/ponder/irc.rb
32
+ lib/ponder/logger/blind_io.rb
33
+ lib/ponder/logger/twoflogger.rb
34
+ lib/ponder/thaum.rb
35
+ lib/ponder/version.rb
36
+ ponder.gemspec
37
+ test/test_async_irc.rb
38
+ test/test_callback.rb
39
+ test/test_helper.rb
40
+ test/test_irc.rb
41
+ ]
38
42
  end
39
43
 
@@ -1,18 +1,13 @@
1
- require 'pathname'
2
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
3
  require 'test_helper'
4
4
  require 'ponder/async_irc'
5
5
 
6
- module Ponder
7
- module AsyncIRC
8
- def raw(*args)
9
- end
10
- end
11
- end
12
-
13
6
  include Ponder::AsyncIRC
7
+ def raw(*args)
8
+ end
14
9
 
15
- class TestIRC < Test::Unit::TestCase
10
+ class TestAsyncIRC < Test::Unit::TestCase
16
11
  def setup
17
12
  @observer_queues = {}
18
13
  end
@@ -1,5 +1,5 @@
1
- require 'pathname'
2
- $LOAD_PATH.unshift Pathname.new(__FILE__).dirname.expand_path
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
3
  require 'test_helper'
4
4
  require 'ponder/callback'
5
5
 
@@ -13,42 +13,43 @@ class TestCallback < Test::Unit::TestCase
13
13
  def setup
14
14
  @empty_proc = Proc.new { }
15
15
  end
16
-
16
+
17
17
  def test_perfect_case
18
18
  callback = Ponder::Callback.new(:channel, /foo/, @empty_proc)
19
-
19
+
20
20
  assert_equal(/foo/, callback.match)
21
21
  assert_equal(@empty_proc, callback.proc)
22
22
  end
23
-
23
+
24
24
  def test_unsupported_event_type
25
25
  assert_raise(TypeError) do
26
26
  Ponder::Callback.new('fu', /foo/, @empty_proc)
27
27
  end
28
28
  end
29
-
29
+
30
30
  def test_regexp
31
31
  assert_raise(TypeError) do
32
32
  Ponder::Callback.new(:channel, 8, @empty_proc)
33
33
  end
34
34
  end
35
-
35
+
36
36
  def test_proc
37
37
  assert_raise(TypeError) do
38
38
  Ponder::Callback.new(:channel, /foo/, 8)
39
39
  end
40
40
  end
41
-
41
+
42
42
  def test__trivial_proc
43
43
  proc = Proc.new { 7 + 1 }
44
-
44
+
45
45
  assert_equal(proc, Ponder::Callback.new(:channel, //, proc).proc)
46
46
  end
47
-
47
+
48
48
  def test_call
49
49
  proc = Proc.new { 8 }
50
-
50
+
51
51
  assert_equal(8, Ponder::Callback.new(:channel, /wizzard/, proc).call(:channel, {:message => 'I like wizzards'}))
52
52
  assert_nil(Ponder::Callback.new(:channel, /wizzard/, proc).call(:channel, {:message => 'I am a wizard'}))
53
53
  end
54
54
  end
55
+