radamant-smirc 0.0.0

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -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.
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = smirc
2
+
3
+ Description goes here.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Adam Pearson. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,51 @@
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
+
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ if File.exist?('VERSION.yml')
40
+ config = YAML.load(File.read('VERSION.yml'))
41
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
42
+ else
43
+ version = ""
44
+ end
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "smirc #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
51
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -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
data/lib/smirc.rb ADDED
@@ -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'
data/smirc.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{smirc}
5
+ s.version = "0.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Adam Pearson"]
9
+ s.date = %q{2009-06-29}
10
+ s.email = %q{ampearson@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".document",
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README.rdoc",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "lib/smirc.rb",
23
+ "lib/smirc/client.rb",
24
+ "lib/smirc/queue.rb",
25
+ "smirc.gemspec",
26
+ "spec/client_spec.rb",
27
+ "spec/queue_spec.rb",
28
+ "spec/smirc_spec.rb",
29
+ "spec/spec.opts",
30
+ "spec/spec_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/radamant/smirc}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.3}
36
+ s.summary = %q{A Simple IRC Client Library for RUby}
37
+ s.test_files = [
38
+ "spec/client_spec.rb",
39
+ "spec/queue_spec.rb",
40
+ "spec/smirc_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<mash>, [">= 0"])
50
+ s.add_runtime_dependency(%q<eventful>, [">= 0"])
51
+ else
52
+ s.add_dependency(%q<mash>, [">= 0"])
53
+ s.add_dependency(%q<eventful>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<mash>, [">= 0"])
57
+ s.add_dependency(%q<eventful>, [">= 0"])
58
+ end
59
+ end
@@ -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
data/spec/spec.opts ADDED
@@ -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,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radamant-smirc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Pearson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-29 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mash
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: eventful
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description:
36
+ email: ampearson@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - lib/smirc.rb
52
+ - lib/smirc/client.rb
53
+ - lib/smirc/queue.rb
54
+ - smirc.gemspec
55
+ - spec/client_spec.rb
56
+ - spec/queue_spec.rb
57
+ - spec/smirc_spec.rb
58
+ - spec/spec.opts
59
+ - spec/spec_helper.rb
60
+ has_rdoc: false
61
+ homepage: http://github.com/radamant/smirc
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: A Simple IRC Client Library for RUby
86
+ test_files:
87
+ - spec/client_spec.rb
88
+ - spec/queue_spec.rb
89
+ - spec/smirc_spec.rb
90
+ - spec/spec_helper.rb