ponder 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+