ircbot 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.
Files changed (43) hide show
  1. data/README +43 -21
  2. data/Rakefile +9 -6
  3. data/bin/ircbot +3 -27
  4. data/lib/ircbot.rb +12 -15
  5. data/lib/ircbot/client.rb +32 -0
  6. data/lib/ircbot/client/commands.rb +34 -0
  7. data/lib/ircbot/client/config.rb +55 -0
  8. data/lib/ircbot/client/config/channels.rb +40 -0
  9. data/lib/ircbot/client/config/plugins.rb +16 -0
  10. data/lib/ircbot/client/encoding.rb +17 -0
  11. data/lib/ircbot/client/plugins.rb +64 -0
  12. data/lib/ircbot/core_ext/delegation.rb +135 -0
  13. data/lib/ircbot/core_ext/extending.rb +80 -0
  14. data/lib/ircbot/core_ext/message.rb +18 -0
  15. data/lib/ircbot/framework.rb +22 -40
  16. data/lib/ircbot/plugin.rb +63 -0
  17. data/lib/ircbot/plugins.rb +141 -0
  18. data/lib/ircbot/version.rb +4 -0
  19. data/plugins/echo.rb +14 -0
  20. data/plugins/irc.rb +19 -0
  21. data/plugins/plugins.rb +59 -0
  22. data/spec/config_spec.rb +83 -0
  23. data/spec/fixtures/sama-zu.yml +8 -0
  24. data/spec/framework_spec.rb +18 -0
  25. data/spec/its_helper.rb +15 -0
  26. data/spec/plugin_spec.rb +70 -0
  27. data/spec/plugins_spec.rb +30 -0
  28. data/spec/provide_helper.rb +36 -0
  29. data/spec/spec_helper.rb +16 -0
  30. metadata +40 -19
  31. data/lib/irc/agent.rb +0 -177
  32. data/lib/irc/client.rb +0 -476
  33. data/lib/irc/const.rb +0 -242
  34. data/lib/irc/irc.rb +0 -324
  35. data/lib/irc/localize.rb +0 -260
  36. data/lib/ircbot/agent_manager.rb +0 -89
  37. data/lib/ircbot/config_client.rb +0 -369
  38. data/lib/ircbot/core_ext/digest.rb +0 -14
  39. data/lib/ircbot/core_ext/irc.rb +0 -61
  40. data/lib/ircbot/core_ext/rand-polimorphism.rb +0 -23
  41. data/lib/ircbot/core_ext/writefile.rb +0 -45
  42. data/lib/ircbot/ordered_hash.rb +0 -91
  43. data/lib/ircbot/reply_client.rb +0 -328
data/README CHANGED
@@ -1,47 +1,69 @@
1
1
  ircbot
2
- ===
2
+ ======
3
3
 
4
- old fashioned irc bot
4
+ An irc bot framework that offers easy-to-use by plugins
5
5
 
6
6
 
7
7
  Config
8
8
  ======
9
9
 
10
- Edit "config/xxx.dat" as your environment.
10
+ Edit "config/xxx.yml" as your environment.
11
+
12
+ * host: irc server host
13
+ * port: irc server port
14
+ * nick: nick name for this bot
15
+ * user: user name for this bot
16
+ * real: real name for this bot
17
+ * help: help message for this bot
18
+ * channels: startup channel names
19
+ * plugins: plugin names
11
20
 
12
21
 
13
22
  Usage
14
23
  =====
15
24
 
16
- ircbot -f config/xxx.dat
25
+ ircbot -f config/xxx.yml
17
26
 
18
27
 
19
- Command
20
- =======
28
+ Plugin
29
+ ======
21
30
 
22
- * (nick|realname).COMMAND arg
23
- # same as `arg > (nick|realname).COMMAND'
24
- * (nick|realname).help
25
- * (nick|realname).restart(CPI_NAME = nil)
26
- * (nick|realname).register(CPI_NAME)
27
- * (nick|realname).remove(CPI_NAME)
31
+ In ircbot world, we define functions as plugin (Ircbot::Plugin).
28
32
 
33
+ Instance methods:
34
+ * reply : this method is called when privmsg event is fired,
35
+ and reply message(the returned string) to the channel.
36
+ args: [text, nick, message object]
29
37
 
30
- CPI
31
- ===
38
+ * help : used from "plugins" plugin
32
39
 
33
- In ircbot's world, we define modules as cpi.
40
+ Accessor methods:
34
41
 
42
+ * message : message object same as 3rd argument
43
+ * direct? : whether the message is directly toward to the bot or not
44
+ * config : hash of given config file
35
45
 
36
46
 
37
- Notice
38
- ======
47
+ Example
48
+ =======
39
49
 
40
- Main code and cpi modules should be euc-japan (KCODE=e).
50
+ When you want echo bot, define the function as plugin first.
41
51
 
52
+ plugins/echo.rb:
42
53
 
43
- Author
44
- ======
54
+ class EchoPlugin < Ircbot::Plugin
55
+ def reply(text)
56
+ text
57
+ end
58
+ end
59
+
60
+
61
+
62
+ Required
63
+ ========
64
+
65
+ * irc-net gem
45
66
 
46
- maiha@wota.jp
47
67
 
68
+ Authors: maiha@wota.jp
69
+ Links: http://github.com/maiha/ircbot
data/Rakefile CHANGED
@@ -7,9 +7,11 @@ require 'rake/gempackagetask'
7
7
  GEM_NAME = "ircbot"
8
8
  AUTHOR = "maiha"
9
9
  EMAIL = "maiha@wota.jp"
10
- HOMEPAGE = "http://github.com/maiha/ircbot"
11
- SUMMARY = "old fashioned irc bot"
12
- GEM_VERSION = "0.0.2"
10
+ SUMMARY = "easy irc bot framework"
11
+
12
+ require File.dirname(__FILE__) + '/lib/ircbot/version'
13
+ GEM_VERSION = Ircbot::VERSION
14
+ HOMEPAGE = Ircbot::HOMEPAGE
13
15
 
14
16
  spec = Gem::Specification.new do |s|
15
17
  s.rubyforge_project = 'asakusarb'
@@ -20,13 +22,14 @@ spec = Gem::Specification.new do |s|
20
22
  s.has_rdoc = true
21
23
  s.extra_rdoc_files = ["README", "MIT-LICENSE"]
22
24
  s.summary = SUMMARY
23
- s.description = s.summary
25
+ s.description = "An irc bot framework that offers easy-to-use by plugins"
24
26
  s.author = AUTHOR
25
27
  s.email = EMAIL
26
28
  s.homepage = HOMEPAGE
27
29
  s.require_path = 'lib'
28
- s.add_dependency('activesupport', '>= 2.0.0')
29
- s.files = %w(MIT-LICENSE README Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
30
+ s.add_dependency('extlib', '>= 0.9.14')
31
+ s.add_dependency('net-irc', '>= 0.0.9')
32
+ s.files = %w(MIT-LICENSE README Rakefile) + Dir.glob("{lib,spec,plugins}/**/*")
30
33
  end
31
34
 
32
35
  Rake::GemPackageTask.new(spec) do |pkg|
data/bin/ircbot CHANGED
@@ -1,21 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
- # clear ARGV for Irb
3
2
 
4
3
  require 'ircbot'
5
4
 
6
- $KCODE = 'e'
7
-
8
- # Sync
9
- STDOUT.sync = true
10
- STDERR.sync = true
11
-
12
- debug = nil
13
5
  config = nil
14
- cpi = Pathname(Dir.getwd) + "cpi"
6
+ plugin = Pathname(Dir.getwd) + "plugins"
15
7
 
16
8
  while (arg = ARGV.shift)
17
9
  case arg
18
- when /^-d$/ ; debug = true
19
10
  when /^-f$/ ; config = ARGV.shift
20
11
  when /^-c$/ ; cpi = ARGV.shift
21
12
  else
@@ -28,23 +19,8 @@ unless config
28
19
  raise "Specify your config file\nusage: #{$0} -f config/xxx.dat"
29
20
  end
30
21
 
31
- # set cpi directory
32
- Ircbot.push_path :cpi, cpi, "**/*.cpi"
33
-
34
-
35
- module Ircbot
36
- class Kicker < Ircbot::ReplyClient
37
- rescue_from(SocketError) {
38
- raise Ircbot::Recover, 30.minutes
39
- }
40
-
41
- rescue_from(Errno::EPIPE, Errno::ECONNRESET, Errno::ETIMEDOUT, IRC::AbnormalTerminated) {
42
- raise Ircbot::Recover, 300.minutes
43
- }
44
- end
45
- end
46
-
22
+ Ircbot.push_path(:plugin, plugin)
47
23
 
48
- irc = Ircbot::ReplyClient.read_config(config, debug)
24
+ irc = Ircbot::Client.from_file(config)
49
25
  irc.start
50
26
  puts "Bye"
@@ -1,8 +1,8 @@
1
-
2
1
  require 'nkf'
3
2
  require 'pathname'
4
3
  require 'rubygems'
5
- require 'active_support'
4
+ require 'extlib'
5
+ require 'extlib/dictionary'
6
6
 
7
7
  ######################################################################
8
8
  ### Load path
@@ -14,28 +14,25 @@ $LOAD_PATH.unshift __DIR__ unless
14
14
  $LOAD_PATH.include?(__DIR__) ||
15
15
  $LOAD_PATH.include?(File.expand_path(__DIR__))
16
16
 
17
- require 'ircbot/framework'
17
+ require "ircbot/framework"
18
+ require "ircbot/version"
18
19
 
20
+ Ircbot.push_path(:plugin, Ircbot.system_root + 'plugins')
21
+ Ircbot.toplevel_binding = binding
19
22
 
20
23
  ######################################################################
21
24
  ### IRC library
22
25
 
23
- require 'irc/irc'
24
- require 'irc/agent'
25
- require 'irc/client'
26
-
26
+ require "net/irc"
27
27
 
28
28
  ######################################################################
29
- ### Ircbot library
30
-
31
- require 'ircbot/core_ext/rand-polimorphism'
32
- require 'ircbot/core_ext/writefile'
33
- require 'ircbot/core_ext/digest'
34
- require 'ircbot/core_ext/irc'
29
+ ### Core ext
35
30
 
31
+ require "ircbot/core_ext/delegation" # from activesupport-2.3.5
32
+ require "ircbot/core_ext/extending" # from activesupport-2.3.5
33
+ require "ircbot/core_ext/message"
36
34
 
37
35
  ######################################################################
38
36
  ### Ircbot
39
37
 
40
- require 'ircbot/reply_client'
41
-
38
+ require "ircbot/client"
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "ircbot/plugin"
4
+ require "ircbot/plugins"
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
26
+
27
+ require "ircbot/client/encoding"
28
+ require "ircbot/client/commands"
29
+ require "ircbot/client/config"
30
+ require "ircbot/client/config/channels"
31
+ require "ircbot/client/config/plugins"
32
+ require "ircbot/client/plugins"
@@ -0,0 +1,34 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ ######################################################################
6
+ ### Convinient access to commands
7
+
8
+ def post(command, *params)
9
+ if params[1]
10
+ params[1] = encode(params[1]).strip
11
+ if config.multiline
12
+ params[1].split(/\n/).compact.each do |text|
13
+ params[1] = text
14
+ super(command, *params)
15
+ end
16
+ return
17
+ end
18
+ end
19
+
20
+ super(command, *params)
21
+ end
22
+
23
+ def notice(channel, text)
24
+ text = encode(text)
25
+ post NOTICE, channel, text
26
+ end
27
+
28
+ def privmsg(channel, text)
29
+ text = encode(text)
30
+ post PRIVMSG, channel, text
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ class Config
6
+ ######################################################################
7
+ ### Reader
8
+ def self.read(path)
9
+ path = Pathname(path)
10
+ ext = path.extname.delete(".")
11
+ ext = "yml" if ext.empty?
12
+
13
+ reader = "read_#{ext}"
14
+ if respond_to?(reader)
15
+ Mash.new(__send__(reader, path))
16
+ else
17
+ raise NotImplementedError, "Cannot read #{path}: Format(#{ext})is not supported"
18
+ end
19
+ end
20
+
21
+ def self.read_yml(path)
22
+ require 'yaml'
23
+ path = Pathname(path)
24
+ YAML.load(path.read{})
25
+ end
26
+
27
+ ######################################################################
28
+ ### Config
29
+ def initialize(obj)
30
+ @obj = obj
31
+ end
32
+
33
+ def [](key)
34
+ __send__(key)
35
+ end
36
+
37
+ private
38
+ def method_missing(*args)
39
+ @obj.__send__(*args)
40
+ end
41
+ end
42
+
43
+ def self.from_file(path)
44
+ new(Config.read(path))
45
+ end
46
+
47
+ def initialize(hash)
48
+ super(hash[:host], hash[:port], hash)
49
+ end
50
+
51
+ def config
52
+ @config ||= Config.new(opts)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+
6
+ ######################################################################
7
+ ### Config
8
+
9
+ class Config
10
+ def channels
11
+ case (val = super)
12
+ when Array
13
+ val
14
+ else
15
+ val.to_s.split
16
+ end
17
+ end
18
+ end
19
+
20
+ ######################################################################
21
+ ### Event
22
+
23
+ def on_rpl_welcome(m)
24
+ super
25
+
26
+ config.channels.each do |channel|
27
+ post JOIN, channel
28
+ end
29
+ end
30
+
31
+ ######################################################################
32
+ ### Command
33
+
34
+ def broadcast(text)
35
+ config.channels.each do |channel|
36
+ privmsg channel, text
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ class Config
6
+ def plugins
7
+ case (val = super)
8
+ when Array
9
+ val
10
+ else
11
+ val.to_s.split
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ ######################################################################
6
+ ### Character conversions
7
+
8
+ def decode(text)
9
+ NKF.nkf('-w', text.to_s)
10
+ end
11
+
12
+ def encode(text)
13
+ NKF.nkf('-j', text.to_s)
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,64 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ircbot
4
+ class Client
5
+ ######################################################################
6
+ ### Accessors
7
+
8
+ def plugins
9
+ @plugins ||= Plugins.new(self, config.plugins)
10
+ end
11
+
12
+ delegate :plugin!, :plugin, :to=>"plugins"
13
+
14
+
15
+ ######################################################################
16
+ ### Events
17
+
18
+ def on_privmsg(m)
19
+ super
20
+
21
+ text = decode(m.params[1].to_s)
22
+ args = [text, m.prefix.nick, m]
23
+
24
+ plugins_call_replies(args, m)
25
+ end
26
+
27
+ private
28
+ def plugins_call_replies(args, m)
29
+ text = catch(:halt) do
30
+ plugins.active.each do |plugin|
31
+ plugins_call_action(:reply, plugin, args, m, :reply=>true)
32
+ end
33
+ return true
34
+ end
35
+ m.reply(self, text) if text
36
+ end
37
+
38
+ def plugins_call_logs(args)
39
+ raise NotImplementedError, "obsoleted"
40
+ plugins.active.each do |plugin|
41
+ plugins_call_action(:log, plugin, args)
42
+ end
43
+ end
44
+
45
+ def plugins_call_action(type, plugin, args, m, opts = {})
46
+ plugin.message = m
47
+ arity = plugin.method(type).arity rescue return
48
+ reply = plugin.__send__(type, *args[0,arity])
49
+ m.reply(self, reply) if opts[:reply]
50
+ rescue Exception => e
51
+ type = (e.class == RuntimeError) ? 'Error' : "#{e.class}"
52
+ m.reply(self, "#{type}: #{e.message}")
53
+ plugins_rescue_action type, plugin, e
54
+ end
55
+
56
+ def plugins_rescue_action(type, plugin, e)
57
+ p [e.class, e.message, type, plugin]
58
+ at = e.backtraces rescue '(no backtraces)'
59
+ puts at
60
+ end
61
+
62
+ end
63
+ end
64
+