ircbot 0.1.2 → 0.1.4

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/README CHANGED
@@ -17,6 +17,7 @@ Config
17
17
  * help: help message for this bot
18
18
  * channels: startup channel names
19
19
  * plugins: plugin names
20
+ * timeout: bot will exit when no new pings come for this sec
20
21
 
21
22
 
22
23
  Usage
@@ -57,7 +58,30 @@ Example
57
58
  end
58
59
  end
59
60
 
60
-
61
+
62
+ Advanced
63
+ ========
64
+
65
+ Messages are passed into plugins automatically.
66
+ If you don't want this plugin chain, throw :done will help you.
67
+
68
+ config:
69
+ plugins: a b
70
+
71
+ class APlugin < Ircbot::Plugin
72
+ def reply(text)
73
+ throw :done, "This is A"
74
+ end
75
+ end
76
+
77
+ class BPlugin < Ircbot::Plugin
78
+ def reply(text)
79
+ "This is B"
80
+ end
81
+ end
82
+
83
+ BPlugin#reply will be never invoked.
84
+
61
85
 
62
86
  Required
63
87
  ========
data/bin/ircbot CHANGED
@@ -62,6 +62,9 @@ end
62
62
 
63
63
  Ircbot.push_path(:plugin, plugin)
64
64
 
65
+ STDOUT.sync = true
66
+ STDERR.sync = true
67
+
65
68
  irc = Ircbot::Client.from_file(config)
66
69
  irc.start
67
70
  puts "Bye"
@@ -0,0 +1,8 @@
1
+ host: localhost
2
+ port: 6666
3
+ nick: airi
4
+ user: airi
5
+ real: airi
6
+ channels: "#test"
7
+ plugins: irc plugins which reminder tv
8
+ multiline: true
@@ -6,3 +6,4 @@ real: sama~zu
6
6
  channels: "#test"
7
7
  plugins: irc plugins
8
8
  multiline: true
9
+ timeout: 500
@@ -1,8 +1,9 @@
1
1
  host: irc.haun.org
2
2
  port: 6667
3
3
  nick: sama-zu
4
- user: samazu
5
- real: sama~zu
4
+ user: sama-zu
5
+ real: sama-zu
6
6
  channels: "#wota"
7
- plugins: irc plugins which
7
+ plugins: irc plugins which reminder tv
8
8
  multiline: true
9
+ timeout: 600
@@ -6,3 +6,5 @@ real: <%= nick %>
6
6
  channels: "#test"
7
7
  plugins: irc plugins
8
8
  multiline: true
9
+ timeout: 500
10
+ # wait_before_restart: 300
@@ -3,30 +3,17 @@
3
3
  require "ircbot/plugin"
4
4
  require "ircbot/plugins"
5
5
 
6
- module Ircbot
7
- class Client < Net::IRC::Client
8
-
9
- # escape from nil black hole
10
- def method_missing(name, *args)
11
- case name.to_s
12
- when /^on_/
13
- # nop for calling super from subclass
14
- else
15
- raise NameError, "undefined local variable or method `#{name}' for #{self}"
16
- end
17
- end
18
-
19
- class Standalone < Client
20
- def initialize(*)
21
- super({})
22
- end
23
- end
24
- end
25
- end
6
+ ######################################################################
7
+ ### Irctob::Client
26
8
 
9
+ require "ircbot/client/core"
10
+ require "ircbot/client/standalone"
11
+ require "ircbot/client/eventable"
12
+ require "ircbot/client/logger"
27
13
  require "ircbot/client/encoding"
28
14
  require "ircbot/client/commands"
29
15
  require "ircbot/client/config"
30
16
  require "ircbot/client/config/channels"
31
17
  require "ircbot/client/config/plugins"
18
+ require "ircbot/client/timeout"
32
19
  require "ircbot/client/plugins"
@@ -27,16 +27,20 @@ module Ircbot
27
27
  ######################################################################
28
28
  ### Config
29
29
  def initialize(obj)
30
- @obj = obj
30
+ @obj = Mash.new(obj)
31
31
  end
32
32
 
33
33
  def [](key)
34
- __send__(key)
34
+ @obj[key]
35
35
  end
36
36
 
37
37
  private
38
- def method_missing(*args)
39
- @obj.__send__(*args)
38
+ def method_missing(name, *args)
39
+ if args.empty?
40
+ self[name]
41
+ else
42
+ super
43
+ end
40
44
  end
41
45
  end
42
46
 
@@ -46,10 +50,9 @@ module Ircbot
46
50
 
47
51
  def initialize(hash)
48
52
  super(hash[:host], hash[:port], hash)
53
+ @config = Config.new(hash)
49
54
  end
50
55
 
51
- def config
52
- @config ||= Config.new(opts)
53
- end
56
+ attr_reader :config
54
57
  end
55
58
  end
@@ -20,13 +20,11 @@ module Ircbot
20
20
  ######################################################################
21
21
  ### Event
22
22
 
23
- def on_rpl_welcome(m)
24
- super
25
-
23
+ event(:rpl_welcome) {
26
24
  config.channels.each do |channel|
27
25
  post JOIN, channel
28
26
  end
29
- end
27
+ }
30
28
 
31
29
  ######################################################################
32
30
  ### Command
@@ -32,34 +32,6 @@ module Ircbot
32
32
  "unknown"
33
33
  end
34
34
  end
35
- def channels
36
- case (val = super)
37
- when Array
38
- val
39
- else
40
- val.to_s.split
41
- end
42
- end
43
- end
44
-
45
- ######################################################################
46
- ### Event
47
-
48
- def on_rpl_welcome(m)
49
- super
50
-
51
- config.channels.each do |channel|
52
- post JOIN, channel
53
- end
54
- end
55
-
56
- ######################################################################
57
- ### Command
58
-
59
- def broadcast(text)
60
- config.channels.each do |channel|
61
- privmsg channel, text
62
- end
63
35
  end
64
36
  end
65
37
  end
@@ -0,0 +1,4 @@
1
+ module Ircbot
2
+ class Client < Net::IRC::Client
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ module Ircbot
2
+ class Client
3
+ include Extlib::Hook
4
+
5
+ class << self
6
+ def event(name, &block)
7
+ name = "on_#{name}".intern
8
+ unless instance_methods.include?(name.to_s)
9
+ define_method(name){|m|}
10
+ end
11
+ before name, &block
12
+ end
13
+ end
14
+
15
+ # escape from nil black hole
16
+ private
17
+ def method_missing(name, *args)
18
+ raise NameError, "undefined local variable or method `#{name}' for #{self}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ def debug(text)
6
+ p [:debug, text]
7
+ end
8
+ end
9
+ end
@@ -15,18 +15,16 @@ module Ircbot
15
15
  ######################################################################
16
16
  ### Events
17
17
 
18
- def on_privmsg(m)
19
- super
20
-
18
+ event(:privmsg) {|m|
21
19
  text = decode(m.params[1].to_s)
22
20
  args = [text, m.prefix.nick, m]
23
21
 
24
22
  plugins_call_replies(args, m)
25
- end
23
+ }
26
24
 
27
25
  private
28
26
  def plugins_call_replies(args, m)
29
- text = catch(:halt) do
27
+ text = catch(:done) do
30
28
  plugins.active.each do |plugin|
31
29
  plugins_call_action(:reply, plugin, args, m, :reply=>true)
32
30
  end
@@ -0,0 +1,9 @@
1
+ module Ircbot
2
+ class Client
3
+ class Standalone < Client
4
+ def initialize(*)
5
+ super({})
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ ######################################################################
6
+ ### Event
7
+
8
+ event(:ping) {
9
+ if (sec = config.timeout.to_i) > 0
10
+ @kill_myself_at.kill if @kill_myself_at.is_a?(Thread)
11
+ @kill_myself_at = Thread.new { sleep sec; timeouted }
12
+ end
13
+ }
14
+
15
+ class Timeouted < RuntimeError; end
16
+
17
+ def start
18
+ super
19
+ rescue Exception => e
20
+ sec = [config.wait_before_restart.to_i, 10].max
21
+ sleep sec
22
+ $stderr.puts "Restarting after timeouted"
23
+ retry
24
+ end
25
+
26
+ private
27
+ def timeouted
28
+ $stderr.puts "No new pings for #{config.timeout}sec."
29
+ raise Timeouted
30
+ end
31
+ end
32
+ end
@@ -29,6 +29,7 @@ module Ircbot
29
29
  ### Accessors
30
30
 
31
31
  delegate :plugin!, :client, :bot, :config, :to=>"@plugins"
32
+ delegate :debug, :to=>"@plugins"
32
33
 
33
34
  def plugin_name
34
35
  @plugin_name ||= Extlib::Inflection.foreign_key(self.class.name).sub(/(_plugin)?_id$/,'')
@@ -59,5 +60,9 @@ module Ircbot
59
60
  def direct?
60
61
  message.channel == config.nick
61
62
  end
63
+
64
+ def nick
65
+ message.prefix.nick
66
+ end
62
67
  end
63
68
  end
@@ -6,7 +6,7 @@ module Ircbot
6
6
  class Plugins
7
7
  attr_reader :plugins
8
8
  attr_reader :client
9
- delegate :config, :to=>"client"
9
+ delegate :config, :debug, :to=>"client"
10
10
 
11
11
  def initialize(client = nil, plugins = nil)
12
12
  @client = client || Client::Standalone.new
@@ -1,4 +1,4 @@
1
1
  module Ircbot
2
- VERSION = '0.1.2' unless defined?(Ircbot::VERSION)
2
+ VERSION = '0.1.4' unless defined?(Ircbot::VERSION)
3
3
  HOMEPAGE = "http://github.com/maiha/ircbot"
4
4
  end
@@ -0,0 +1,276 @@
1
+ #!/usr/bin/env ruby -Ku
2
+ # -*- coding: utf-8 -*-
3
+
4
+ ######################################################################
5
+ # [Install]
6
+ #
7
+ # gem install chawan night-time dm-core dm-migrations dm-timestamps do_sqlite3 data_objects
8
+ #
9
+
10
+ require 'rubygems'
11
+ require 'ircbot'
12
+ require 'chawan'
13
+ require 'night-time'
14
+
15
+ require 'dm-core'
16
+ require 'dm-migrations'
17
+ require 'dm-timestamps'
18
+
19
+ module Reminder
20
+ def self.connect(path = nil)
21
+ @connecteds ||= {}
22
+ @connecteds[path] ||=
23
+ (
24
+ path = Pathname(path || Pathname(Dir.getwd) + "db" + "reminder.db").expand_path
25
+ path.parent.mkpath
26
+ DataMapper.setup(:default, "sqlite3://#{path}")
27
+ Reminder::Event.auto_upgrade!
28
+ )
29
+ end
30
+
31
+ ######################################################################
32
+ ### Exceptions
33
+
34
+ class EventNotFound < RuntimeError; end
35
+ class EventNotSaved < RuntimeError
36
+ attr_accessor :event
37
+ def initialize(event)
38
+ @event = event
39
+ end
40
+ end
41
+ class EventHasDone < EventNotSaved; end
42
+ class StartNotFound < EventNotSaved; end
43
+
44
+ ######################################################################
45
+ ### Event
46
+
47
+ class Event
48
+ include DataMapper::Resource
49
+
50
+ property :id , Serial
51
+ property :st , DateTime # 開始日時
52
+ property :en , DateTime # 終了日時
53
+ property :title , String # 件名
54
+ property :desc , String # 詳細
55
+ property :where , String # 場所
56
+ property :allday , Boolean , :default=>false # 終日フラグ
57
+ property :alerted , Boolean , :default=>false # お知らせ済
58
+ property :alert_at , DateTime # お知らせ日時
59
+
60
+ ######################################################################
61
+ ### Class methods
62
+
63
+ class << self
64
+ def default_storage_name
65
+ "event"
66
+ end
67
+
68
+ def reminders
69
+ all(:alerted=>false, :alert_at.lt=>Time.now, :order=>[:alert_at])
70
+ end
71
+ end
72
+
73
+ ######################################################################
74
+ ### Instance methods
75
+
76
+ def done!
77
+ self.alerted = true
78
+ save
79
+ end
80
+
81
+ def to_s
82
+ desc.to_s
83
+ end
84
+ end
85
+
86
+ module TimeParser
87
+ def parse(text)
88
+ event = Event.new
89
+ event.desc = text
90
+ event.title = text.sub(%r{^[\s\d:-]+}, '')
91
+ event.allday = false
92
+
93
+ t = Date._parse(text)
94
+ # => {:zone=>"-14:55", :year=>2010, :hour=>13, :min=>30, :mday=>4, :offset=>-53700, :mon=>1}
95
+
96
+ if t[:year] && t[:mon] && t[:mday] && t[:hour]
97
+ event.st = Time.mktime(t[:year], t[:mon], t[:mday], t[:hour], t[:min], t[:sec])
98
+ if t[:zone].to_s =~ /^-?(\d+):(\d+)(:(\d+))?$/
99
+ event.en = Time.mktime(t[:year], t[:mon], t[:mday], $1, $2, $4)
100
+ end
101
+ else
102
+ event.allday = true
103
+ event.st = Time.mktime(t[:year], t[:mon], t[:mday]) rescue nil
104
+ end
105
+
106
+ return event
107
+ end
108
+
109
+ def register(text)
110
+ event = parse(text)
111
+ event.st or raise StartNotFound, event
112
+ if event.st.to_time > Time.now
113
+ event.alert_at = Time.at(event.st.to_time.to_i - 30*60)
114
+ event.save or raise EventNotSaved, event
115
+ return event
116
+ else
117
+ raise EventHasDone, event
118
+ end
119
+ end
120
+ end
121
+
122
+ extend TimeParser
123
+ end
124
+
125
+
126
+ class ReminderPlugin < Ircbot::Plugin
127
+ class EventWatcher
128
+ attr_accessor :interval
129
+ attr_accessor :callback
130
+
131
+ def initialize(options = {})
132
+ @interval = options[:interval] || 60
133
+ @callback = options[:callback] || proc{|e| puts e}
134
+ end
135
+
136
+ def start
137
+ loop do
138
+ if callback
139
+ events = Reminder::Event.reminders
140
+ #debug "#{self.class} found #{events.size} events"
141
+ events.each do |event|
142
+ callback.call(event)
143
+ event.done!
144
+ end
145
+ end
146
+ sleep interval
147
+ end
148
+ end
149
+ end
150
+
151
+ def reply(text)
152
+ start_reminder
153
+
154
+ case text
155
+ when %r{^\d{4}.?\d{1,2}.?\d{1,2}}
156
+ event = Reminder.register(text)
157
+ text = "Remind you again at %s" % event.alert_at.strftime("%Y-%m-%d %H:%M")
158
+ throw :done, text
159
+ end
160
+ return nil
161
+
162
+ rescue Reminder::EventNotFound
163
+ return nil
164
+
165
+ rescue Reminder::StartNotFound => e
166
+ return "Reminder cannot detect start: #{e.event.st}"
167
+
168
+ rescue Reminder::EventHasDone => e
169
+ puts "Reminder ignores past event: #{e.event.st}"
170
+ return nil
171
+ end
172
+
173
+ private
174
+ def start_reminder(&callback)
175
+ bot = self.bot
176
+ callback ||= proc{|event| bot.broadcast event.to_s}
177
+ @event_watcher_thread ||=
178
+ (connect
179
+ reminder = EventWatcher.new(:interval=>60, :callback=>callback)
180
+ Thread.new { reminder.start })
181
+ end
182
+
183
+ def reminder_db_path
184
+ Ircbot.root + "db" + "reminder-#{config.nick}.db"
185
+ end
186
+
187
+ def connect
188
+ @connect ||= Reminder.connect(reminder_db_path)
189
+ end
190
+ end
191
+
192
+
193
+ ######################################################################
194
+ ### Setup database
195
+
196
+ if $0 == __FILE__
197
+
198
+ def spec(src, buffer, &block)
199
+ buffer = "require '#{Pathname(src).expand_path}'\n" + buffer
200
+ tmp = Tempfile.new("dynamic-spec")
201
+ tmp.print(buffer)
202
+ tmp.close
203
+ block.call(tmp)
204
+ ensure
205
+ tmp.close(true)
206
+ end
207
+
208
+ spec($0, DATA.read{}) do |tmp|
209
+ system("spec -cfs #{tmp.path}")
210
+ end
211
+ end
212
+
213
+ __END__
214
+
215
+ require 'spec'
216
+ require 'ostruct'
217
+
218
+ module Spec
219
+ module Example
220
+ module Subject
221
+ module ExampleGroupMethods
222
+ def parse(text, &block)
223
+ describe "(#{text})" do
224
+ subject {
225
+ event = Reminder.parse(text)
226
+ hash = {
227
+ :st => (event.st.strftime("%Y-%m-%d %H:%M:%S") rescue nil),
228
+ :en => (event.en.strftime("%Y-%m-%d %H:%M:%S") rescue nil),
229
+ :title => event.title.to_s,
230
+ :desc => event.title.to_s,
231
+ :allday => event.allday,
232
+ }
233
+ OpenStruct.new(hash)
234
+ }
235
+ instance_eval(&block)
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
242
+
243
+ describe "Reminder#parse" do
244
+
245
+ parse '' do
246
+ its(:st) { should == nil }
247
+ end
248
+
249
+ parse '2010-01-04 CX' do
250
+ its(:st) { should == "2010-01-04 00:00:00" }
251
+ its(:en) { should == nil }
252
+ its(:title) { should == "CX" }
253
+ its(:allday) { should == true }
254
+ end
255
+
256
+ parse '2010-01-04 13:30 CX' do
257
+ its(:st) { should == "2010-01-04 13:30:00" }
258
+ its(:en) { should == nil }
259
+ its(:title) { should == "CX" }
260
+ its(:allday) { should == false }
261
+ end
262
+
263
+ parse '2010-01-04 13:30-14:55 CX' do
264
+ its(:st) { should == "2010-01-04 13:30:00" }
265
+ its(:en) { should == "2010-01-04 14:55:00" }
266
+ its(:title) { should == "CX" }
267
+ its(:allday) { should == false }
268
+ end
269
+
270
+ parse '2010-01-18 27:15-27:45 TX' do
271
+ its(:st) { should == "2010-01-19 03:15:00" }
272
+ its(:en) { should == "2010-01-19 03:45:00" }
273
+ its(:title) { should == "TX" }
274
+ its(:allday) { should == false }
275
+ end
276
+ end
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # tv.rb
4
+ # Author:
5
+ # Created: Sun Jan 10 18:44:35 2010
6
+
7
+ require 'rubygems'
8
+ require 'ircbot'
9
+ require '/git/plugins/ircbot-plugins/lib/tvguide'
10
+ require '/git/plugins/ircbot-plugins/lib/tv-cast'
11
+ require 'chawan'
12
+
13
+ class TVGuide::Program
14
+ def id
15
+ "#{st}:#{sn}"
16
+ end
17
+ end
18
+
19
+ class TvPlugin < Ircbot::Plugin
20
+ ######################################################################
21
+ ### Extensions to Plugin
22
+
23
+ class WeightedRandomizer
24
+ def initialize(hash)
25
+ @hash = construct(hash)
26
+ end
27
+
28
+ def construct(obj)
29
+ case obj
30
+ when Hash
31
+ return obj
32
+ when Array
33
+ hash = {}
34
+ obj.reverse.each_with_index do |val,i|
35
+ hash[val] = i+1
36
+ end
37
+ return hash
38
+ else
39
+ raise NotImplementedError, "expected Hash or Array, but got #{hash.class}: #{hash.inspect}"
40
+ end
41
+ end
42
+
43
+ def execute
44
+ maps = []
45
+ stop = 0
46
+ @hash.each_pair do |val, key|
47
+ start = stop
48
+ stop += key
49
+ maps << [start...stop, val]
50
+ end
51
+ hit = rand(stop)
52
+ maps.each do |(range, val)|
53
+ return val if range === hit
54
+ end
55
+ return @hash.keys.first
56
+ end
57
+ end
58
+
59
+ module ReplyApiFu
60
+ class Reply < RuntimeError
61
+ def initialize(text)
62
+ @text = text
63
+ end
64
+
65
+ def text
66
+ case @text
67
+ when Hash
68
+ WeightedRandomizer.new(@text).execute
69
+ else
70
+ @text.to_s
71
+ end
72
+ end
73
+ end
74
+
75
+ class Nop < RuntimeError; end
76
+
77
+ def nop
78
+ raise Nop
79
+ end
80
+ end
81
+
82
+ include ReplyApiFu
83
+
84
+ ######################################################################
85
+ ### TvPlugin
86
+
87
+ STATION_ABBRS = {
88
+ 'NHK' => 'NHK総合',
89
+ 'NHKG' => 'NHK総合',
90
+ 'NHKE' => 'NHK教育',
91
+ 'ETV' => 'NHK教育',
92
+ '日テレ' => '日本テレビ',
93
+ 'NTV' => '日本テレビ',
94
+ 'TBS' => 'TBSテレビ',
95
+ 'フジ' => 'フジテレビ',
96
+ 'CX' => 'フジテレビ',
97
+ 'テレ朝' => 'テレビ朝日',
98
+ 'EX' => 'テレビ朝日',
99
+ 'テレ東' => 'テレビ東京',
100
+ 'TX' => 'テレビ東京',
101
+ 'MX' => 'TOKYO MX',
102
+ 'BS' => 'NHK衛星第一',
103
+ 'BS1' => 'NHK衛星第一',
104
+ 'BS2' => 'NHK衛星第二',
105
+ }
106
+
107
+ class Conversation
108
+ attr_reader :nick
109
+ attr_reader :messages
110
+
111
+ Message = Struct.new(:time, :text)
112
+
113
+ delegate :[], :first, :last, :clear, :to=>"@messages"
114
+
115
+ def initialize(nick)
116
+ @nick = nick
117
+ @messages = []
118
+ end
119
+
120
+ def <<(text)
121
+ messages << Message.new(Time.now, text.to_s)
122
+ end
123
+
124
+ class One < Conversation
125
+ def <<(text)
126
+ clear
127
+ super
128
+ end
129
+ end
130
+ end
131
+
132
+ EagarProgram = Struct.new(:nick, :time, :program)
133
+ class EagarProgram
134
+ def push(program)
135
+ self.time = Time.now
136
+ self.program = program
137
+ end
138
+
139
+ def shift
140
+ self.time = nil
141
+ return program
142
+ end
143
+ end
144
+
145
+ def reply(text)
146
+ respond_to_eagar_program
147
+
148
+ names = extract_station_names(text)
149
+ case text
150
+ when /キャスト/
151
+ do_cast(names.first)
152
+ when /(だれ|誰).*(\?|?)/
153
+ do_who(names.first)
154
+ else
155
+ do_summary(names)
156
+ end
157
+
158
+ nop
159
+ rescue Nop
160
+ return nil
161
+ rescue Reply => reply
162
+ return reply.text
163
+ end
164
+
165
+ def do_summary(names)
166
+ reports = names.map{|name| summary(current[name])}.compact
167
+ raise Reply, reports.join("\n")
168
+ end
169
+
170
+ def do_who(name)
171
+ prog = current[name]
172
+ if prog.casts.size > 0
173
+ raise Reply, "#{name}: #{prog.casts.join(',')}"
174
+ else
175
+ eagar_program_for(nick).push prog
176
+ raise Reply, {
177
+ "知るかよ!" => 80,
178
+ "#{nick}必死w" => 10,
179
+ "EPGには記述されていません" => 1,
180
+ }
181
+ end
182
+ end
183
+
184
+ def do_cast(name)
185
+ p = current[name]
186
+ query = "%s %s" % [p.title, name]
187
+ casts = TvCast.lookup!(query)
188
+ if casts.size > 0
189
+ raise Reply, "#{name}: #{casts.join(',')}"
190
+ else
191
+ raise Reply, "見つかりませんでした"
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ def extract_station_names(text)
198
+ text = text.sub(/(誰|キャスト)/, ',\1')
199
+ nouns = Chawan.parse(text.gsub(/\s+/,',')).compact.noun.map(&:to_s)
200
+ names = nouns.map{|name| STATION_ABBRS[name] || name} & station_names
201
+ nop if names.empty?
202
+ return names
203
+ end
204
+
205
+ def eagar_program_for(nick)
206
+ @eagar_programs ||= {}
207
+ @eagar_programs[nick] ||= EagarProgram.new(nick)
208
+ end
209
+
210
+ def respond_to_eagar_program
211
+ eager = eagar_program_for(nick)
212
+ if eager.time and Time.now.to_i < eager.time.to_i + 10 and prog = eager.shift
213
+ query = "%s %s" % [prog.title, prog.station_name]
214
+ casts = TvCast.lookup!(query)
215
+ if casts.size > 0
216
+ random = WeightedRandomizer.new(casts)
217
+ name = random.execute
218
+ raise Reply, {
219
+ "#{name}と思われ" => 50,
220
+ "#{name}?" => 50,
221
+ "#{name}の予感!" => 50,
222
+ "#{casts[0,2].join('か')}のどっちか" => 30,
223
+ "ググった限り#{name}ぽい>#{prog.title}" => 20,
224
+ "#{name}に大決定や!(確度#{(100/casts.size).to_i}%)" => 10,
225
+ casts.inspect => 2,
226
+ }
227
+ end
228
+ raise Reply, text
229
+ end
230
+ end
231
+
232
+ def current
233
+ @current ||= TVGuide.current
234
+ end
235
+
236
+ def station_names
237
+ @station_names ||= current.station_names
238
+ end
239
+
240
+ def reporteds
241
+ @reporteds ||= {}
242
+ end
243
+
244
+ def summary(p)
245
+ nop if reporteds[p.id]
246
+ reporteds[p.id] = true
247
+ time1 = p.st.strftime("%H:%M") rescue ''
248
+ time2 = p.en.strftime("%H:%M") rescue ''
249
+ "#{time1}-#{time2} #{p.title} (#{p.sn})"
250
+ rescue
251
+ nop
252
+ end
253
+ end
254
+
255
+
256
+ if $0 == __FILE__
257
+ $KCODE = 'u'
258
+ require 'pp'
259
+
260
+ # pp TVGuide::TXML301PG.new.map
261
+ pp TvPlugin.new.reply('NHK総合')
262
+ end
@@ -33,6 +33,7 @@ describe Ircbot::Client do
33
33
  its(:real) { should == "sama~zu" }
34
34
  its(:host) { should == "localhost" }
35
35
  its(:port) { should == "6667" }
36
+ its(:unknown_key) { should == nil } # should not raise error
36
37
 
37
38
  describe "#channels" do
38
39
  it "should return the array when an array is given" do
@@ -36,6 +36,7 @@ describe Ircbot::Plugin do
36
36
  provide :plugin
37
37
  provide :plugin!
38
38
  provide :direct?
39
+ provide :nick
39
40
 
40
41
  ######################################################################
41
42
  ### Not connected
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ircbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - maiha
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-10 00:00:00 +09:00
12
+ date: 2010-01-27 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,8 +52,13 @@ files:
52
52
  - lib/ircbot/client/config/plugins.rb
53
53
  - lib/ircbot/client/config/generator.rb
54
54
  - lib/ircbot/client/encoding.rb
55
+ - lib/ircbot/client/core.rb
55
56
  - lib/ircbot/client/commands.rb
57
+ - lib/ircbot/client/standalone.rb
56
58
  - lib/ircbot/client/plugins.rb
59
+ - lib/ircbot/client/logger.rb
60
+ - lib/ircbot/client/eventable.rb
61
+ - lib/ircbot/client/timeout.rb
57
62
  - lib/ircbot/core_ext/extending.rb
58
63
  - lib/ircbot/core_ext/message.rb
59
64
  - lib/ircbot/core_ext/delegation.rb
@@ -69,11 +74,14 @@ files:
69
74
  - spec/spec_helper.rb
70
75
  - spec/framework_spec.rb
71
76
  - spec/plugins_spec.rb
77
+ - plugins/tv.rb
78
+ - plugins/reminder.rb
72
79
  - plugins/echo.rb
73
80
  - plugins/plugins.rb
74
81
  - plugins/which.rb
75
82
  - plugins/irc.rb
76
83
  - config/wota.yml
84
+ - config/airi.yml
77
85
  - config/sama-zu.yml
78
86
  - config/yml.erb
79
87
  has_rdoc: true