Sutto-marvin 0.4.0 → 0.8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/marvin +22 -156
- data/handlers/keiki_thwopper.rb +21 -0
- data/handlers/tweet_tweet.rb +1 -3
- data/lib/marvin/abstract_client.rb +75 -189
- data/lib/marvin/abstract_parser.rb +9 -11
- data/lib/marvin/base.rb +134 -101
- data/lib/marvin/client/actions.rb +104 -0
- data/lib/marvin/client/default_handlers.rb +97 -0
- data/lib/marvin/command_handler.rb +60 -49
- data/lib/marvin/console.rb +4 -31
- data/lib/marvin/core_commands.rb +30 -12
- data/lib/marvin/distributed/client.rb +225 -0
- data/lib/marvin/distributed/handler.rb +85 -0
- data/lib/marvin/distributed/protocol.rb +88 -0
- data/lib/marvin/distributed/server.rb +154 -0
- data/lib/marvin/distributed.rb +4 -10
- data/lib/marvin/dsl.rb +103 -0
- data/lib/marvin/exception_tracker.rb +7 -4
- data/lib/marvin/irc/client.rb +127 -99
- data/lib/marvin/irc/event.rb +14 -10
- data/lib/marvin/irc.rb +0 -1
- data/lib/marvin/middle_man.rb +1 -1
- data/lib/marvin/parsers/command.rb +10 -8
- data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
- data/lib/marvin/parsers/prefixes/server.rb +1 -1
- data/lib/marvin/parsers/ragel_parser.rb +59 -52
- data/lib/marvin/parsers/ragel_parser.rl +6 -7
- data/lib/marvin/parsers/simple_parser.rb +4 -9
- data/lib/marvin/parsers.rb +1 -2
- data/lib/marvin/settings.rb +29 -79
- data/lib/marvin/test_client.rb +20 -26
- data/lib/marvin/util.rb +10 -3
- data/lib/marvin.rb +42 -39
- data/templates/boot.erb +3 -0
- data/templates/connections.yml.erb +10 -0
- data/templates/debug_handler.erb +5 -0
- data/templates/hello_world.erb +10 -0
- data/templates/rakefile.erb +15 -0
- data/templates/settings.yml.erb +8 -0
- data/{config/setup.rb → templates/setup.erb} +8 -10
- data/templates/test_helper.erb +17 -0
- data/test/abstract_client_test.rb +63 -0
- data/test/parser_comparison.rb +2 -2
- data/test/parser_test.rb +3 -3
- data/test/test_helper.rb +58 -6
- metadata +51 -83
- data/README.textile +0 -105
- data/TUTORIAL.textile +0 -54
- data/VERSION.yml +0 -4
- data/config/boot.rb +0 -14
- data/config/connections.yml.sample +0 -5
- data/config/settings.yml.sample +0 -13
- data/handlers/logging_handler.rb +0 -89
- data/lib/marvin/core_ext.rb +0 -11
- data/lib/marvin/daemon.rb +0 -71
- data/lib/marvin/data_store.rb +0 -73
- data/lib/marvin/dispatchable.rb +0 -99
- data/lib/marvin/distributed/dispatch_handler.rb +0 -83
- data/lib/marvin/distributed/drb_client.rb +0 -78
- data/lib/marvin/distributed/ring_server.rb +0 -41
- data/lib/marvin/handler.rb +0 -12
- data/lib/marvin/irc/server/abstract_connection.rb +0 -84
- data/lib/marvin/irc/server/base_connection.rb +0 -66
- data/lib/marvin/irc/server/channel.rb +0 -115
- data/lib/marvin/irc/server/named_store.rb +0 -14
- data/lib/marvin/irc/server/remote_interface.rb +0 -77
- data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
- data/lib/marvin/irc/server/user.rb +0 -5
- data/lib/marvin/irc/server/user_connection.rb +0 -134
- data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
- data/lib/marvin/irc/server.rb +0 -71
- data/lib/marvin/loader.rb +0 -149
- data/lib/marvin/logger.rb +0 -86
- data/lib/marvin/options.rb +0 -42
- data/lib/marvin/parsers/regexp_parser.rb +0 -93
- data/lib/marvin/status.rb +0 -72
- data/script/client +0 -3
- data/script/console +0 -3
- data/script/distributed_client +0 -3
- data/script/install +0 -1
- data/script/ring_server +0 -4
- data/script/server +0 -4
- data/script/status +0 -3
- data/spec/marvin/abstract_client_test.rb +0 -38
- data/spec/spec_helper.rb +0 -14
data/lib/marvin/dsl.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Handy Dandy DSL style stuff for Marvin
|
2
|
+
module Marvin
|
3
|
+
class DSL
|
4
|
+
|
5
|
+
class Proxy < Perennial::Proxy
|
6
|
+
|
7
|
+
def initialize(klass)
|
8
|
+
@prototype_klass = Class.new(klass)
|
9
|
+
@mapping = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def define_shortcut(name, method_name)
|
13
|
+
@mapping[name] = method_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def shortdef(hash = {})
|
17
|
+
hash.each_pair { |k,v| define_shortcut(k, v) }
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
def initialize_class!
|
23
|
+
@klass = Class.new(@prototype_klass)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_instance
|
27
|
+
@klass.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_class
|
31
|
+
@klass
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(name, *args, &blk)
|
35
|
+
name = name.to_sym
|
36
|
+
if @mapping.has_key?(name)
|
37
|
+
@klass.define_method(@mapping[name], &blk)
|
38
|
+
else
|
39
|
+
@klass.send(name, *args, &blk)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(&blk)
|
46
|
+
instance_eval(&blk)
|
47
|
+
end
|
48
|
+
|
49
|
+
def logging(&blk)
|
50
|
+
call_prototype(:logging, &blk).register!
|
51
|
+
end
|
52
|
+
|
53
|
+
def handler(&blk)
|
54
|
+
call_prototype(:handler, &blk).register!
|
55
|
+
end
|
56
|
+
|
57
|
+
def commands(&blk)
|
58
|
+
call_prototype(:commands, &blk).register!
|
59
|
+
end
|
60
|
+
|
61
|
+
def configure(&blk)
|
62
|
+
Marvin::Settings.client.configure(&blk)
|
63
|
+
end
|
64
|
+
|
65
|
+
def server(name, port = nil)
|
66
|
+
name = name.to_s.dup
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def initialize_prototypes
|
74
|
+
prototype_for(:logging, Marvin::LoggingHandler) do
|
75
|
+
shortdef :setup => :setup_logging,
|
76
|
+
:teardown => :teardown_logging,
|
77
|
+
:incoming => :log_incoming,
|
78
|
+
:outgoing => :log_outgoing,
|
79
|
+
:message => :log_message
|
80
|
+
end
|
81
|
+
prototype_for(:handler, Marvin::Base) do
|
82
|
+
map :on => :on_event,
|
83
|
+
:numeric => :on_numeric
|
84
|
+
end
|
85
|
+
prototype_for(:handler, Marvin::CommandHandler)
|
86
|
+
end
|
87
|
+
|
88
|
+
def prototype_for(name, klass, &blk)
|
89
|
+
@prototypes ||= {}
|
90
|
+
p = Proxy.new(klass)
|
91
|
+
p.instance_eval(&blk)
|
92
|
+
@prototypes[name] = p
|
93
|
+
end
|
94
|
+
|
95
|
+
def call_prototype(name, &blk)
|
96
|
+
p = @prototypes[name]
|
97
|
+
p.initialize_class!
|
98
|
+
p.instance_eval(&blk)
|
99
|
+
return p.to_class
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -1,15 +1,18 @@
|
|
1
1
|
module Marvin
|
2
2
|
class ExceptionTracker
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
is :loggable
|
5
|
+
|
6
|
+
cattr_accessor :log_exception_proc
|
7
|
+
self.log_exception_proc = proc { |e| e }
|
6
8
|
|
7
9
|
def self.log(e)
|
8
|
-
logger.fatal "
|
9
|
-
logger.fatal "#{e}
|
10
|
+
logger.fatal "Oh noes cap'n - we have an exception!."
|
11
|
+
logger.fatal "#{e.class.name}: #{e.message}"
|
10
12
|
e.backtrace.each do |line|
|
11
13
|
logger.fatal line
|
12
14
|
end
|
15
|
+
@@log_exception_proc.call(e)
|
13
16
|
end
|
14
17
|
|
15
18
|
end
|
data/lib/marvin/irc/client.rb
CHANGED
@@ -1,138 +1,166 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
3
|
module Marvin::IRC
|
4
|
-
|
5
|
-
# == Marvin::IRC::Client
|
6
|
-
# An EventMachine protocol implementation built to
|
7
|
-
# serve as a basic, single server IRC client.
|
8
|
-
#
|
9
|
-
# Operates on the principal of Events as well
|
10
|
-
# as handlers.
|
11
|
-
#
|
12
|
-
# === Events
|
13
|
-
# Events are things that can happen (e.g. an
|
14
|
-
# incoming message). All outgoing events are
|
15
|
-
# automatically handled from within the client
|
16
|
-
# class. Incoming events are currently based
|
17
|
-
# on regular expression based matches of
|
18
|
-
# incoming messages. the Client#register_event
|
19
|
-
# method takes either an instance of Marvin::IRC::Event
|
20
|
-
# or a set of arguments which will then be used
|
21
|
-
# in the constructor of a new Marvin::IRC::Event
|
22
|
-
# instance (see, for example, the source code for
|
23
|
-
# this class for examples).
|
24
|
-
#
|
25
|
-
# === Handlers
|
26
|
-
# Handlers on the other hand do as the name suggests
|
27
|
-
# - they listen for dispatched events and act accordingly.
|
28
|
-
# Handlers are simply objects which follow a certain
|
29
|
-
# set of guidelines. Typically, a handler will at
|
30
|
-
# minimum respond to #handle(event_name, details)
|
31
|
-
# where event_name is a symbol for the current
|
32
|
-
# event (e.g. :incoming_event) whilst details is a
|
33
|
-
# a hash of details about the current event (e.g.
|
34
|
-
# message target and the message itself).
|
35
|
-
#
|
36
|
-
# ==== Getting the current client instance
|
37
|
-
# If the object responds to client=, The client will
|
38
|
-
# call it with the current instance of itself
|
39
|
-
# enabling the handler to do things such as respond.
|
40
|
-
# Also, if a method handle_[message_name] exists,
|
41
|
-
# it will be called instead of handle.
|
42
|
-
#
|
43
|
-
# ==== Adding handlers
|
44
|
-
# To add an object as a handler, you simply call
|
45
|
-
# the class method, register_handler with the
|
46
|
-
# handler as the only argument.
|
47
4
|
class Client < Marvin::AbstractClient
|
48
|
-
|
49
|
-
|
5
|
+
|
6
|
+
@@stopped = false
|
50
7
|
|
51
8
|
attr_accessor :em_connection
|
52
9
|
|
53
10
|
class EMConnection < EventMachine::Protocols::LineAndTextProtocol
|
54
|
-
|
11
|
+
is :loggable
|
12
|
+
|
13
|
+
attr_accessor :client, :port, :configuration
|
55
14
|
|
56
15
|
def initialize(*args)
|
57
|
-
|
16
|
+
@configuration = args.last.is_a?(Marvin::Nash) ? args.pop : Marvin::Nash.new
|
58
17
|
super(*args)
|
59
|
-
|
60
|
-
|
18
|
+
@client = Marvin::IRC::Client.new(@configuration)
|
19
|
+
@client.em_connection = self
|
20
|
+
@connected = false
|
21
|
+
rescue Exception => e
|
22
|
+
Marvin::ExceptionTracker.log(e)
|
23
|
+
Marvin::IRC::Client.stop
|
61
24
|
end
|
62
25
|
|
63
26
|
def post_init
|
64
|
-
client.process_connect
|
65
27
|
super
|
28
|
+
if should_use_ssl?
|
29
|
+
logger.info "Starting SSL for #{host_with_port}"
|
30
|
+
start_tls
|
31
|
+
else
|
32
|
+
connected!
|
33
|
+
end
|
34
|
+
rescue Exception => e
|
35
|
+
Marvin::ExceptionTracker.log(e)
|
36
|
+
Marvin::IRC::Client.stop
|
37
|
+
end
|
38
|
+
|
39
|
+
def ssl_handshake_completed
|
40
|
+
logger.info "SSL handshake completed for #{host_with_port}"
|
41
|
+
connected! if should_use_ssl?
|
42
|
+
rescue Exception => e
|
43
|
+
Marvin::ExceptionTracker.log(e)
|
44
|
+
Marvin::IRC::Client.stop
|
66
45
|
end
|
67
46
|
|
68
47
|
def unbind
|
69
|
-
client.process_disconnect
|
48
|
+
@client.process_disconnect
|
70
49
|
super
|
71
50
|
end
|
72
51
|
|
73
52
|
def receive_line(line)
|
74
|
-
|
75
|
-
|
53
|
+
return unless @connected
|
54
|
+
line = line.strip
|
55
|
+
logger.debug "<< #{line}"
|
56
|
+
@client.receive_line(line)
|
57
|
+
rescue Exception => e
|
58
|
+
logger.warn "Uncaught exception raised; Likely in Marvin"
|
59
|
+
Marvin::ExceptionTracker.log(e)
|
76
60
|
end
|
77
61
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
## Client specific details
|
86
|
-
|
87
|
-
# Starts the EventMachine loop and hence starts up the actual
|
88
|
-
# networking portion of the IRC Client.
|
89
|
-
def self.run(force = false)
|
90
|
-
return if self.stopped && !force
|
91
|
-
self.setup # So we have options etc
|
92
|
-
settings = YAML.load_file(Marvin::Settings.root / "config/connections.yml")
|
93
|
-
if settings.is_a?(Hash)
|
94
|
-
# Use epoll if available
|
95
|
-
EventMachine.epoll
|
96
|
-
EventMachine::run do
|
97
|
-
settings.each do |name, options|
|
98
|
-
settings = options.symbolize_keys!
|
99
|
-
settings[:server] ||= name
|
100
|
-
settings.reverse_merge!(:port => 6667, :channels => [])
|
101
|
-
connect settings
|
102
|
-
end
|
62
|
+
def send_line(*lines)
|
63
|
+
return unless @connected
|
64
|
+
lines.each do |line|
|
65
|
+
logger.debug ">> #{line.strip}"
|
66
|
+
send_data line
|
103
67
|
end
|
104
|
-
else
|
105
|
-
logger.fatal "config/connections.yml couldn't be loaded. Exiting"
|
106
68
|
end
|
69
|
+
|
70
|
+
def connected!
|
71
|
+
@connected = true
|
72
|
+
@client.process_connect
|
73
|
+
end
|
74
|
+
|
75
|
+
def should_use_ssl?
|
76
|
+
@should_use_ssl ||= @configuration.ssl?
|
77
|
+
end
|
78
|
+
|
79
|
+
def host_with_port
|
80
|
+
"#{@configuration.host}:#{@configuration.port}"
|
81
|
+
end
|
82
|
+
|
107
83
|
end
|
108
84
|
|
109
|
-
|
110
|
-
logger.info "Connecting to #{opts[:server]}:#{opts[:port]} - Channels: #{opts[:channels].join(", ")}"
|
111
|
-
EventMachine::connect(opts[:server], opts[:port], EMConnection, opts)
|
112
|
-
end
|
85
|
+
## Client specific details
|
113
86
|
|
114
|
-
def
|
115
|
-
|
116
|
-
logger.debug "Telling all connections to quit"
|
117
|
-
self.connections.dup.each { |connection| connection.quit }
|
118
|
-
logger.debug "Telling Event Machine to Stop"
|
119
|
-
EventMachine::stop_event_loop
|
120
|
-
logger.debug "Stopped."
|
121
|
-
self.stopped = true
|
87
|
+
def send_line(*args)
|
88
|
+
@em_connection.send_line(*args)
|
122
89
|
end
|
123
90
|
|
124
|
-
|
125
|
-
|
126
|
-
EventMachine
|
127
|
-
|
128
|
-
|
91
|
+
class << self
|
92
|
+
|
93
|
+
# Starts the EventMachine loop and hence starts up the actual
|
94
|
+
# networking portion of the IRC Client.
|
95
|
+
def run(opts = {}, force = false)
|
96
|
+
self.development = opts[:development]
|
97
|
+
return if @stopped && !force
|
98
|
+
self.setup # So we have options etc
|
99
|
+
connections_file = Marvin::Settings.root / "config" / "connections.yml"
|
100
|
+
connections = Marvin::Nash.load_file(connections_file) rescue nil
|
101
|
+
if connections.present?
|
102
|
+
# Use epoll if available
|
103
|
+
EventMachine.kqueue
|
104
|
+
EventMachine.epoll
|
105
|
+
EventMachine.run do
|
106
|
+
connections.each_pair do |server, configuration|
|
107
|
+
connect(configuration.merge(:server => server.to_s))
|
108
|
+
end
|
109
|
+
Marvin::Distributed::Server.start if Marvin::Distributed::Handler.registered?
|
110
|
+
@@stopped = false
|
111
|
+
end
|
112
|
+
else
|
113
|
+
logger.fatal "config/connections.yml couldn't be loaded."
|
114
|
+
end
|
129
115
|
end
|
116
|
+
|
117
|
+
def connect(c, &blk)
|
118
|
+
c = normalize_connection_options(c)
|
119
|
+
raise ArgumentError, "Your connection options must specify a server" if !c.server?
|
120
|
+
raise ArgumentError, "Your connection options must specify a port" if !c.port?
|
121
|
+
real_block = blk.present? ? proc { |c| blk.call(connection.client) } : nil
|
122
|
+
logger.info "Connecting to #{c.server}:#{c.port} (using ssl: #{c.ssl?}) - Channels: #{c.channels.join(", ")}"
|
123
|
+
EventMachine.connect(c.server, c.port, EMConnection, c, &real_block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def stop
|
127
|
+
return if @@stopped
|
128
|
+
logger.debug "Telling all connections to quit"
|
129
|
+
connections.dup.each { |connection| connection.quit }
|
130
|
+
logger.debug "Telling Event Machine to Stop"
|
131
|
+
EventMachine.stop_event_loop
|
132
|
+
logger.debug "Stopped."
|
133
|
+
@@stoped = true
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_reconnect(c)
|
137
|
+
logger.warn "Adding timer to reconnect to #{c.server}:#{c.port} in 15 seconds"
|
138
|
+
EventMachine.add_timer(15) do
|
139
|
+
logger.warn "Preparing to reconnect to #{c.server}:#{c.port}"
|
140
|
+
connect(c)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
protected
|
145
|
+
|
146
|
+
def normalize_connection_options(config)
|
147
|
+
config = Marvin::Nash.new(config) if !config.is_a?(Marvin::Nash)
|
148
|
+
config = config.normalized
|
149
|
+
channels = config.channels
|
150
|
+
if channels.present?
|
151
|
+
config.channels = [*channels].compact.reject { |c| c.blank? }
|
152
|
+
else
|
153
|
+
config.channels = []
|
154
|
+
end
|
155
|
+
config.host ||= config.server
|
156
|
+
return config
|
157
|
+
end
|
158
|
+
|
130
159
|
end
|
131
160
|
|
132
161
|
# Registers a callback handle that will be periodically run.
|
133
162
|
def periodically(timing, event_callback)
|
134
|
-
|
135
|
-
EventMachine::add_periodic_timer(timing, &callback)
|
163
|
+
EventMachine.add_periodic_timer(timing) { dispatch(event_callback.to_sym) }
|
136
164
|
end
|
137
165
|
|
138
166
|
end
|
data/lib/marvin/irc/event.rb
CHANGED
@@ -3,32 +3,36 @@ module Marvin::IRC
|
|
3
3
|
attr_accessor :keys, :name, :raw_arguments, :prefix
|
4
4
|
|
5
5
|
def initialize(name, *args)
|
6
|
-
|
7
|
-
|
6
|
+
@name = name.to_sym
|
7
|
+
@keys = args.flatten.map { |k| k.to_sym }
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_hash
|
11
11
|
return @hash_value unless @hash_value.blank?
|
12
12
|
results = {}
|
13
|
-
values =
|
14
|
-
last_index =
|
15
|
-
|
13
|
+
values = @raw_arguments.to_a
|
14
|
+
last_index = @keys.size - 1
|
15
|
+
@keys.each_with_index do |key, i|
|
16
16
|
results[key] = (i == last_index ? values.join(" ").strip : values.shift)
|
17
17
|
end
|
18
|
-
results.merge!(prefix.to_hash) unless prefix.blank?
|
19
|
-
|
18
|
+
results.merge!(@prefix.to_hash) unless @prefix.blank?
|
19
|
+
@hash_value = results
|
20
20
|
end
|
21
21
|
|
22
22
|
def inspect
|
23
|
-
"#<Marvin::IRC::Event name=#{
|
23
|
+
"#<Marvin::IRC::Event name=#{@name} attributes=#{to_hash.inspect} >"
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_event_name(prefix = nil)
|
27
|
+
[prefix, @name].join("_").to_sym
|
24
28
|
end
|
25
29
|
|
26
30
|
def to_incoming_event_name
|
27
|
-
:
|
31
|
+
to_event_name :incoming
|
28
32
|
end
|
29
33
|
|
30
34
|
def to_outgoing_event_name
|
31
|
-
:
|
35
|
+
to_event_name :outgoing
|
32
36
|
end
|
33
37
|
|
34
38
|
end
|
data/lib/marvin/irc.rb
CHANGED
data/lib/marvin/middle_man.rb
CHANGED
@@ -20,16 +20,18 @@ module Marvin
|
|
20
20
|
# attempt to recognize the command and convert
|
21
21
|
# it to an event which can be used for other stuff.
|
22
22
|
def to_event
|
23
|
-
|
23
|
+
# If we have a numeric...
|
24
|
+
if @code =~ /^\d+$/
|
24
25
|
ev = @@commands[:numeric].dup
|
25
26
|
data = @params[0..-2]
|
26
27
|
data << "#{@params.last.include?(" ") ? ":" : ""}#{@params.last}"
|
27
28
|
ev.raw_arguments = [self.code.to_s, data.join(" ")]
|
28
|
-
elsif code == "PRIVMSG" && params.last
|
29
|
-
|
30
|
-
|
29
|
+
elsif code == "PRIVMSG" && params.last =~ /^\001(.*)\001$/
|
30
|
+
results = $1.to_s
|
31
|
+
if results =~ /^ACTION /
|
32
|
+
name, value = :action, results.gsub(/^ACTION /, '')
|
31
33
|
else
|
32
|
-
name, value = :ctcp,
|
34
|
+
name, value = :ctcp, results
|
33
35
|
end
|
34
36
|
self.params[-1] = value
|
35
37
|
ev = @@commands[name].dup
|
@@ -96,9 +98,9 @@ module Marvin
|
|
96
98
|
register_event :ison, :ISON, :nick
|
97
99
|
# Add the default numeric event
|
98
100
|
register_event :numeric, :numeric, :code, :data
|
99
|
-
# And a few others reserved for special
|
100
|
-
register_event :action, :action, :message
|
101
|
-
register_event :ctcp, :ctcp, :message
|
101
|
+
# And a few others reserved for special purposes
|
102
|
+
register_event :action, :action, :target, :message
|
103
|
+
register_event :ctcp, :ctcp, :target, :message
|
102
104
|
|
103
105
|
end
|
104
106
|
end
|
@@ -3,25 +3,30 @@ module Marvin
|
|
3
3
|
module Prefixes
|
4
4
|
# A Generic host mask prefix for a message.
|
5
5
|
class HostMask
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :nick, :user, :host
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def initialize(nick = nil, user = nil, host = nil)
|
9
|
+
@nick = nick || ""
|
10
|
+
@user = user || ""
|
11
|
+
@host = host || ""
|
12
12
|
end
|
13
13
|
|
14
14
|
# Convert it to a usable hash.
|
15
15
|
def to_hash
|
16
|
-
{
|
16
|
+
{
|
17
|
+
:nick => @nick.dup.freeze,
|
18
|
+
:ident => @user.dup.freeze,
|
19
|
+
:host => @host.dup.freeze
|
20
|
+
}
|
17
21
|
end
|
18
22
|
|
19
23
|
# Converts it back to a nicer form / a string.
|
20
24
|
def to_s
|
21
25
|
str = ""
|
22
|
-
str << @
|
26
|
+
str << @nick.to_s
|
23
27
|
str << "!#{@user}" unless @user.blank?
|
24
28
|
str << "@#{@host}" unless @host.blank?
|
29
|
+
str
|
25
30
|
end
|
26
31
|
|
27
32
|
end
|