Sutto-marvin 0.2.2 → 0.2.3
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/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
|