smirc 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,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