blur 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/library/blur.rb ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pp'
4
+ require 'yaml'
5
+ require 'socket'
6
+ require 'ostruct'
7
+
8
+ Dir.glob("#{File.dirname __FILE__}/blur/**/*.rb").each &method(:require)
9
+
10
+ module Blur
11
+ class << Version = [1,4]
12
+ def to_s; join '.' end
13
+ end
14
+
15
+ def self.connect options, &block
16
+ Client.new(options).tap do |client|
17
+ client.instance_eval &block
18
+ end.connect
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ require 'blur/handling'
4
+
5
+ module Blur
6
+ class Client
7
+ include Handling
8
+
9
+ attr_accessor :options, :networks
10
+
11
+ def initialize options
12
+ @options = options
13
+ @networks = []
14
+ @callbacks = {}
15
+ @connected = true
16
+
17
+ @options[:networks].each do |options|
18
+ @networks.<< Network.new options
19
+ end
20
+
21
+ trap 2, &method(:quit)
22
+ end
23
+
24
+ def connect
25
+ networks = @networks.select { |network| not network.connected? }
26
+
27
+ networks.each do |network|
28
+ network.delegate = self
29
+ network.connect
30
+ end
31
+
32
+ run_loop
33
+ end
34
+
35
+ def got_command network, command
36
+ puts "<- \e[1m#{network}\e[0m | #{command}"
37
+ name = :"got_#{command.name.downcase}"
38
+
39
+ if respond_to? name
40
+ __send__ name, network, command
41
+ end
42
+ end
43
+
44
+ def quit signal
45
+ @networks.each do |network|
46
+ network.transmit :QUIT, "Got SIGINT?"
47
+ network.transcieve
48
+ network.disconnect
49
+ end
50
+
51
+ @connected = false
52
+
53
+ exit 0
54
+ end
55
+
56
+ private
57
+
58
+ def run_loop
59
+ puts "Starting run loop ..."
60
+
61
+ while @connected
62
+ @networks.each do |network|
63
+ begin
64
+ network.transcieve
65
+ sleep 0.05
66
+ rescue StandardError => exception
67
+ puts "#{network} threw an exception: #{exception.class.name} #{exception.message} #{exception.backtrace.to_s}"
68
+
69
+ network.disconnect if network.connected?
70
+ @networks.delete network
71
+ end
72
+ end
73
+ end
74
+
75
+ puts "Ended run loop ..."
76
+ end
77
+
78
+ def emit name, *args
79
+ @callbacks[name].each do |callback|
80
+ callback.call *args
81
+ end if @callbacks[name]
82
+ end
83
+
84
+ def catch name, &block
85
+ (@callbacks[name] ||= []) << block
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ class Exception
4
+ def line; backtrace.first.match(/^.*?:(\d+):/)[1].to_i end
5
+ end
6
+
7
+ class String
8
+ alias_method :starts_with?, :start_with?
9
+ end
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Client
5
+ module Handling
6
+
7
+ protected
8
+
9
+ # End of MOTD
10
+ def got_end_of_motd network, command
11
+ emit :connection_ready, network
12
+
13
+ network.options[:channels].each do |channel|
14
+ network.transmit :JOIN, channel
15
+ end
16
+ end
17
+
18
+ # The /NAMES list
19
+ def got_353 network, command
20
+ name = command[2]
21
+ users = command[3].split.map &Network::User.method(:new)
22
+
23
+ if channel = network.channel_by_name(name)
24
+ users.each do |user|
25
+ user.channel = channel
26
+ channel.users << user
27
+ end
28
+ else
29
+ network.channels.<< Network::Channel.new name, network, users
30
+ end
31
+ end
32
+
33
+ # Are we still breathing?
34
+ def got_ping network, command
35
+ network.transmit :PONG, command[0]
36
+ end
37
+
38
+ # Someone changed their nickname
39
+ def got_nick network, command
40
+ nick = command.sender.nickname
41
+
42
+ if channels = network.channels_with_user(nick)
43
+ channels.each do |channel|
44
+ if user = channel.user_by_nick(nick)
45
+ emit :user_rename, channel, user, command[0]
46
+ user.nick = command[0]
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Someone send a message
53
+ def got_privmsg network, command
54
+ return if command.sender.is_a? String # Ignore all server privmsgs
55
+
56
+ name, message = command.params
57
+
58
+ if channel = network.channel_by_name(name)
59
+ if user = channel.user_by_nick(command.sender.nickname)
60
+ emit :message, user, channel, message
61
+ else
62
+ # Odd… this shouldn't happen
63
+ end
64
+ end
65
+ end
66
+
67
+ # Someone joined a channel
68
+ def got_join network, command
69
+ name = command[0]
70
+ user = Network::User.new command.sender.nickname
71
+
72
+ if channel = network.channel_by_name(name)
73
+ user.name = command.sender.username
74
+ user.host = command.sender.hostname
75
+
76
+ channel.users << user
77
+
78
+ emit :user_entered, channel, user
79
+ end
80
+ end
81
+
82
+ # Someone left a channel
83
+ def got_part network, command
84
+ name = command[0]
85
+
86
+ if channel = network.channel_by_name(name)
87
+ if user = channel.user_by_nick(command.sender.nickname)
88
+ channel.users.delete user
89
+
90
+ emit :user_left, channel, user
91
+ end
92
+ end
93
+ end
94
+
95
+ # Someone quit irc
96
+ def got_quit network, command
97
+ nick = command.sender.nickname
98
+
99
+ if channels = network.channels_with_user(nick)
100
+ channels.each do |channel|
101
+ if user = channel.user_by_nick(nick)
102
+ channel.users.delete user
103
+
104
+ emit :user_quit, channel, user
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ alias_method :got_422, :got_end_of_motd
111
+ alias_method :got_376, :got_end_of_motd
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class ConnectionError < StandardError; end
6
+ attr_accessor :options, :channels, :delegate, :connection
7
+
8
+ def connected?; @connection.established? end
9
+
10
+ def host; @options[:hostname] end
11
+ def port; @options[:port] ||= (@options[:secure] == true) ? 6697 : 6667 end
12
+
13
+ def initialize options = {}
14
+ @options = options
15
+
16
+ unless options[:nickname]
17
+ raise ArgumentError, "nickname is missing from the network's option block"
18
+ end
19
+
20
+ @options[:username] ||= @options[:nickname]
21
+ @options[:realname] ||= @options[:username]
22
+ @options[:channels] ||= []
23
+
24
+ @channels = []
25
+ @connection = Connection.new self, host, port
26
+ end
27
+
28
+ def say recipient, message
29
+ transmit :PRIVMSG, recipient, message
30
+ end
31
+
32
+ def got_command command
33
+ @delegate.got_command self, command
34
+ end
35
+
36
+ def channel_by_name name
37
+ @channels.find { |channel| channel.name == name }
38
+ end
39
+
40
+ def channels_with_user nick
41
+ @channels.select { |channel| channel.user_by_nick nick }
42
+ end
43
+
44
+ def connect
45
+ @connection.establish
46
+
47
+ transmit :PASS, @options[:password] if @options[:password]
48
+ transmit :NICK, @options[:nickname]
49
+ transmit :USER, @options[:username], :void, :void, @options[:realname]
50
+ end
51
+
52
+ def disconnect
53
+ @connection.terminate
54
+ end
55
+
56
+ def transmit name, *arguments
57
+ command = Command.new name, arguments
58
+ puts "-> \e[1m#{self}\e[0m | #{command}"
59
+
60
+ @connection.transmit command
61
+ end
62
+
63
+ def transcieve
64
+ @connection.transcieve
65
+ end
66
+
67
+ def to_s
68
+ %{#<#{self.class.name} "#{host}:#{port}">}
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Channel
6
+ attr_accessor :name, :users
7
+
8
+ def initialize name, network = nil, users = []
9
+ @name = name
10
+ @users = users
11
+ @network = network
12
+
13
+ users.each { |user| user.channel = self }
14
+ end
15
+
16
+ def say message
17
+ @network.say self, message
18
+ end
19
+
20
+ def user_by_nick nick
21
+ @users.find { |user| user.nick == nick }
22
+ end
23
+
24
+ def inspect
25
+ %{#<#{self.class.name} @name=#{@name.inspect} @users=#{@users.inspect}}
26
+ end
27
+
28
+ def to_s
29
+ @name
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Command
6
+ attr_accessor :name, :params, :prefix
7
+
8
+ Pattern = /^(?:[:@]([^\s]+) )?([^\s]+)(?: ((?:[^:\s][^\s]* ?)*))?(?: ?:(.*))?$/
9
+
10
+ def self.parse data
11
+ match = data.strip.match Pattern
12
+ prefix, name, args, extra = match.captures
13
+ params = extra ? args.split << extra : args.split
14
+
15
+ new(name, params).tap do |this|
16
+ this.prefix = prefix
17
+ end
18
+ end
19
+
20
+ def [] index; @params[index] end
21
+
22
+ def initialize name, params = []
23
+ @name, @params = name, params
24
+ end
25
+
26
+ def sender
27
+ return @sender if @sender
28
+
29
+ if prefix =~ /^(\S+)!(\S+)@(\S+)$/
30
+ @sender = OpenStruct.new nickname: $1, username: $2, hostname: $3
31
+ else
32
+ @sender = prefix
33
+ end
34
+ end
35
+
36
+ def to_s
37
+ String.new.tap do |line|
38
+ line << "#{prefix} " if prefix
39
+ line << name.to_s
40
+
41
+ params.each_with_index do |param, index|
42
+ line << ' '
43
+ line << ?: if index == params.length - 1 and param =~ /[ :]/
44
+ line << param.to_s
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Connection
6
+ def established?; @socket and not (@socket.closed? or @socket.eof?) end
7
+
8
+ def initialize delegate, host = nil, port = nil
9
+ @host = host
10
+ @port = port
11
+ @queue = []
12
+ @buffer = ""
13
+ @socket = nil
14
+ @delegate = delegate
15
+ end
16
+
17
+ def establish
18
+ @socket = TCPSocket.new @host, @port
19
+ end
20
+
21
+ def terminate
22
+ @socket.close
23
+ @socket = nil
24
+ end
25
+
26
+ def transmit command
27
+ @queue.push command
28
+ end
29
+
30
+ def transcieve
31
+ readable, writable = IO.select [@socket], [@socket]
32
+
33
+ # If the socket is ready to recieve, do so.
34
+ if socket = readable.first
35
+ @buffer.<< socket.read_nonblock 512
36
+
37
+ while index = @buffer.index(?\n)
38
+ command = Command.parse @buffer.slice! 0..index
39
+ @delegate.got_command command
40
+ end
41
+ end
42
+
43
+ # If it's ready to write, do that too until the outoing queue is empty.
44
+ if socket = writable.first
45
+ socket.write_nonblock "#{command}\n" while command = @queue.shift
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class User
6
+ attr_accessor :nick, :name, :host, :channel
7
+
8
+ def initialize nick
9
+ @nick = nick.sub /^[@|~|\+|%|&]/, ''
10
+ end
11
+
12
+ def synchronize sender
13
+ @nick, @name, @host = sender.nickname, sender.username, sender.hostname
14
+ end
15
+
16
+ def inspect
17
+ %{#<#{self.class.name} @nick=#{@nick.inspect} @channel=#{@channel.name.inspect}>}
18
+ end
19
+
20
+ def to_s
21
+ @nick
22
+ end
23
+ end
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blur
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 4
8
+ version: "1.4"
9
+ platform: ruby
10
+ authors:
11
+ - Mikkel Kroman
12
+ autorequire:
13
+ bindir: executables
14
+ cert_chain: []
15
+
16
+ date: 2011-01-17 00:00:00 +01:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description:
21
+ email: mk@maero.dk
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files: []
27
+
28
+ files:
29
+ - library/blur/client.rb
30
+ - library/blur/enhancements.rb
31
+ - library/blur/handling.rb
32
+ - library/blur/network/channel.rb
33
+ - library/blur/network/command.rb
34
+ - library/blur/network/connection.rb
35
+ - library/blur/network/user.rb
36
+ - library/blur/network.rb
37
+ - library/blur.rb
38
+ has_rdoc: true
39
+ homepage:
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - library
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 1
54
+ - 9
55
+ - 1
56
+ version: 1.9.1
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.7
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Extensible IRC library
72
+ test_files: []
73
+