irc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ Usage
2
+ =====
3
+
4
+ ## Quickstart
5
+ ``` ruby
6
+ require 'irc'
7
+
8
+ host 'localhost'
9
+ nick 'MyBot'
10
+ channel '#MyChannel', '#OtherChannel'
11
+
12
+ # Say hi when somebody joins the channel:
13
+ on :join do
14
+ say "Hi #{nick}!"
15
+ end
16
+
17
+ # Tell the time and date:
18
+ match /^!(?:time|now)/ do
19
+ reply Time.now.strftime("it is %l:%M %P on %A, %B %-d, %Y.").gsub(/[ ]+/, ' ' )
20
+ end
21
+
22
+ start!
23
+ ```
24
+ Then, `ruby newbot.rb`
25
+
26
+
27
+ ## Subclass
28
+
29
+ You can also `require 'irc/base'` and subclass `IRC::Bot`:
30
+ ``` ruby
31
+ require 'irc/base'
32
+
33
+ class MyBot < IRC::Bot
34
+ host 'localhost'
35
+ nick 'MyBot'
36
+ channel '#MyChannel'
37
+
38
+ start!
39
+ end
40
+ ```
41
+
42
+ You can re-load the bot to update its callbacks without disconnecting:
43
+ ``` ruby
44
+ # mention_match requires messages to start with the name of the bot
45
+ mention_match /reload!/ do
46
+ self.class.reset!
47
+
48
+ load __FILE__
49
+ end
50
+ ```
@@ -0,0 +1,17 @@
1
+ require 'irc/base'
2
+
3
+ class NewBot < IRC::Bot
4
+
5
+ end
6
+
7
+ module IRC
8
+ module Delegator
9
+ NewBot.public_methods.each do |method_name|
10
+ define_method method_name do |*args, &block|
11
+ NewBot.send method_name, *args, &block
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ extend IRC::Delegator
@@ -0,0 +1,6 @@
1
+ require 'irc/extensions'
2
+
3
+ require 'irc/connection'
4
+ require 'irc/callback'
5
+ require 'irc/message'
6
+ require 'irc/bot'
@@ -0,0 +1,114 @@
1
+ module IRC
2
+ class Bot
3
+ attr_reader :message
4
+
5
+ def initialize message
6
+ @message = message
7
+ end
8
+
9
+ def stop
10
+ Thread.current.kill
11
+ end
12
+
13
+ def say something, recipients = nil
14
+ message.connection.privmsg something, recipients || self.class.channels
15
+ end
16
+
17
+ def reply something, mention = true
18
+ if message.middle == self.class.nick
19
+ say something, message.nick
20
+ elsif mention
21
+ say "#{message.nick}, #{something}", message.middle
22
+ else
23
+ say something, message.middle
24
+ end
25
+ end
26
+
27
+ def store namespace = nil
28
+ @store ||= IRC::Store.store
29
+
30
+ if namespace
31
+ (@namespace ||= {})[namespace] ||= Redis::Namespace.new(namespace, redis: @store)
32
+ else
33
+ @store
34
+ end
35
+ end
36
+
37
+ def conjugate noun, lookup = nil
38
+ lookup ||= {
39
+ 'me' => nick,
40
+ 'you' => self.class.nick,
41
+ nick => 'you'
42
+ }
43
+ noun.gsub /[\w]+/i, lookup
44
+ end
45
+
46
+ def method_missing method_name, *args
47
+ message.public_send method_name, *args
48
+ end
49
+
50
+ class << self
51
+ attr_accessor :nick, :host, :port, :channels
52
+
53
+ def start!
54
+ @connection ||= Connection.new @host, @port
55
+
56
+ on(:ping) { connection.pong params }
57
+
58
+ @connection.nick @nick
59
+ @connection.join @channels
60
+
61
+ @connection.listen
62
+ end
63
+
64
+ def reset!
65
+ Callback.reset!
66
+ @channels = []
67
+ end
68
+
69
+ def host _host = nil
70
+ puts " host: '#{_host}'"
71
+ @host = _host || @host
72
+ end
73
+
74
+ def port _port = nil
75
+ puts " port: '#{_port}'"
76
+ @port = _port || @port
77
+ end
78
+
79
+ def nick _nick = nil
80
+ puts " nick: '#{_nick}'" if _nick
81
+ @nick = _nick || @nick
82
+ end
83
+
84
+ def store _store, options = nil
85
+ require 'irc/store'
86
+
87
+ case _store
88
+ when :redis
89
+ IRC::Store.options = options
90
+ end
91
+ end
92
+
93
+ def channel *_channels
94
+ _channels.each do |c|
95
+ puts "channel: '#{c}'"
96
+ (@channels ||= []) << c
97
+ end
98
+ end
99
+
100
+ def match regex, &block
101
+ on(:privmsg, regex, &block)
102
+ end
103
+
104
+ def mention_match regex, &block
105
+ r = /^#{@nick}[,: ]*/ + regex
106
+ on(:privmsg, r, &block)
107
+ end
108
+
109
+ def on action, regex = nil, &block
110
+ Callback.add(action, regex, self, &block)
111
+ end
112
+ end # class << Bot
113
+ end # class Bot
114
+ end # module IRC
@@ -0,0 +1,57 @@
1
+ module IRC
2
+ class Callback
3
+ attr_accessor :action, :regex
4
+
5
+ def initialize action, regex = nil, factory = nil, &block
6
+ @action = action
7
+ @regex = regex || //
8
+ @block = block
9
+ @factory = factory
10
+ end
11
+
12
+ def call! message
13
+ if match = @regex.match(message.content)
14
+ (class << message; self; end).send :attr_accessor, *@regex.names
15
+ @regex.names.each do |name|
16
+ message.instance_variable_set("@#{name}", match[name])
17
+ end
18
+
19
+ Thread.new do
20
+ # begin
21
+ if @factory
22
+ @factory.new(message).instance_eval(&@block)
23
+ else
24
+ puts "calling #{@block}"
25
+ @block.call(message, match)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ class << self
32
+ attr_accessor :callbacks
33
+
34
+ def handle message
35
+ callbacks[message.action].each do |callback|
36
+ callback.call! message
37
+ end
38
+ end
39
+
40
+ def add action, *args, &block
41
+ callback = new(action, *args, &block)
42
+
43
+ callbacks[action] << callback
44
+ callbacks[:all] << callback
45
+ end
46
+
47
+ def callbacks
48
+ @callbacks ||= Hash.new {|hash,key| hash[key] = []}
49
+ end
50
+
51
+ def reset!
52
+ @callbacks = nil
53
+ callbacks
54
+ end
55
+ end # class << Callback
56
+ end # class Callback
57
+ end
@@ -0,0 +1,91 @@
1
+ require 'socket'
2
+ require 'thread'
3
+
4
+ module IRC
5
+ class Connection
6
+ def initialize host = nil, port = 6667
7
+ @host = host
8
+ @port = port
9
+ end
10
+
11
+ def mutex
12
+ @mutex ||= Mutex.new
13
+ end
14
+
15
+ def disconnected?
16
+ !@socket || @socket.closed?
17
+ end
18
+
19
+ def connected?
20
+ !disconnected?
21
+ end
22
+
23
+ def write *strings
24
+ # mutex do
25
+ strings.each do |string|
26
+ puts '-> ' + string
27
+ socket.print string + "\r\n"
28
+ end
29
+ # end
30
+ end
31
+
32
+ def join *channels
33
+ channels.flatten.each do |channel|
34
+ @channel = channel
35
+ write "JOIN #{channel}"
36
+ end
37
+ end
38
+
39
+ def part *channels
40
+ channels.flatten.each do |channel|
41
+ write "PART #{channel}"
42
+ end
43
+ end
44
+
45
+ def nick _nick, realname = nil
46
+ realname ||= _nick
47
+ write "NICK #{_nick}"
48
+ write "USER #{_nick} localhost #{@host} :#{realname}"
49
+ end
50
+
51
+ def privmsg content, *recipients
52
+ recipients = @channel unless recipients.any?
53
+ recipients = [recipients].flatten.join(',')
54
+
55
+ msg = "PRIVMSG #{recipients} :#{content}"
56
+ write msg.slice!(0,500)
57
+ privmsg msg, recipients if msg != ''
58
+ end
59
+
60
+ def quit message = nil
61
+ write "QUIT :#{message}"
62
+ end
63
+
64
+ def pong value
65
+ write "PONG #{value}"
66
+ end
67
+
68
+ def disconnect
69
+ quit
70
+ socket.close
71
+ end
72
+
73
+ def socket
74
+ @socket ||= TCPSocket.open(@host, @port)
75
+ end
76
+ Thread.abort_on_exception = true
77
+
78
+ def listen
79
+ unless @listening
80
+ loop do
81
+ @listening = true
82
+ socket.lines "\r\n" do |line|
83
+ message = Message.new(line, self)
84
+ Callback.handle message
85
+ end
86
+ @listening = false
87
+ end
88
+ end
89
+ end
90
+ end # class Connection
91
+ end
@@ -0,0 +1,33 @@
1
+ class Array
2
+ def to_sentence
3
+ case length
4
+ when 0
5
+ ''
6
+ when 1
7
+ self[0].to_s
8
+ when 2
9
+ "#{self[0]} and #{self[1]}"
10
+ else
11
+ "#{self[0..-2].join(', ')}, and #{self.last}"
12
+ end
13
+ end
14
+ end
15
+
16
+ class String
17
+ def pluralize number = 2
18
+ case number
19
+ when 0
20
+ "no #{self}s"
21
+ when 1
22
+ "1 #{self}"
23
+ else
24
+ "#{number} #{self}s"
25
+ end
26
+ end
27
+ end
28
+
29
+ class Regexp
30
+ def +(r)
31
+ Regexp.new(source + r.source)
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ module IRC
2
+ class Message
3
+ REGEX = /^
4
+ (:
5
+ (?<prefix>
6
+ (
7
+ (?<servername>(?<nick>[a-z][a-z0-9_\-\[\]\\`\^\{\}\.\|]*))
8
+ )
9
+ (!(?<user>[a-z0-9~\.]+))?
10
+ (@(?<host>[a-z0-9\.]+))?
11
+ )
12
+ [\ ]+
13
+ )?
14
+ (?<command>[a-z]+|[0-9]{3})
15
+ (?<params>
16
+ (\ +(?<middle>[^:\r\n\ ][^\r\n\ ]*))*
17
+ (\ *:(?<trailing>.+))?
18
+ )
19
+ \r\n$
20
+ /xi
21
+
22
+ attr_reader :raw
23
+ attr_accessor :connection
24
+ attr_accessor *REGEX.names
25
+
26
+ def initialize message_string, connection
27
+ @raw = message_string
28
+
29
+ @connection = connection
30
+ @match = REGEX.match(message_string) || {}
31
+
32
+ REGEX.names.each do |name|
33
+ instance_variable_set("@#{name}", @match[name])
34
+ end
35
+
36
+ end
37
+
38
+ def action
39
+ @action ||= (command || '').downcase.intern
40
+ end
41
+
42
+ def content
43
+ @content ||= trailing || middle
44
+ end
45
+ end # class Message
46
+ end
@@ -0,0 +1,24 @@
1
+ require 'redis'
2
+ require 'redis-namespace'
3
+
4
+ module IRC
5
+ class Store
6
+ attr_reader :store
7
+
8
+ def initialize options = {}
9
+ options = {:host => 'localhost', :port => 6379}.merge(options)
10
+ @store = Redis.new options
11
+ end
12
+
13
+ def method_missing method_name, *args, &block
14
+ store.send method_name, *args, &block
15
+ end
16
+
17
+ class << self
18
+ attr_accessor :options
19
+ def store
20
+ self.new options
21
+ end
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: irc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeff Peterson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: a simple ruby irc (bot framework)
15
+ email: jeff@petersonj.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.markdown
21
+ - lib/irc.rb
22
+ - lib/irc/base.rb
23
+ - lib/irc/bot.rb
24
+ - lib/irc/callback.rb
25
+ - lib/irc/connection.rb
26
+ - lib/irc/extensions.rb
27
+ - lib/irc/message.rb
28
+ - lib/irc/store.rb
29
+ homepage: http://github.com/jeffpeterson/irc
30
+ licenses: []
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 1.8.24
50
+ signing_key:
51
+ specification_version: 3
52
+ summary: a simple ruby irc (bot) framework
53
+ test_files: []