Sutto-marvin 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/TUTORIAL.textile +54 -0
- data/VERSION.yml +1 -1
- data/bin/marvin +8 -0
- data/config/boot.rb +14 -0
- data/lib/marvin/command_handler.rb +1 -1
- data/lib/marvin/distributed/dispatch_handler.rb +1 -0
- data/lib/marvin/irc/server.rb +24 -10
- data/lib/marvin/irc/server/abstract_connection.rb +5 -0
- data/lib/marvin/irc/server/channel.rb +7 -3
- data/lib/marvin/irc/server/remote_interface.rb +59 -0
- data/lib/marvin/irc/server/user/handle_mixin.rb +6 -4
- data/lib/marvin/irc/server/user_connection.rb +11 -4
- data/lib/marvin/irc/server/virtual_user_connection.rb +80 -0
- data/script/client +1 -7
- data/script/distributed_client +1 -7
- data/script/install +1 -3
- data/script/ring_server +1 -9
- data/script/server +1 -9
- data/script/status +1 -9
- data/test/parser_test.rb +2 -0
- data/test/util_test.rb +57 -0
- metadata +7 -2
data/TUTORIAL.textile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
h1. A Quick Introduction to Marvin
|
2
|
+
|
3
|
+
Welcome young one - in today's lesson we're going to learn
|
4
|
+
how to build a simple IRC bot using "Marvin":http://github.com/Sutto/marvin.
|
5
|
+
If you haven't built an IRC bot before, there is a great
|
6
|
+
deal of things you can do - ranging from consuming content (e.g.
|
7
|
+
analysing logs of IRC rooms, seeing who swears the most)
|
8
|
+
as well as other things such as bridges between other
|
9
|
+
protocols (twitter => irc bridges) and all sorts of fancy stuff.
|
10
|
+
|
11
|
+
h3. What is this marvin thingy-majiggy?
|
12
|
+
|
13
|
+
Marvin is an IRC Library / Framework (it can be used either way)
|
14
|
+
built with an evented design on top of DRb, EventMachine and a bunch
|
15
|
+
of other stuff for Ruby. it's currently got a fairly complete client
|
16
|
+
and a very incomplete server implementation.
|
17
|
+
|
18
|
+
h2. Step #1 - Getting Marvin
|
19
|
+
|
20
|
+
There are currently two different ways to get marvin - via the
|
21
|
+
GitHub gem sources or directly from the source.
|
22
|
+
|
23
|
+
To install from the GitHub gem source, simply use:
|
24
|
+
|
25
|
+
sudo gem install Sutto-marvin -s http://gems.github.com
|
26
|
+
|
27
|
+
Alternatively, you can directly clone the repository. To do this, you'll need to run the
|
28
|
+
following:
|
29
|
+
|
30
|
+
git clone git://github.com/Sutto/marvin.git
|
31
|
+
cd marvin
|
32
|
+
sudo ./script/install
|
33
|
+
|
34
|
+
Once that's done, not only will you now have a handy "marvin" gem which you
|
35
|
+
can require but you will also have a handy executable of the same name which
|
36
|
+
you can use.
|
37
|
+
|
38
|
+
h2. Step #2 - Creating a Skeleton App
|
39
|
+
|
40
|
+
By default, marvin currently uses a simple skeleton app (not unlike
|
41
|
+
Ruby on Rails) as a starting point. To get started, you simply use
|
42
|
+
the "marvin create" command with a path to / folder name (which must not
|
43
|
+
yet exist) into which you wish to create the folder. For example, if I wanted
|
44
|
+
to create a new irc bot called "BlorkBot", I could do the following:
|
45
|
+
|
46
|
+
marvin create BlorkBot
|
47
|
+
|
48
|
+
And a new directory with the basic structure called "BlorkBot" will be created
|
49
|
+
under the current directory. To get started, you can then open your editor and
|
50
|
+
browse the given folder. Of this generated structure, there are only two folders
|
51
|
+
you need to worry about for the moment - config and handlers.
|
52
|
+
|
53
|
+
h2. Step #3 - Basic configuration
|
54
|
+
|
data/VERSION.yml
CHANGED
data/bin/marvin
CHANGED
@@ -32,6 +32,7 @@ class Marvin < Thor
|
|
32
32
|
mkdir source(@dest, "lib")
|
33
33
|
say " => Copying files..."
|
34
34
|
copy "config/setup.rb"
|
35
|
+
copy "config/boot.rb"
|
35
36
|
copy "config/connections.yml.sample", "config/connections.yml"
|
36
37
|
copy "config/settings.yml.sample", "config/settings.yml"
|
37
38
|
copy "handlers/hello_world.rb"
|
@@ -67,6 +68,13 @@ class Marvin < Thor
|
|
67
68
|
start_script(:client)
|
68
69
|
end
|
69
70
|
|
71
|
+
desc "server [PATH]", "starts a server instance from the given location"
|
72
|
+
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
73
|
+
def server(path = ".")
|
74
|
+
@dest = File.expand_path(path)
|
75
|
+
start_script(:server)
|
76
|
+
end
|
77
|
+
|
70
78
|
desc "ring_server [PATH]", "starts a ring server from the given location"
|
71
79
|
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
72
80
|
def ring_server(path = ".")
|
data/config/boot.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Load Marvin, do any initialization etc.
|
2
|
+
# Note: this is called from inside scripts
|
3
|
+
# or anywhere you want to start a base marvin
|
4
|
+
# instance.
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
MARVIN_ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
9
|
+
|
10
|
+
# Check if a local copy of marvin exists, and set the load path if it does.
|
11
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
12
|
+
|
13
|
+
# And Require Marvin.
|
14
|
+
require 'marvin'
|
@@ -41,7 +41,7 @@ module Marvin
|
|
41
41
|
unless command_name.nil?
|
42
42
|
logger.debug "Command Exists - processing"
|
43
43
|
# Dispatch the command.
|
44
|
-
self.send(command_name, data.split(" ")) if self.respond_to?(command_name)
|
44
|
+
self.send(command_name, data.to_s.split(" ")) if self.respond_to?(command_name)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -55,6 +55,7 @@ module Marvin
|
|
55
55
|
logger.warn "Dispatch handler queue is currently holding #{size} items"
|
56
56
|
end
|
57
57
|
else
|
58
|
+
logger.debug "Writing #{@queued_messages.size} message to the ring server"
|
58
59
|
@queued_messages.dup.each do |t|
|
59
60
|
ring_server.write(t)
|
60
61
|
@queued_messages.delete(t)
|
data/lib/marvin/irc/server.rb
CHANGED
@@ -7,33 +7,46 @@ module Marvin
|
|
7
7
|
|
8
8
|
# Store each user
|
9
9
|
UserStore = NamedStore.new(:nicks, :user) do
|
10
|
+
|
11
|
+
def virtual?(nick)
|
12
|
+
self[nick].is_a?(Marvin::IRC::Server::VirtualUserConnection)
|
13
|
+
end
|
14
|
+
|
15
|
+
def reclaim(nick)
|
16
|
+
if has_key?(nick) && virtual?(nick)
|
17
|
+
self[nick].reclaim!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Nick is not taken when
|
10
22
|
def nick_taken?(nick)
|
11
|
-
has_key?(nick)
|
23
|
+
has_key?(nick) && !virtual(nick)
|
12
24
|
end
|
13
25
|
|
14
26
|
def each_user_except(user)
|
15
|
-
self.each_user
|
16
|
-
yield u unless user == u
|
17
|
-
end
|
27
|
+
self.each_user { |u| yield u unless user == u }
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
21
31
|
# Store each channel
|
22
32
|
ChannelStore = NamedStore.new(:names, :channel)
|
23
33
|
|
24
|
-
autoload :
|
34
|
+
autoload :RemoteInterface, 'marvin/irc/server/remote_interface'
|
35
|
+
autoload :Channel, 'marvin/irc/server/channel'
|
25
36
|
# The actual network connection
|
26
|
-
autoload :BaseConnection,
|
37
|
+
autoload :BaseConnection, 'marvin/irc/server/base_connection'
|
27
38
|
# An our implementations of protocol-specific stuff.
|
28
|
-
autoload :
|
29
|
-
autoload :
|
30
|
-
autoload :
|
39
|
+
autoload :VirtualUserConnection, 'marvin/irc/server/virtual_user_connection'
|
40
|
+
autoload :AbstractConnection, 'marvin/irc/server/abstract_connection'
|
41
|
+
autoload :UserConnection, 'marvin/irc/server/user_connection'
|
42
|
+
autoload :ServerConnection, 'marvin/irc/server/server_connection'
|
31
43
|
# Extensions for each part
|
32
|
-
autoload :User,
|
44
|
+
autoload :User, 'marvin/irc/server/user'
|
33
45
|
|
34
46
|
# call start_server w/ the default options
|
35
47
|
# and inside an EM::run block.
|
36
48
|
def self.run
|
49
|
+
Marvin::IRC::Server::RemoteInterface.start
|
37
50
|
EventMachine::run do
|
38
51
|
Marvin::Logger.info "Starting server..."
|
39
52
|
start_server :bind_addr => "0.0.0.0"
|
@@ -46,6 +59,7 @@ module Marvin
|
|
46
59
|
opts[:host] ||= self.host_name
|
47
60
|
opts[:port] ||= 6667
|
48
61
|
EventMachine::start_server(opts[:bind_addr] || opts[:host], opts[:port], BaseConnection, opts)
|
62
|
+
Marvin::Logger.info "Server started"
|
49
63
|
end
|
50
64
|
|
51
65
|
def self.host_name
|
@@ -69,9 +69,13 @@ module Marvin::IRC::Server
|
|
69
69
|
check_emptyness!
|
70
70
|
end
|
71
71
|
|
72
|
-
def message(user, message)
|
73
|
-
@members.each
|
74
|
-
|
72
|
+
def message(user, message, virtual = false)
|
73
|
+
@members.each do |m|
|
74
|
+
if virtual || user != m
|
75
|
+
m.notify(:privmsg, @name, ":#{message}", :prefix => user.prefix, :virtual => virtual)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
dispatch :outgoing_message, :target => self, :user => user, :message => message, :virtual => virtual
|
75
79
|
end
|
76
80
|
|
77
81
|
def notice(user, message)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'rinda/ring'
|
3
|
+
module Marvin
|
4
|
+
module IRC
|
5
|
+
module Server
|
6
|
+
|
7
|
+
# Make sure that a proxy object is used vs. the real thing.
|
8
|
+
[Channel, AbstractConnection, User, NamedStore].each do |c|
|
9
|
+
c.class_eval { include DRbUndumped }
|
10
|
+
end
|
11
|
+
|
12
|
+
# A DRb interface to post / receive messages from the
|
13
|
+
# a running server instance. Used for things such as
|
14
|
+
# posting status updated directly on the server.
|
15
|
+
class RemoteInterface
|
16
|
+
include DRbUndumped
|
17
|
+
|
18
|
+
def self.start
|
19
|
+
DRb.start_service
|
20
|
+
instance = self.new # Create the new instance
|
21
|
+
begin
|
22
|
+
rs = Rinda::RingFinger.primary
|
23
|
+
renewer = Rinda::SimpleRenewer.new
|
24
|
+
tuple = [:marvin_server, Marvin::Settings.distributed_namespace, instance]
|
25
|
+
Marvin::Logger.info "Publishing information about service to the tuplespace"
|
26
|
+
Marvin::Logger.debug "Pushing #{tuple.inspect} to #{rs.__drburi}"
|
27
|
+
rs.write(tuple, renewer)
|
28
|
+
rescue
|
29
|
+
Marvin::Logger.warn "No ring server found - remote interface not running"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns an array of all channels
|
34
|
+
def channels
|
35
|
+
Marvin::IRC::Server::ChannelStore.values
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the names of all channels
|
39
|
+
def channel_names
|
40
|
+
Marvin::IRC::Server::ChannelStore.keys
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the channel with the given name.
|
44
|
+
def channel(name)
|
45
|
+
Marvin::IRC::Server::ChannelStore[name]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Send an action from a user to a specific
|
49
|
+
# channel, using from nick as a facade.
|
50
|
+
def message(from_nick, target, contents)
|
51
|
+
u = (Marvin::IRC::Server::UserStore[from_nick.to_s.downcase] ||= VirtualUserConnection.new(from_nick))
|
52
|
+
Marvin::Logger.info "#{from_nick} (#{u.inspect}) messaging #{target}: #{contents}"
|
53
|
+
u.send_message(target, contents) unless u.blank?
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -15,11 +15,13 @@ module Marvin::IRC::Server::User::HandleMixin
|
|
15
15
|
nick = opts[:new_nick]
|
16
16
|
if !nick.blank? && !Marvin::IRC::Server::UserStore.nick_taken?(nick.downcase)
|
17
17
|
if !(new_nick = @nick.nil?)
|
18
|
+
logger.info "Reclaiming nick (if taken)"
|
19
|
+
Marvin::IRC::Server::UserStore.reclaim(nick)
|
18
20
|
logger.debug "Notifying all users of nick change: #{@nick} => #{nick}"
|
19
21
|
# Get all users and let them now we've changed nick from @nick to nick
|
20
22
|
users = [self]
|
21
23
|
@channels.each do |c|
|
22
|
-
users += c.members
|
24
|
+
users += c.members
|
23
25
|
end
|
24
26
|
users.uniq.each { |u| u.notify :NICK, nick, :prefix => prefix }
|
25
27
|
dispatch :outgoing_nick, :nick => @nick, :new_nick => nick
|
@@ -62,7 +64,7 @@ module Marvin::IRC::Server::User::HandleMixin
|
|
62
64
|
end
|
63
65
|
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
64
66
|
if chan.join(self)
|
65
|
-
rpl :TOPIC, channel, ":#{chan.topic.blank? ? "There is no topic" :
|
67
|
+
rpl :TOPIC, channel, ":#{chan.topic.blank? ? "There is no topic" : chan.topic}"
|
66
68
|
rpl :NAMREPLY, "=", channel, ":#{chan.members.map { |m| m.nick }.join(" ")}"
|
67
69
|
rpl :ENDOFNAMES, channel, ":End of /NAMES list."
|
68
70
|
@channels << chan
|
@@ -123,7 +125,7 @@ module Marvin::IRC::Server::User::HandleMixin
|
|
123
125
|
return if c.blank?
|
124
126
|
if !@channels.include?(c)
|
125
127
|
err :NOTONCHANNEL, opts[:target], ":Not a member of that channel"
|
126
|
-
elsif opts[:
|
128
|
+
elsif opts[:topic].blank?
|
127
129
|
t = c.topic
|
128
130
|
if t.blank?
|
129
131
|
rpl :NOTOPIC, c.name, ":No topic is set"
|
@@ -131,7 +133,7 @@ module Marvin::IRC::Server::User::HandleMixin
|
|
131
133
|
rpl :TOPIC, c.name, ":#{t}"
|
132
134
|
end
|
133
135
|
else
|
134
|
-
c.topic self, opts[:
|
136
|
+
c.topic self, opts[:topic].strip
|
135
137
|
end
|
136
138
|
end
|
137
139
|
|
@@ -3,6 +3,7 @@ module Marvin::IRC::Server
|
|
3
3
|
USER_MODES = "aAbBcCdDeEfFGhHiIjkKlLmMnNopPQrRsStUvVwWxXyYzZ0123459*@"
|
4
4
|
CHANNEL_MODES = "bcdefFhiIklmnoPqstv"
|
5
5
|
CHANNEL = /^[\&\#]+/
|
6
|
+
|
6
7
|
include User::HandleMixin
|
7
8
|
|
8
9
|
attr_accessor :nick, :host, :user, :prefix, :password, :mode,
|
@@ -29,9 +30,15 @@ module Marvin::IRC::Server
|
|
29
30
|
|
30
31
|
# Notification messages
|
31
32
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
33
|
+
def send_message(target, message)
|
34
|
+
t = target_from(target)
|
35
|
+
logger.debug "Sending #{t.inspect} #{message.inspect} from #{self.inspect}"
|
36
|
+
t.message(self, message) unless t.blank?
|
37
|
+
end
|
38
|
+
|
39
|
+
def message(user, message, virtual = false)
|
40
|
+
notify :PRIVMSG, @nick, ":#{message}", :prefix => user.prefix, :virtual => virtual
|
41
|
+
dispatch :outgoing_message, :user => user, :message => message, :target => self, :virtual => virtual
|
35
42
|
end
|
36
43
|
|
37
44
|
def notice(user, message)
|
@@ -93,7 +100,7 @@ module Marvin::IRC::Server
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def update_prefix!
|
96
|
-
@prefix = "#{@nick}
|
103
|
+
@prefix = "#{@nick}!n=#{@user}@#{peer_name}" if details_complete?
|
97
104
|
end
|
98
105
|
|
99
106
|
def details_complete?
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Marvin::IRC::Server
|
2
|
+
class VirtualUserConnection
|
3
|
+
include Marvin::Dispatchable
|
4
|
+
|
5
|
+
CHANNEL = /^[\&\#]+/
|
6
|
+
|
7
|
+
attr_accessor :nick, :channels
|
8
|
+
|
9
|
+
def initialize(nick)
|
10
|
+
self.nick = nick
|
11
|
+
self.channels = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def prefix
|
15
|
+
"#{@nick}!n=rruser@relayrelay.com"
|
16
|
+
end
|
17
|
+
|
18
|
+
def notify(*args)
|
19
|
+
Marvin::Logger.debug "Virtual User #{self.nick} got notify w/ #{args.inspect}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Notify the remote handler we've received a message
|
23
|
+
def message(user, message, virtual = false)
|
24
|
+
dispatch :received_message, :user => user, :message => message, :target => self unless virtual
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_message(target, message)
|
28
|
+
t = target_from(target)
|
29
|
+
Marvin::Logger.debug "DRb Message from #{self.nick} to #{t.inspect}: #{message.inspect}"
|
30
|
+
if t.blank?
|
31
|
+
Marvin::Logger.debug "Target not found"
|
32
|
+
return nil
|
33
|
+
else
|
34
|
+
Marvin::Logger.debug "Sending message to #{t.inspect}"
|
35
|
+
return t.message(self, message, true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def reclaim!
|
40
|
+
self.channels.each { |c| c.part(self, "Reclaiming nick for virtual user...") }
|
41
|
+
Marvin::IRC::Server::UserStore.delete(self.nick.downcase)
|
42
|
+
end
|
43
|
+
|
44
|
+
def join(channel)
|
45
|
+
return nil if channel !~ CHANNEL
|
46
|
+
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
47
|
+
if chan.join(self)
|
48
|
+
@channels << channel
|
49
|
+
return chan
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
|
55
|
+
def claimed?(nick)
|
56
|
+
Marvin::IRC::Server::UserStore.virtual?(nick)
|
57
|
+
end
|
58
|
+
|
59
|
+
def claim(nick)
|
60
|
+
unless Marvin::IRC::Server::UserStore[nick.downcase].blank?
|
61
|
+
return(Marvin::IRC::Server::UserStore[nick.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(nick))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def target_from(target)
|
70
|
+
if target =~ CHANNEL
|
71
|
+
c = Marvin::IRC::Server::ChannelStore[target.downcase]
|
72
|
+
c = join(target) if c.nil? || !c.member?(self)
|
73
|
+
return c
|
74
|
+
else
|
75
|
+
return Marvin::IRC::Server::UserStore[target.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(target)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/script/client
CHANGED
@@ -1,9 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
|
4
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
5
|
-
MARVIN_ROOT = File.join(File.dirname(__FILE__), "..")
|
6
|
-
|
7
|
-
# And Require Marvin.
|
8
|
-
require 'marvin'
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "config", "boot")
|
9
3
|
Marvin::Loader.run! :client
|
data/script/distributed_client
CHANGED
@@ -1,9 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
|
4
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
5
|
-
MARVIN_ROOT = File.join(File.dirname(__FILE__), "..")
|
6
|
-
|
7
|
-
# And Require Marvin.
|
8
|
-
require 'marvin'
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "config", "boot")
|
9
3
|
Marvin::Loader.run! :distributed_client
|
data/script/install
CHANGED
data/script/ring_server
CHANGED
@@ -1,12 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
#!/usr/bin/env ruby
|
4
|
-
require 'rubygems'
|
5
|
-
|
6
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
7
|
-
MARVIN_ROOT = File.join(File.dirname(__FILE__), "..")
|
8
|
-
|
9
|
-
# And Require Marvin.
|
10
|
-
require 'marvin'
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "config", "boot")
|
11
3
|
Marvin::Loader.run! :ring_server
|
12
4
|
|
data/script/server
CHANGED
@@ -1,12 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
#!/usr/bin/env ruby
|
4
|
-
require 'rubygems'
|
5
|
-
|
6
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
7
|
-
MARVIN_ROOT = File.join(File.dirname(__FILE__), "..")
|
8
|
-
|
9
|
-
# And Require Marvin.
|
10
|
-
require 'marvin'
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "config", "boot")
|
11
3
|
Marvin::Loader.run! :server
|
12
4
|
|
data/script/status
CHANGED
@@ -1,11 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
|
5
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/") if File.exist?(File.dirname(__FILE__) + "/../lib/marvin.rb")
|
6
|
-
MARVIN_ROOT = File.join(File.dirname(__FILE__), "..")
|
7
|
-
|
8
|
-
# And Require Marvin.
|
9
|
-
require 'marvin'
|
10
|
-
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "config", "boot")
|
11
3
|
Marvin::Status.show!
|
data/test/parser_test.rb
CHANGED
@@ -6,6 +6,8 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
6
6
|
# 3) The two different types of prefixes
|
7
7
|
# 4) The Event class
|
8
8
|
class ParserTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
# The default parser
|
9
11
|
@@parser = Marvin::Parsers::SimpleParser
|
10
12
|
|
11
13
|
context "When parsing a LIST" do
|
data/test/util_test.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class UtilTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Converting a string to a channel name" do
|
6
|
+
|
7
|
+
should "not convert it if it starts with #" do
|
8
|
+
assert_equal "#offrails", Marvin::Util.channel_name("#offrails")
|
9
|
+
end
|
10
|
+
|
11
|
+
should "append a # if not present" do
|
12
|
+
assert_equal "#offrails", Marvin::Util.channel_name("offrails")
|
13
|
+
end
|
14
|
+
|
15
|
+
should "also be available as chan" do
|
16
|
+
assert_equal "#offrails", Marvin::Util.chan("#offrails")
|
17
|
+
assert_equal "#offrails", Marvin::Util.chan("offrails")
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "Parsing arguments" do
|
23
|
+
|
24
|
+
should "parse 'a b c' as ['a', 'b', 'c']" do
|
25
|
+
assert_equal ['a', 'b', 'c'], Marvin::Util.arguments("a b c")
|
26
|
+
end
|
27
|
+
|
28
|
+
should "parse 'a b :c d' as ['a', 'b', 'c d']" do
|
29
|
+
assert_equal ['a', 'b', 'c d'], Marvin::Util.arguments("a b :c d")
|
30
|
+
end
|
31
|
+
|
32
|
+
should "parse 'a :b c :d e' as ['a', 'b c :d e']" do
|
33
|
+
assert_equal ['a', 'b c :d e'], Marvin::Util.arguments('a :b c :d e')
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
context "Preparing last parameters" do
|
39
|
+
|
40
|
+
should "prepend a :" do
|
41
|
+
assert_equal ':zomg ninjas', Marvin::Util.last_param('zomg ninjas')
|
42
|
+
assert_equal '::zomg ninjas', Marvin::Util.last_param(':zomg ninjas')
|
43
|
+
end
|
44
|
+
|
45
|
+
should "strip the input" do
|
46
|
+
assert_equal ':zomg ninjas', Marvin::Util.last_param(' zomg ninjas ')
|
47
|
+
end
|
48
|
+
|
49
|
+
should "be available as lp" do
|
50
|
+
assert_equal ':zomg ninjas', Marvin::Util.lp('zomg ninjas')
|
51
|
+
assert_equal '::zomg ninjas', Marvin::Util.lp(':zomg ninjas')
|
52
|
+
assert_equal ':zomg ninjas', Marvin::Util.lp(' zomg ninjas ')
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Sutto-marvin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darcy Laycock
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-01-03 00:00:00 -08:00
|
13
13
|
default_executable: marvin
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -58,6 +58,7 @@ extra_rdoc_files: []
|
|
58
58
|
|
59
59
|
files:
|
60
60
|
- README.textile
|
61
|
+
- TUTORIAL.textile
|
61
62
|
- VERSION.yml
|
62
63
|
- bin/marvin
|
63
64
|
- lib/marvin
|
@@ -87,10 +88,12 @@ files:
|
|
87
88
|
- lib/marvin/irc/server/base_connection.rb
|
88
89
|
- lib/marvin/irc/server/channel.rb
|
89
90
|
- lib/marvin/irc/server/named_store.rb
|
91
|
+
- lib/marvin/irc/server/remote_interface.rb
|
90
92
|
- lib/marvin/irc/server/user
|
91
93
|
- lib/marvin/irc/server/user/handle_mixin.rb
|
92
94
|
- lib/marvin/irc/server/user.rb
|
93
95
|
- lib/marvin/irc/server/user_connection.rb
|
96
|
+
- lib/marvin/irc/server/virtual_user_connection.rb
|
94
97
|
- lib/marvin/irc/server.rb
|
95
98
|
- lib/marvin/irc.rb
|
96
99
|
- lib/marvin/loader.rb
|
@@ -116,6 +119,7 @@ files:
|
|
116
119
|
- test/parser_comparison.rb
|
117
120
|
- test/parser_test.rb
|
118
121
|
- test/test_helper.rb
|
122
|
+
- test/util_test.rb
|
119
123
|
- spec/marvin
|
120
124
|
- spec/marvin/abstract_client_test.rb
|
121
125
|
- spec/spec_helper.rb
|
@@ -131,6 +135,7 @@ files:
|
|
131
135
|
- handlers/logging_handler.rb
|
132
136
|
- handlers/tweet_tweet.rb
|
133
137
|
- config/setup.rb
|
138
|
+
- config/boot.rb
|
134
139
|
- config/settings.yml.sample
|
135
140
|
- config/connections.yml.sample
|
136
141
|
has_rdoc: false
|