smirc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Adam Pearson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,47 @@
1
+ = smirc
2
+
3
+ A simple Ruby IRC client.
4
+
5
+ Features:
6
+ * Message Queueing to prevent flood disconnects
7
+ * Simple event handling
8
+ * No DSL required, easy access to Irc#join and Irc#message
9
+
10
+
11
+ == Example
12
+
13
+ options = {
14
+ :server => "my.irc.net",
15
+ :nickname => "Hal",
16
+ :realname => "Daisy, Daisy",
17
+ :port => 6667,
18
+ }
19
+
20
+ @irc = Smirc::Client.new(options)
21
+ @irc.on(:connect) do |irc|
22
+ irc.join("#mychannel")
23
+ end
24
+
25
+ @irc.on(:message) do |irc, channel, message, user|
26
+ case message
27
+ when /open the bomb-bay doors/
28
+ irc.message(channel, "I'm sorry, I cannot do that, Dave")
29
+ end
30
+ end
31
+
32
+ begin
33
+ @irc.connect
34
+ ensure
35
+ @irc.disconnect
36
+ end
37
+
38
+
39
+
40
+
41
+ == Contributions and Credit
42
+
43
+ This gem is based heavily on ichverstehe's Isaac gem. There's no way this would be written without that gem as a reference.
44
+
45
+ == Copyright
46
+
47
+ Copyright (c) 2009 Adam Pearson. See LICENSE for details.
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "smirc"
8
+ gem.summary = "A Simple IRC Client Library for RUby"
9
+ gem.email = "ampearson@gmail.com"
10
+ gem.homepage = "http://github.com/radamant/smirc"
11
+ gem.authors = ["Adam Pearson"]
12
+ gem.add_dependency('mash')
13
+ gem.add_dependency('eventful')
14
+ gem.add_development_dependency "rspec", ">= 1.2.9"
15
+
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ if File.exist?('VERSION.yml')
42
+ config = YAML.load(File.read('VERSION.yml'))
43
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
44
+ else
45
+ version = ""
46
+ end
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "smirc #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
53
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,7 @@
1
+ require 'socket'
2
+ require 'rubygems'
3
+ require 'eventful'
4
+ require 'mash'
5
+
6
+ require 'smirc/queue'
7
+ require 'smirc/client'
@@ -0,0 +1,124 @@
1
+ module Smirc
2
+ # A Simple Irc Client
3
+ # Events:
4
+ # <tt>:connected</tt>
5
+ # Fires when a connection has successfully been made
6
+ #
7
+ # <tt>:message</tt> |irc, channel, message, user|
8
+ # Fires when a PRIVMSG is sent from the server
9
+ #
10
+ # <tt>:log</tt> |irc, message|
11
+ # Fires when message is logged by the client
12
+ #
13
+ # TODO:
14
+ # * Implement Queueing (based on Isaac gem)
15
+ # * Add :error event
16
+ #
17
+ class Client
18
+ include Eventful
19
+ attr_accessor :queue
20
+
21
+ # Configuration options
22
+ # * :server
23
+ # * :nickname
24
+ # * :realname
25
+ # * :port
26
+ # * :password
27
+ def initialize(configuration={})
28
+ @configuration = Mash.new(configuration)
29
+ @queue = Smirc::Queue.new
30
+
31
+ @queue.on(:lock) { send("PING :#{@configuration.server}\r\n") }
32
+ @queue.on(:send) { |q, msg| send(msg) }
33
+ end
34
+
35
+ # Attempt to connect to the server. Will fire :connect if successful
36
+ def connect
37
+ @registrations = []
38
+ @registered = false
39
+
40
+ server = config.server || 'localhost'
41
+ port = config.port || 6667
42
+
43
+ log("Connecting to #{server} #{port}")
44
+ @socket = TCPSocket.new(server, port)
45
+
46
+ send("PASS #{config.password}\r\n") if config.password
47
+ send("NICK #{config.nickname}\r\n")
48
+ send("USER #{config.nickname} 0 * :#{config.realname}\r\n")
49
+
50
+ listen
51
+ end
52
+
53
+ def config
54
+ return @configuration
55
+ end
56
+
57
+ # Disconnect from the server
58
+ def disconnect
59
+ send("QUIT\r\n")
60
+ log "Disconnecting"
61
+ @socket.close
62
+ end
63
+
64
+
65
+ # Send a message to <tt>channel</tt> with <tt>text</tt>
66
+ def message(channel, text)
67
+ @queue << "PRIVMSG #{channel} :#{text}\r\n"
68
+ end
69
+
70
+ # Join the <tt>channel</tt>
71
+ def join (channel)
72
+ send ("JOIN #{channel}\r\n")
73
+ end
74
+
75
+
76
+ def parse(line)
77
+ log "<- #{line}"
78
+ case line.chomp
79
+ when /(^:\S+ )?00([1-4])/
80
+ @registrations << $2.to_i
81
+ when /(^:(\S+)!\S+ )?PRIVMSG \S+ :?\001VERSION\001/
82
+ send "NOTICE #{$2} :\001VERSION ruby.irk\001"
83
+ when /^PING (\S+)/
84
+ send "PONG #{$1}\r\n"
85
+ @queue.unlock
86
+ when /(^:\S+)?PONG/
87
+ @queue.unlock
88
+
89
+ when /(^:(\S+)!(\S+) )?PRIVMSG (\S+) :?(.*)/
90
+ env = Mash.new({ :nick => $2, :userhost => $3, :channel => $4, :message => $5 })
91
+ type = env[:channel].match(/^#/) ? :channel : :private
92
+ fire(:message, env.channel, env.message, env.nick)
93
+ when /(^:\S+ )?([4-5]\d\d) \S+ (\S+)/
94
+ env = {:error => $2.to_i, :message => $2, :nick => $3, :channel => $3}
95
+ fire(:error, env)
96
+ end
97
+ end
98
+
99
+
100
+ private
101
+
102
+ def log(message)
103
+ fire(:log, message)
104
+ end
105
+
106
+ def listen
107
+ while(line = @socket.gets)
108
+ parse(line)
109
+ if !@registered && ([1,2,3,4] - @registrations).empty?
110
+ fire(:connected)
111
+ @registered = true
112
+ end
113
+ end
114
+ end
115
+
116
+
117
+ def send(data)
118
+ log "-> #{data}"
119
+ @socket.print(data)
120
+ end
121
+
122
+
123
+ end
124
+ end
@@ -0,0 +1,66 @@
1
+ module Smirc
2
+ class Queue
3
+ include Eventful
4
+ attr_accessor :locked, :messages, :transferred, :limit
5
+
6
+ def initialize
7
+ @locked = false
8
+ @messages = []
9
+ @transferred = 0
10
+ @limit = 1400
11
+ end
12
+
13
+ def lock
14
+ @locked = true
15
+ fire(:lock)
16
+ end
17
+
18
+ def unlock
19
+ @locked = false
20
+ @transferred = 0
21
+ fire(:unlock)
22
+ invoke
23
+ end
24
+
25
+ def locked?
26
+ @locked
27
+ end
28
+
29
+ def <<(message)
30
+ @messages << message
31
+ invoke
32
+ end
33
+
34
+ def size
35
+ @messages.size
36
+ end
37
+
38
+ def should_invoke?
39
+ !locked? && size > 0
40
+ end
41
+
42
+
43
+ def invoke
44
+ while(should_invoke?) do
45
+ unless limit_exceeded?(messages.first.size)
46
+ message = messages.shift
47
+ send(message) unless limit_exceeded?
48
+ @transferred += message.size
49
+ lock if limit_exceeded?
50
+ else
51
+ lock
52
+ end
53
+ end
54
+ end
55
+
56
+ def limit_exceeded?(additional = 0)
57
+ @transferred + additional > @limit
58
+ end
59
+
60
+ def send(message)
61
+ fire(:send, message)
62
+ end
63
+
64
+
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{smirc}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Adam Pearson"]
12
+ s.date = %q{2010-02-27}
13
+ s.email = %q{ampearson@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/smirc.rb",
26
+ "lib/smirc/client.rb",
27
+ "lib/smirc/queue.rb",
28
+ "smirc.gemspec",
29
+ "spec/client_spec.rb",
30
+ "spec/queue_spec.rb",
31
+ "spec/smirc_spec.rb",
32
+ "spec/spec.opts",
33
+ "spec/spec_helper.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/radamant/smirc}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.6}
39
+ s.summary = %q{A Simple IRC Client Library for RUby}
40
+ s.test_files = [
41
+ "spec/client_spec.rb",
42
+ "spec/queue_spec.rb",
43
+ "spec/smirc_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_runtime_dependency(%q<mash>, [">= 0"])
53
+ s.add_runtime_dependency(%q<eventful>, [">= 0"])
54
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
55
+ else
56
+ s.add_dependency(%q<mash>, [">= 0"])
57
+ s.add_dependency(%q<eventful>, [">= 0"])
58
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<mash>, [">= 0"])
62
+ s.add_dependency(%q<eventful>, [">= 0"])
63
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
64
+ end
65
+ end
66
+
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Smirc::Client do
4
+
5
+ context "with flood-prevention queue" do
6
+ before(:each) do
7
+ @client = Smirc::Client.new(:server => 'foo')
8
+ @client.stub!(:send)
9
+ end
10
+
11
+ it "should ping the server when the queue is locked" do
12
+ @client.should_receive(:send).with("PING :foo\r\n")
13
+ @client.queue.lock
14
+ end
15
+
16
+ it "should unlock the queue when a pong is received from the server" do
17
+ @client.queue.should_receive(:unlock)
18
+ @client.parse("PONG")
19
+ end
20
+
21
+ it "should unlock the queue when a ping is received from the server" do
22
+ @client.queue.should_receive(:unlock)
23
+ @client.parse("PING :foo")
24
+ end
25
+
26
+ it "should pass messages through the queue before directly sending them" do
27
+ @client.should_not_receive(:send)
28
+ @client.queue.should_receive(:<<)
29
+ @client.queue.stub!(:invoke)
30
+ @client.message("#random", "message")
31
+ end
32
+
33
+ it "should call #send when the queue fires :send" do
34
+ @client.should_receive(:send).and_return(true)
35
+ @client.queue.fire(:send, "foo")
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Smirc::Queue do
4
+ before(:each) do
5
+ @queue = Smirc::Queue.new()
6
+ end
7
+
8
+ context "#invoke" do
9
+ before(:each) do
10
+ @queue.messages = %w(foo bar you baz)
11
+ end
12
+
13
+ it "should lock if message size has exceeded limit" do
14
+ @queue.transferred = @queue.limit - 2
15
+ @queue << "foo"
16
+ @queue.locked?.should be_true
17
+ end
18
+
19
+ it "should send messages to the server if limit has not been exceeded" do
20
+ @queue.should_receive(:send).exactly(4).times
21
+ @queue.stub!(:limit_exceeded?).and_return(false)
22
+ @queue.invoke
23
+ end
24
+
25
+ it "should not send messages to the server if limit has been exceeded" do
26
+ @queue.should_not_receive(:send)
27
+ @queue.stub!(:limit_exceeded?).and_return(true)
28
+ @queue.invoke
29
+ end
30
+
31
+ it "should not shift the queue if the limit would be exceeded" do
32
+ @queue.transferred = @queue.limit - 2
33
+ lambda{ @queue.invoke}.should_not change(@queue, :size)
34
+ end
35
+
36
+ it "should increase transferred amount with each message" do
37
+ lambda{ @queue.invoke}.should change(@queue, :transferred).by(12)
38
+ end
39
+
40
+
41
+ end
42
+
43
+ it "should add messages to the queue when << is called" do
44
+ @queue.stub!(:invoke)
45
+ lambda{
46
+ @queue << "hi message"
47
+ }.should change(@queue, :size).by(1)
48
+ end
49
+
50
+ it "should invoke messages when << is called" do
51
+ @queue.should_receive(:invoke)
52
+ @queue << "foo"
53
+ end
54
+
55
+ context "#lock" do
56
+ it "should lock when #lock is called" do
57
+ Smirc::Queue.new.lock
58
+ @queue.lock
59
+ @queue.locked?.should be_true
60
+ end
61
+ it "should fire the :lock event" do
62
+ @event_handled = false
63
+ @queue.on(:lock) { @event_handled = true }
64
+ @queue.lock
65
+ @event_handled.should be_true
66
+ end
67
+ end
68
+
69
+ context "#unlock" do
70
+ it "should unlock when #unlock is called" do
71
+ @queue.lock
72
+ @queue.unlock
73
+ @queue.locked?.should be_false
74
+ end
75
+
76
+ it "should invoke when unlock is called" do
77
+ @queue.should_receive(:invoke)
78
+ @queue.unlock
79
+ end
80
+
81
+ it "should reset transfer counter" do
82
+ @queue.transferred = 60
83
+ @queue.unlock
84
+ @queue.transferred.should == 0
85
+ end
86
+
87
+ it "should fire :unlock when unlock is called" do
88
+ @event_handled = false
89
+ @queue.on(:unlock) { @event_handled = true}
90
+ @queue.unlock
91
+ @event_handled.should be_true
92
+ end
93
+
94
+ end
95
+
96
+ context "#send" do
97
+ it "should fire :send with the given message" do
98
+ @queue.on(:send) { |q, msg| @message = msg}
99
+ @queue.send("foo")
100
+ @message.should == "foo"
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Smirc" do
4
+ #it "fails" do
5
+ #fail "hey buddy, you should probably rename this file and start specing for real"
6
+ #end
7
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ require 'spec'
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require 'smirc'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smirc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Adam Pearson
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-02-27 00:00:00 -08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mash
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: eventful
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: rspec
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 1
53
+ - 2
54
+ - 9
55
+ version: 1.2.9
56
+ type: :development
57
+ version_requirements: *id003
58
+ description:
59
+ email: ampearson@gmail.com
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ extra_rdoc_files:
65
+ - LICENSE
66
+ - README.rdoc
67
+ files:
68
+ - .document
69
+ - .gitignore
70
+ - LICENSE
71
+ - README.rdoc
72
+ - Rakefile
73
+ - VERSION
74
+ - lib/smirc.rb
75
+ - lib/smirc/client.rb
76
+ - lib/smirc/queue.rb
77
+ - smirc.gemspec
78
+ - spec/client_spec.rb
79
+ - spec/queue_spec.rb
80
+ - spec/smirc_spec.rb
81
+ - spec/spec.opts
82
+ - spec/spec_helper.rb
83
+ has_rdoc: true
84
+ homepage: http://github.com/radamant/smirc
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options:
89
+ - --charset=UTF-8
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.3.6
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: A Simple IRC Client Library for RUby
113
+ test_files:
114
+ - spec/client_spec.rb
115
+ - spec/queue_spec.rb
116
+ - spec/smirc_spec.rb
117
+ - spec/spec_helper.rb