krtek 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/krtek.gemspec +75 -0
- data/lib/krtek.rb +24 -0
- data/lib/krtek/client.rb +102 -0
- data/lib/krtek/commands.rb +52 -0
- data/lib/krtek/handler.rb +32 -0
- data/lib/krtek/recepient.rb +6 -0
- data/lib/krtek/responses.rb +80 -0
- data/lib/support/dsl_accessor.rb +23 -0
- data/script/krtek_irb +3 -0
- data/script/krtek_irb.rb +27 -0
- data/spec/integration/client_integration.rb +65 -0
- data/spec/lib/krtek/client_spec.rb +164 -0
- data/spec/lib/krtek/commands_spec.rb +11 -0
- data/spec/lib/krtek/responses_spec.rb +30 -0
- data/spec/spec_helper.rb +7 -0
- metadata +154 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3-p286@krtek --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.8)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
diff-lcs (1.1.3)
|
8
|
+
eventmachine (0.12.10)
|
9
|
+
faker (1.1.2)
|
10
|
+
i18n (~> 0.5)
|
11
|
+
git (1.2.5)
|
12
|
+
i18n (0.6.1)
|
13
|
+
jeweler (1.8.4)
|
14
|
+
bundler (~> 1.0)
|
15
|
+
git (>= 1.2.5)
|
16
|
+
rake
|
17
|
+
rdoc
|
18
|
+
json (1.7.6)
|
19
|
+
multi_json (1.3.6)
|
20
|
+
rake (10.0.3)
|
21
|
+
rdoc (3.12)
|
22
|
+
json (~> 1.4)
|
23
|
+
rspec (2.11.0)
|
24
|
+
rspec-core (~> 2.11.0)
|
25
|
+
rspec-expectations (~> 2.11.0)
|
26
|
+
rspec-mocks (~> 2.11.0)
|
27
|
+
rspec-core (2.11.1)
|
28
|
+
rspec-expectations (2.11.2)
|
29
|
+
diff-lcs (~> 1.1.3)
|
30
|
+
rspec-mocks (2.11.2)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
activesupport
|
37
|
+
eventmachine
|
38
|
+
faker
|
39
|
+
jeweler
|
40
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Jiri Chara
|
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,19 @@
|
|
1
|
+
= krtek
|
2
|
+
|
3
|
+
Simple Irc Bot running on EventMachine
|
4
|
+
|
5
|
+
== Contributing to krtek
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
|
+
* Fork the project.
|
10
|
+
* Start a feature/bugfix branch.
|
11
|
+
* Commit and push until you are happy with your contribution.
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2013 Jiri Chara. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "krtek"
|
18
|
+
gem.homepage = "http://github.com/JiriChara/krtek"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Simple IRC Bot running on EventMachine}
|
21
|
+
gem.description = %Q{Simple, smart, easy-to-use, fully tested gem}
|
22
|
+
gem.email = "jirik.chara@gmail.com"
|
23
|
+
gem.authors = ["Jiri Chara"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rdoc/task'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "simple_shell #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/krtek.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "krtek"
|
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 = ["Jiri Chara"]
|
12
|
+
s.date = "2013-01-18"
|
13
|
+
s.description = "Simple, smart, easy-to-use, fully tested gem"
|
14
|
+
s.email = "jirik.chara@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"krtek.gemspec",
|
30
|
+
"lib/krtek.rb",
|
31
|
+
"lib/krtek/client.rb",
|
32
|
+
"lib/krtek/commands.rb",
|
33
|
+
"lib/krtek/handler.rb",
|
34
|
+
"lib/krtek/recepient.rb",
|
35
|
+
"lib/krtek/responses.rb",
|
36
|
+
"lib/support/dsl_accessor.rb",
|
37
|
+
"script/krtek_irb",
|
38
|
+
"script/krtek_irb.rb",
|
39
|
+
"spec/integration/client_integration.rb",
|
40
|
+
"spec/lib/krtek/client_spec.rb",
|
41
|
+
"spec/lib/krtek/commands_spec.rb",
|
42
|
+
"spec/lib/krtek/responses_spec.rb",
|
43
|
+
"spec/spec_helper.rb"
|
44
|
+
]
|
45
|
+
s.homepage = "http://github.com/JiriChara/krtek"
|
46
|
+
s.licenses = ["MIT"]
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
s.rubygems_version = "1.8.24"
|
49
|
+
s.summary = "Simple IRC Bot running on EventMachine"
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
s.specification_version = 3
|
53
|
+
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
|
56
|
+
s.add_runtime_dependency(%q<faker>, [">= 0"])
|
57
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
62
|
+
s.add_dependency(%q<faker>, [">= 0"])
|
63
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
65
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
69
|
+
s.add_dependency(%q<faker>, [">= 0"])
|
70
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
71
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
72
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
data/lib/krtek.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.expand_path '..', __FILE__
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'set'
|
7
|
+
require 'faker'
|
8
|
+
require 'active_support/core_ext/hash/keys'
|
9
|
+
require 'active_support/core_ext/object/blank'
|
10
|
+
require 'active_support/callbacks'
|
11
|
+
require 'active_support/deprecation'
|
12
|
+
require 'active_support/concern'
|
13
|
+
require 'active_support/core_ext/array/extract_options'
|
14
|
+
|
15
|
+
require 'krtek/commands'
|
16
|
+
require 'krtek/responses'
|
17
|
+
require 'krtek/client'
|
18
|
+
require 'krtek/handler'
|
19
|
+
|
20
|
+
|
21
|
+
module Krtek
|
22
|
+
module Irc
|
23
|
+
end
|
24
|
+
end
|
data/lib/krtek/client.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'support/dsl_accessor'
|
2
|
+
|
3
|
+
module Krtek
|
4
|
+
module Irc
|
5
|
+
class Client
|
6
|
+
include DslAccessor
|
7
|
+
include Commands::RFC1459
|
8
|
+
include Responses
|
9
|
+
|
10
|
+
attr_accessor :connection
|
11
|
+
attr_reader :channels
|
12
|
+
attr_reader :callbacks
|
13
|
+
attr_reader :username
|
14
|
+
|
15
|
+
dsl_accessor :host
|
16
|
+
dsl_accessor :port
|
17
|
+
dsl_accessor :ssl
|
18
|
+
dsl_accessor :realname
|
19
|
+
|
20
|
+
def initialize(opts = {}, &block)
|
21
|
+
opts.symbolize_keys!
|
22
|
+
opts = {
|
23
|
+
:realname => Faker::Name.name,
|
24
|
+
:host => "127.0.0.1",
|
25
|
+
:port => "6667",
|
26
|
+
:ssl => false,
|
27
|
+
:username => Faker::Name.first_name
|
28
|
+
}.merge!(opts)
|
29
|
+
|
30
|
+
@host = opts[:host]
|
31
|
+
@port = opts[:port]
|
32
|
+
@ssl = opts[:ssl]
|
33
|
+
@realname = opts[:realname]
|
34
|
+
@username = opts[:username]
|
35
|
+
@connected = false
|
36
|
+
@channels = Set.new
|
37
|
+
@callbacks = Hash.new
|
38
|
+
|
39
|
+
if block_given?
|
40
|
+
if block.arity == 1
|
41
|
+
yield self
|
42
|
+
else
|
43
|
+
instance_eval(&block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def connect
|
49
|
+
self.connection ||= EM::connect(@host, @port, Handler,
|
50
|
+
:client => self, :ssl => @ssl)
|
51
|
+
end
|
52
|
+
|
53
|
+
def connected?
|
54
|
+
@connected
|
55
|
+
end
|
56
|
+
|
57
|
+
def send_data(message)
|
58
|
+
return false unless connected?
|
59
|
+
message = message + "\r\n"
|
60
|
+
self.connection.send_data(message)
|
61
|
+
end
|
62
|
+
|
63
|
+
def receive_data(data)
|
64
|
+
data.split("\r\n").each do |message|
|
65
|
+
trigger(:raw, message)
|
66
|
+
parsed = parse_message(message)
|
67
|
+
handle_parsed_message(parsed)
|
68
|
+
trigger(:parsed, parsed)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def ready
|
73
|
+
@connected = true
|
74
|
+
user(@username, Faker::Internet.domain_word, Faker::Internet.domain_word, @realname)
|
75
|
+
trigger(:connect)
|
76
|
+
end
|
77
|
+
|
78
|
+
def unbind
|
79
|
+
trigger(:disconnect)
|
80
|
+
end
|
81
|
+
|
82
|
+
def run!
|
83
|
+
EM.epoll
|
84
|
+
EM.run do
|
85
|
+
trap("TERM") { EM.stop }
|
86
|
+
trap("INT") { EM.stop }
|
87
|
+
connect
|
88
|
+
puts "Starting IRC Client..."
|
89
|
+
end
|
90
|
+
puts "Stopping IRC Client..."
|
91
|
+
end
|
92
|
+
|
93
|
+
def on(name, &block)
|
94
|
+
(@callbacks[name.to_sym] ||= []) << block
|
95
|
+
end
|
96
|
+
|
97
|
+
def trigger(name, *args)
|
98
|
+
(@callbacks[name.to_sym] || []).each {|blk| blk.call(*args)}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Krtek
|
2
|
+
module Irc
|
3
|
+
module Commands
|
4
|
+
module RFC1459
|
5
|
+
# Command: NICK
|
6
|
+
# http://tools.ietf.org/html/rfc1459.html#section-4.1.2
|
7
|
+
def nick(nick = nil)
|
8
|
+
if nick
|
9
|
+
send_data("NICK #{nick}")
|
10
|
+
else
|
11
|
+
@nick
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Command: USER
|
16
|
+
# Parameters: <username> <hostname> <servername> <realname>
|
17
|
+
def user(username, hostname, servername, realname)
|
18
|
+
# send_data("USER #{username} #{hostname} #{servername} :#{realname}")
|
19
|
+
send_data("USER #{username} tolmoon tolsun lol :Ronnie Reagan")
|
20
|
+
end
|
21
|
+
|
22
|
+
def join(*args)
|
23
|
+
raise ArgumentError.new("Not enough arguments") unless args.size > 0
|
24
|
+
channels, keys = [], []
|
25
|
+
args.map! {|arg| arg.is_a?(Array) ? arg : [arg, '']}
|
26
|
+
args.sort! {|a,b| b[1].length <=> a[1].length} # key channels first
|
27
|
+
args.each {|arg|
|
28
|
+
channels << arg[0]
|
29
|
+
keys << arg[1] if arg[1].length > 0
|
30
|
+
}
|
31
|
+
send_data("JOIN #{channels.join(',')} #{keys.join(',')}".strip)
|
32
|
+
end
|
33
|
+
|
34
|
+
def privmsg(target, message)
|
35
|
+
send_data("PRIVMSG #{target} :#{message}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def pong(*servers)
|
39
|
+
send_data("PONG #{servers.join(' ')}")
|
40
|
+
end
|
41
|
+
|
42
|
+
def ping(server, target = '')
|
43
|
+
send_data("PING #{server} #{target}".strip)
|
44
|
+
end
|
45
|
+
|
46
|
+
def server_connect(target, port, remote = nil)
|
47
|
+
send_data("CONNECT #{target} #{port} #{remote}".strip)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Krtek
|
3
|
+
module Irc
|
4
|
+
class Handler < EM::Connection
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@client, :receive_data
|
8
|
+
|
9
|
+
def initialize(opts = {})
|
10
|
+
raise ArgumentError, "missing :client parameter for EM#connect" unless opts[:client]
|
11
|
+
@client = opts[:client]
|
12
|
+
@ssl = opts[:ssl] || false
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_data(data)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_init
|
20
|
+
@client.connection = self
|
21
|
+
end
|
22
|
+
|
23
|
+
def connection_completed
|
24
|
+
@ssl ? start_tls : @client.ready
|
25
|
+
end
|
26
|
+
|
27
|
+
def ssl_handshake_completed
|
28
|
+
@client.ready if @client.ssl
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Krtek
|
2
|
+
module Irc
|
3
|
+
module Responses
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
|
7
|
+
base.class_attribute :server_callbacks
|
8
|
+
|
9
|
+
base.server_reply 'PRIVMSG' do |m|
|
10
|
+
who = sender_nick(m[:prefix])
|
11
|
+
channel = m[:params].first
|
12
|
+
message = m[:params].slice(1..-1).join(' ').gsub(/^:/, '')
|
13
|
+
trigger(:privmsg, who, channel, message)
|
14
|
+
end
|
15
|
+
|
16
|
+
base.server_reply '001', 'RPL_WELCOME' do |m|
|
17
|
+
@nick = m[:params].first
|
18
|
+
trigger(:nick, @nick)
|
19
|
+
end
|
20
|
+
|
21
|
+
base.server_reply 'PING' do |m|
|
22
|
+
pong(m[:params].first)
|
23
|
+
trigger(:ping, *m[:params])
|
24
|
+
end
|
25
|
+
|
26
|
+
base.server_reply 'JOIN' do |m|
|
27
|
+
trigger(:join, sender_nick(m[:prefix]), m[:params].first)
|
28
|
+
end
|
29
|
+
|
30
|
+
base.server_reply '433', 'ERR_NICKNAMEINUSE' do |m|
|
31
|
+
@nick = nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
def server_reply(*cmds, &blk)
|
37
|
+
cmds << cmds.first if cmds.size == 1
|
38
|
+
self.server_callbacks ||= {}
|
39
|
+
self.server_callbacks[cmds.first] = {
|
40
|
+
:name => cmds.last,
|
41
|
+
:callback => block_given? ? blk : lambda {|m|
|
42
|
+
trigger(cmd.last.downcase.to_sym, *m[:params])
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_message(message)
|
49
|
+
result = {}
|
50
|
+
|
51
|
+
parts = message.split(' ')
|
52
|
+
result[:prefix] = parts.shift.gsub(/^:/, '') if parts[0] =~ /^:/
|
53
|
+
result[:command] = parts.shift
|
54
|
+
result[:params] = parts.take_while { |e| e[0] != ':' }
|
55
|
+
|
56
|
+
if result[:params].size < parts.size
|
57
|
+
full_string = parts.slice(result[:params].size..-1).join(" ")
|
58
|
+
full_string.gsub!(/^:/, '')
|
59
|
+
result[:params] << full_string
|
60
|
+
end
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle_parsed_message(m)
|
65
|
+
if handler = self.class.server_callbacks[m[:command]]
|
66
|
+
instance_exec(m, &handler[:callback])
|
67
|
+
# error codes 400 to 599
|
68
|
+
trigger(:error, handler[:name]) if (m[:command].to_i / 100) > 3
|
69
|
+
else
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def sender_nick(prefix)
|
76
|
+
prefix.split('!').first
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DslAccessor
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend Macros
|
5
|
+
end
|
6
|
+
|
7
|
+
module Macros
|
8
|
+
def dsl_accessor(*keys)
|
9
|
+
keys.map(&:to_s).each do |key|
|
10
|
+
class_eval <<-ACCESSORS
|
11
|
+
attr_writer :#{key}
|
12
|
+
def #{key}(val = nil)
|
13
|
+
if val
|
14
|
+
@#{key} = val
|
15
|
+
else
|
16
|
+
@#{key}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
ACCESSORS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/script/krtek_irb
ADDED
data/script/krtek_irb.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "./lib/krtek"
|
2
|
+
|
3
|
+
module Krtek
|
4
|
+
module Irc
|
5
|
+
class Client
|
6
|
+
def self.factory(trace = false)
|
7
|
+
krtek = self.new
|
8
|
+
|
9
|
+
krtek.on(:connect) do
|
10
|
+
krtek.nick "krtek"
|
11
|
+
end
|
12
|
+
|
13
|
+
krtek.on(:nick) do
|
14
|
+
krtek.join('#testing-chan')
|
15
|
+
end
|
16
|
+
|
17
|
+
if trace
|
18
|
+
krtek.on(:raw) do |msg|
|
19
|
+
puts msg
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
krtek
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
shared_context 'client integration', :test_client => true do
|
2
|
+
class TestClient < Krtek::Irc::Client
|
3
|
+
def initialize(opts = {})
|
4
|
+
@history = []
|
5
|
+
super(opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
def receive_data(data)
|
9
|
+
@history << data
|
10
|
+
super(data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def history
|
14
|
+
@history.join('\n')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def em_test_run(time = 5, &block)
|
19
|
+
EM.run do
|
20
|
+
yield(block) if block_given?
|
21
|
+
EM.add_timer(time) { EM::stop }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:pepa) { TestClient.new }
|
26
|
+
let(:lojza) { TestClient.new }
|
27
|
+
let(:jarda) { TestClient.new }
|
28
|
+
|
29
|
+
before do
|
30
|
+
pepa.on(:connect) { pepa.nick('pepa') }
|
31
|
+
lojza.on(:connect) { lojza.nick('lojza') }
|
32
|
+
|
33
|
+
pepa.on(:nick) { pepa.join('#testing-chan') }
|
34
|
+
lojza.on(:nick) { lojza.join('#testing-chan') }
|
35
|
+
|
36
|
+
pepa.on(:join) do |who, channel|
|
37
|
+
pepa.privmsg(channel, 'hello!') if who =~ /pepa/
|
38
|
+
end
|
39
|
+
|
40
|
+
lojza.on(:join) do |who, channel|
|
41
|
+
lojza.privmsg(channel, 'howdy all!') if who =~ /lojza/
|
42
|
+
end
|
43
|
+
|
44
|
+
pepa.on(:raw) do |msg|
|
45
|
+
puts msg
|
46
|
+
end
|
47
|
+
|
48
|
+
lojza.on(:raw) do |msg|
|
49
|
+
puts msg
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe :integration, :test_client => true do
|
55
|
+
it "client integration must work" do
|
56
|
+
em_test_run do
|
57
|
+
pepa.connect
|
58
|
+
lojza.connect
|
59
|
+
end
|
60
|
+
|
61
|
+
pepa.history.should =~ /Welcome/
|
62
|
+
pepa.history.should =~ /howdy all/
|
63
|
+
lojza.history.should =~ /Welcome/
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'integration/client_integration'
|
3
|
+
|
4
|
+
describe Krtek::Irc::Client, :test_client => true do
|
5
|
+
context :initialization do
|
6
|
+
it 'sets random realname' do
|
7
|
+
jarda.realname.should_not be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'sets random username' do
|
11
|
+
jarda.username.should_not be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'defaults host to 127.0.0.1' do
|
15
|
+
jarda.host.should eq('127.0.0.1')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'defaults ssl to false' do
|
19
|
+
jarda.ssl.should eq(false)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'defaults connected to false' do
|
23
|
+
jarda.should_not be_connected
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'default channels to empty set' do
|
27
|
+
jarda.channels.class.should eq(Set)
|
28
|
+
jarda.channels.should be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'default callbacks to empty hash' do
|
32
|
+
jarda.callbacks.class.should eq(Hash)
|
33
|
+
jarda.callbacks.should be_empty
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should optionally yield self' do
|
37
|
+
TestClient.new do |c|
|
38
|
+
c.should be_kind_of(TestClient)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should optionally instance_eval' do
|
43
|
+
krtecek = TestClient.new do
|
44
|
+
realname 'Krtecek'
|
45
|
+
end
|
46
|
+
|
47
|
+
krtecek.realname.should eq('Krtecek')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context :connect do
|
52
|
+
it 'should create EM TCP connection with correct args' do
|
53
|
+
EM.should_receive(:connect).with('irc.net', '9999', Krtek::Irc::Handler,
|
54
|
+
:client => jarda,
|
55
|
+
:ssl => true)
|
56
|
+
jarda.host = 'irc.net'
|
57
|
+
jarda.port = '9999'
|
58
|
+
jarda.ssl = true
|
59
|
+
jarda.connect
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should connect only once' do
|
63
|
+
EM.stub(:connect => mock('Connection'))
|
64
|
+
EM.should_receive(:connect).once
|
65
|
+
jarda.connect
|
66
|
+
jarda.connect
|
67
|
+
jarda.connect
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context :send_data do
|
72
|
+
before do
|
73
|
+
@connection = mock('Connection')
|
74
|
+
jarda.stub(:connection => @connection)
|
75
|
+
jarda.stub(:connected? => true)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should return false if not connected' do
|
79
|
+
jarda.stub(:connected? => nil)
|
80
|
+
jarda.send_data('NICK krtek').should be_false
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should send message to irc server' do
|
84
|
+
jarda.stub(:connection => @connection)
|
85
|
+
@connection.should_receive(:send_data).with("NICK krtek\r\n")
|
86
|
+
jarda.send_data('NICK krtek')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context :receive_data do
|
91
|
+
let(:messages) {
|
92
|
+
[
|
93
|
+
':irc.localhost 020 * :Please wait while we process your connection.',
|
94
|
+
':irc.localhost 001 pepa :Welcome to the Internet Relay Network pepa!~tolmoon@127.0.0.1',
|
95
|
+
':irc.localhost 002 pepa :Your host is irc.localhost, running version 2.11.2p2',
|
96
|
+
':irc.localhost 003 pepa :This server was created Mon Oct 17 2011 at 18:50:45 UTC',
|
97
|
+
':irc.localhost 004 pepa irc.localhost 2.11.2p2 aoOirw abeiIklmnoOpqrRstv'
|
98
|
+
]
|
99
|
+
}
|
100
|
+
|
101
|
+
let(:data) { messages.join("\r\n") }
|
102
|
+
|
103
|
+
let(:parsed_message) {mock.as_null_object}
|
104
|
+
|
105
|
+
before do
|
106
|
+
jarda.stub(:parse_message).and_return(parsed_message)
|
107
|
+
jarda.stub(:handle_parsed_message)
|
108
|
+
jarda.stub(:trigger)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should receive messages separated by \\r\\n' do
|
112
|
+
jarda.should_receive(:parse_message).exactly(5).times
|
113
|
+
jarda.receive_data(data)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should trigger :raw callbacks' do
|
117
|
+
jarda.should_receive(:trigger).with(:raw, messages[0])
|
118
|
+
jarda.should_receive(:trigger).with(:raw, messages[1])
|
119
|
+
jarda.should_receive(:trigger).with(:raw, messages[2])
|
120
|
+
jarda.should_receive(:trigger).with(:raw, messages[3])
|
121
|
+
jarda.should_receive(:trigger).with(:raw, messages[4])
|
122
|
+
jarda.receive_data(data)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should handle parsed messages' do
|
126
|
+
jarda.should_receive(:handle_parsed_message).exactly(5).times
|
127
|
+
jarda.receive_data(data)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should trigger :parsed callbacks' do
|
131
|
+
jarda.should_receive(:trigger).with(:parsed, parsed_message).exactly(5).times
|
132
|
+
jarda.receive_data(data)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context :ready do
|
137
|
+
before do
|
138
|
+
jarda.stub(:user)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should call :connect callback' do
|
142
|
+
jarda.should_receive(:trigger).with(:connect)
|
143
|
+
jarda.ready
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should mark client as connected' do
|
147
|
+
jarda.ready
|
148
|
+
jarda.should be_connected
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should call user method' do
|
152
|
+
string = an_instance_of(String)
|
153
|
+
jarda.should_receive(:user).with(jarda.username, string, string, jarda.realname)
|
154
|
+
jarda.ready
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context :unbind do
|
159
|
+
it 'should call :disconnect callback' do
|
160
|
+
jarda.should_receive(:trigger).with(:disconnect)
|
161
|
+
jarda.unbind
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'integration/client_integration'
|
3
|
+
|
4
|
+
describe Krtek::Irc::Commands::RFC1459, :test_client => true do
|
5
|
+
context :nick do
|
6
|
+
it "should set nick" do
|
7
|
+
jarda.should_receive(:send_data).with("NICK jardoslav")
|
8
|
+
jarda.nick("jardoslav")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'integration/client_integration'
|
3
|
+
|
4
|
+
describe Krtek::Irc::Client, :test_client => true do
|
5
|
+
def handle(raw)
|
6
|
+
parsed = jarda.parse_message(raw)
|
7
|
+
jarda.handle_parsed_message(parsed)
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'ping' do
|
11
|
+
it 'should respond with pong' do
|
12
|
+
jarda.should_receive(:pong).with('irc.net')
|
13
|
+
handle ':irc.net PING irc.net'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'privmsg' do
|
18
|
+
it 'should trigger privmsg' do
|
19
|
+
jarda.should_receive(:trigger).with(:privmsg, 'sender', '#channel', 'full message')
|
20
|
+
handle ':sender!~sender@host PRIVMSG #channel :full message'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'join' do
|
25
|
+
it 'should trigger join' do
|
26
|
+
jarda.should_receive(:trigger).with(:join, 'sender', '#channel')
|
27
|
+
handle ":sender!~sender@host JOIN #channel"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: krtek
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jiri Chara
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: faker
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activesupport
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: jeweler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Simple, smart, easy-to-use, fully tested gem
|
95
|
+
email: jirik.chara@gmail.com
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files:
|
99
|
+
- LICENSE.txt
|
100
|
+
- README.rdoc
|
101
|
+
files:
|
102
|
+
- .document
|
103
|
+
- .rspec
|
104
|
+
- .rvmrc
|
105
|
+
- Gemfile
|
106
|
+
- Gemfile.lock
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.rdoc
|
109
|
+
- Rakefile
|
110
|
+
- VERSION
|
111
|
+
- krtek.gemspec
|
112
|
+
- lib/krtek.rb
|
113
|
+
- lib/krtek/client.rb
|
114
|
+
- lib/krtek/commands.rb
|
115
|
+
- lib/krtek/handler.rb
|
116
|
+
- lib/krtek/recepient.rb
|
117
|
+
- lib/krtek/responses.rb
|
118
|
+
- lib/support/dsl_accessor.rb
|
119
|
+
- script/krtek_irb
|
120
|
+
- script/krtek_irb.rb
|
121
|
+
- spec/integration/client_integration.rb
|
122
|
+
- spec/lib/krtek/client_spec.rb
|
123
|
+
- spec/lib/krtek/commands_spec.rb
|
124
|
+
- spec/lib/krtek/responses_spec.rb
|
125
|
+
- spec/spec_helper.rb
|
126
|
+
homepage: http://github.com/JiriChara/krtek
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
hash: 1173182324073103880
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ! '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 1.8.24
|
151
|
+
signing_key:
|
152
|
+
specification_version: 3
|
153
|
+
summary: Simple IRC Bot running on EventMachine
|
154
|
+
test_files: []
|