irc 0.0.1

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.
@@ -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: []