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.
Files changed (85) hide show
  1. data/bin/marvin +22 -156
  2. data/handlers/keiki_thwopper.rb +21 -0
  3. data/handlers/tweet_tweet.rb +1 -3
  4. data/lib/marvin/abstract_client.rb +75 -189
  5. data/lib/marvin/abstract_parser.rb +9 -11
  6. data/lib/marvin/base.rb +134 -101
  7. data/lib/marvin/client/actions.rb +104 -0
  8. data/lib/marvin/client/default_handlers.rb +97 -0
  9. data/lib/marvin/command_handler.rb +60 -49
  10. data/lib/marvin/console.rb +4 -31
  11. data/lib/marvin/core_commands.rb +30 -12
  12. data/lib/marvin/distributed/client.rb +225 -0
  13. data/lib/marvin/distributed/handler.rb +85 -0
  14. data/lib/marvin/distributed/protocol.rb +88 -0
  15. data/lib/marvin/distributed/server.rb +154 -0
  16. data/lib/marvin/distributed.rb +4 -10
  17. data/lib/marvin/dsl.rb +103 -0
  18. data/lib/marvin/exception_tracker.rb +7 -4
  19. data/lib/marvin/irc/client.rb +127 -99
  20. data/lib/marvin/irc/event.rb +14 -10
  21. data/lib/marvin/irc.rb +0 -1
  22. data/lib/marvin/middle_man.rb +1 -1
  23. data/lib/marvin/parsers/command.rb +10 -8
  24. data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
  25. data/lib/marvin/parsers/prefixes/server.rb +1 -1
  26. data/lib/marvin/parsers/ragel_parser.rb +59 -52
  27. data/lib/marvin/parsers/ragel_parser.rl +6 -7
  28. data/lib/marvin/parsers/simple_parser.rb +4 -9
  29. data/lib/marvin/parsers.rb +1 -2
  30. data/lib/marvin/settings.rb +29 -79
  31. data/lib/marvin/test_client.rb +20 -26
  32. data/lib/marvin/util.rb +10 -3
  33. data/lib/marvin.rb +42 -39
  34. data/templates/boot.erb +3 -0
  35. data/templates/connections.yml.erb +10 -0
  36. data/templates/debug_handler.erb +5 -0
  37. data/templates/hello_world.erb +10 -0
  38. data/templates/rakefile.erb +15 -0
  39. data/templates/settings.yml.erb +8 -0
  40. data/{config/setup.rb → templates/setup.erb} +8 -10
  41. data/templates/test_helper.erb +17 -0
  42. data/test/abstract_client_test.rb +63 -0
  43. data/test/parser_comparison.rb +2 -2
  44. data/test/parser_test.rb +3 -3
  45. data/test/test_helper.rb +58 -6
  46. metadata +51 -83
  47. data/README.textile +0 -105
  48. data/TUTORIAL.textile +0 -54
  49. data/VERSION.yml +0 -4
  50. data/config/boot.rb +0 -14
  51. data/config/connections.yml.sample +0 -5
  52. data/config/settings.yml.sample +0 -13
  53. data/handlers/logging_handler.rb +0 -89
  54. data/lib/marvin/core_ext.rb +0 -11
  55. data/lib/marvin/daemon.rb +0 -71
  56. data/lib/marvin/data_store.rb +0 -73
  57. data/lib/marvin/dispatchable.rb +0 -99
  58. data/lib/marvin/distributed/dispatch_handler.rb +0 -83
  59. data/lib/marvin/distributed/drb_client.rb +0 -78
  60. data/lib/marvin/distributed/ring_server.rb +0 -41
  61. data/lib/marvin/handler.rb +0 -12
  62. data/lib/marvin/irc/server/abstract_connection.rb +0 -84
  63. data/lib/marvin/irc/server/base_connection.rb +0 -66
  64. data/lib/marvin/irc/server/channel.rb +0 -115
  65. data/lib/marvin/irc/server/named_store.rb +0 -14
  66. data/lib/marvin/irc/server/remote_interface.rb +0 -77
  67. data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
  68. data/lib/marvin/irc/server/user.rb +0 -5
  69. data/lib/marvin/irc/server/user_connection.rb +0 -134
  70. data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
  71. data/lib/marvin/irc/server.rb +0 -71
  72. data/lib/marvin/loader.rb +0 -149
  73. data/lib/marvin/logger.rb +0 -86
  74. data/lib/marvin/options.rb +0 -42
  75. data/lib/marvin/parsers/regexp_parser.rb +0 -93
  76. data/lib/marvin/status.rb +0 -72
  77. data/script/client +0 -3
  78. data/script/console +0 -3
  79. data/script/distributed_client +0 -3
  80. data/script/install +0 -1
  81. data/script/ring_server +0 -4
  82. data/script/server +0 -4
  83. data/script/status +0 -3
  84. data/spec/marvin/abstract_client_test.rb +0 -38
  85. data/spec/spec_helper.rb +0 -14
data/bin/marvin CHANGED
@@ -1,167 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
- require 'fileutils'
4
- require "thor"
3
+ require File.join(File.dirname(__FILE__), "..", "lib", "marvin")
5
4
 
6
- class Marvin < Thor
5
+ Marvin::Application.processing(ARGV) do |a|
7
6
 
8
- GEM_ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
7
+ a.banner = "Marvin v#{Marvin::VERSION} - An IRC Library for Ruby"
9
8
 
10
- attr_accessor :dest
9
+ a.generator!
11
10
 
12
- # Map default help tasks.
13
- map ["-h", "-?", "--help", "-D"] => :help
11
+ a.option :development, "Runs the app in development mode (handler reloading)", :shortcut => "D"
12
+ a.controller! :client, "Starts the actual Marvin client instance"
13
+ a.controller! :console, "Opens a friendly IRB prompt with Marvin pre-loaded"
14
+ a.controller! :distributed_client, "Starts a distributed client instance"
14
15
 
15
- desc "create [PATH]", "creates a new marvin app at the given path"
16
- method_options :verbose => :boolean
17
- def create(path)
18
- @dest = File.expand_path(path)
19
- @verbose = options[:verbose]
20
- if File.directory?(@dest)
21
- STDOUT.puts "The given directory, \"#{path}\", already exists."
22
- exit! 1
23
- else
24
- say "Creating Marvin app"
25
- say " => Making directories"
26
- mkdir @dest
27
- mkdir source(@dest, "script")
28
- mkdir source(@dest, "config")
29
- mkdir source(@dest, "handlers")
30
- mkdir_p source(@dest, "tmp/pids")
31
- mkdir source(@dest, "log")
32
- mkdir source(@dest, "lib")
33
- say " => Copying files..."
34
- copy "config/setup.rb"
35
- copy "config/boot.rb"
36
- copy "config/connections.yml.sample", "config/connections.yml"
37
- copy "config/settings.yml.sample", "config/settings.yml"
38
- copy "handlers/hello_world.rb"
39
- copy "handlers/debug_handler.rb"
40
- %w(client console distributed_client ring_server status).each do |c|
41
- copy "script/#{c}"
42
- FileUtils.chmod 0755, source(@dest, "script/#{c}")
43
- end
44
- say "Done!"
45
- end
46
- end
47
-
48
- map "cl" => :client, "st" => :status, "rs" => :ring_server,
49
- "dc" => :distributed_client, "co" => :console
50
-
51
- desc "start [PATH]", "starts client at the given path"
52
- method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
53
- def start(path = ".")
54
- @dest = File.expand_path(path)
55
- start_script(:client)
56
- end
57
-
58
- desc "status [PATH]", "shows status of marvin app at a given location"
59
- def status(path = ".")
60
- @dest = File.expand_path(path)
61
- start_script(:status)
62
- end
63
-
64
- desc "client [PATH]", "starts a client instance from the given location"
65
- method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
66
- def client(path = ".")
67
- @dest = File.expand_path(path)
68
- start_script(:client)
69
- end
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
-
78
- desc "ring_server [PATH]", "starts a ring server from the given location"
79
- method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
80
- def ring_server(path = ".")
81
- @dest = File.expand_path(path)
82
- start_script(:ring_server)
83
- end
84
-
85
- desc "distributed_client [PATH]", "starts a distributed client from the given location"
86
- method_options :verbose => :boolean, :daemon => :boolean, :level => :optional,
87
- :kill => :boolean, :nodes => :numeric
88
- def distributed_client(path = ".")
89
- @dest = File.expand_path(path)
90
- start_script(:distributed_client)
91
- end
92
-
93
- desc "console [PATH]", "starts a marvin console from the given location"
94
- def console(path = ".")
95
- @dest = File.expand_path(path)
96
- start_script(:console)
97
- end
98
-
99
- private
100
-
101
- def source(*args)
102
- File.expand_path(File.join(*args))
103
- end
104
-
105
- def copy(from, to = from)
106
- s, d = source(GEM_ROOT, from), source(@dest, to)
107
- say " --> cp #{s.gsub(" ", "\\ ")} #{d.gsub(" ", "\\ ")}" if @verbose
108
- FileUtils.cp_r(s, d)
109
- end
110
-
111
- def mkdir(path)
112
- say " --> mkdir #{path.gsub(" ", "\\ ")}" if @verbose
113
- FileUtils.mkdir path
114
- end
115
-
116
- def mkdir_p(path)
117
- say " --> mkdir #{path.gsub(" ", "\\ ")}" if @verbose
118
- FileUtils.mkdir_p path
119
- end
120
-
121
- def say(text)
122
- STDOUT.puts text
123
- end
124
-
125
- def marvin_repo?(path, type = client)
126
- File.directory?(source(path, "script")) && File.exist?(source(path, "script/#{type}"))
127
- end
128
-
129
- def start_script(name)
130
- if marvin_repo?(@dest, name)
131
- extra_args = []
132
- extra_args << "-k" if options[:kill]
133
- extra_args << "-v" if options[:verbose]
134
- extra_args << "-d" if options[:daemon]
135
- extra_args << "--level=#{options[:level]}" if options[:level]
136
- if options[:daemon] && options[:nodes]
137
- nodes = options[:nodes]
138
- else
139
- nodes = 1
140
- end
141
- Dir.chdir(@dest) do
142
- # Lets you start a number of different processes.
143
- # uses system if there are more than 1 nodes, exec
144
- # otherwise.
145
- if nodes > 1
146
- nodes.times { system("script/#{name}", *extra_args) }
147
- else
148
- exec("script/#{name}", *extra_args)
149
- end
150
- end
151
- else
152
- STDOUT.puts "Woop! #{@dest.gsub(" ", "\\ ")} isn't a marvin app."
16
+ a.option :force, "force the creation of the application"
17
+ a.add "create PATH", "Creates a marvin application at the given location" do |path, options|
18
+ path = File.expand_path(path)
19
+ if File.exists?(path) && !options[:force]
20
+ die! "The path you tried to use, #{path}, already exists. Please try another or use the --force option"
153
21
  end
22
+ setup_generator(path)
23
+ folders 'tmp', 'config', 'lib', 'handlers', 'test'
24
+ template 'boot.erb', 'config/boot.rb'
25
+ template 'setup.erb', 'config/setup.rb'
26
+ template 'settings.yml.erb', 'config/settings.yml'
27
+ template 'connections.yml.erb', 'config/connections.yml'
28
+ template 'debug_handler.erb', 'handlers/debug_handler.rb'
29
+ template 'hello_world.erb', 'handlers/hello_world.rb'
30
+ template 'rakefile.erb', 'Rakefile'
154
31
  end
155
32
 
156
33
  end
157
-
158
- STDOUT.puts "Marvin - IRC Library / Framework for Ruby"
159
-
160
- # Check if we have arguments, we run the normal
161
- # thor task otherwise we just print the help
162
- # message.
163
- if ARGV.empty?
164
- Marvin.new.help
165
- else
166
- Marvin.start
167
- end
@@ -0,0 +1,21 @@
1
+ class KeikiThwopper < Marvin::Base
2
+
3
+ FROM_REGEXP = /^(sutto)/i
4
+ THWOP_REGEXP = /(t+h+w+o+m*p+|stab|kill)/i
5
+
6
+ MESSAGES = [
7
+ "mwahahahaha",
8
+ "you totally deserved it",
9
+ "oi! leave 'em alone!",
10
+ "say hello to my little friend",
11
+ "you know, they could have liked that?"
12
+ ]
13
+
14
+ on_event :incoming_action, :thwop_back
15
+
16
+ def thwop_back
17
+ return if !from || from !~ FROM_REGEXP || options.message !~ THWOP_REGEXP
18
+ action "#{$1}s #{from} (#{MESSAGES[rand(MESSAGES.length)]})"
19
+ end
20
+
21
+ end
@@ -1,6 +1,6 @@
1
1
  # Not Yet Complete: Twitter Client in Channel.
2
2
  class TweetTweet < Marvin::Base
3
-
3
+
4
4
  on_event :client_connected do
5
5
  start_tweeting
6
6
  end
@@ -16,6 +16,4 @@ class TweetTweet < Marvin::Base
16
16
  def show_tweet(tweet)
17
17
  end
18
18
 
19
-
20
-
21
19
  end
@@ -1,30 +1,30 @@
1
- require 'ostruct'
2
- require 'active_support'
3
1
  require "marvin/irc/event"
4
2
 
5
3
  module Marvin
6
4
  class AbstractClient
7
5
 
8
- include Marvin::Dispatchable
6
+ is :dispatchable, :loggable
9
7
 
10
- def initialize(opts = {})
11
- self.original_opts = opts.dup # Copy the options so we can use them to reconnect.
12
- self.server = opts[:server]
13
- self.port = opts[:port]
14
- self.default_channels = opts[:channels]
15
- self.nicks = opts[:nicks] || []
16
- self.pass = opts[:pass]
8
+ def initialize(opts)
9
+ opts = opts.to_nash if opts.is_a?(Hash)
10
+ @connection_config = opts.dup # Copy the options so we can use them to reconnect.
11
+ @server = opts.server
12
+ @port = opts.port
13
+ @default_channels = opts.channels
14
+ @nicks = opts.nicks || []
15
+ @pass = opts.pass
17
16
  end
18
17
 
19
- cattr_accessor :events, :configuration, :logger, :is_setup, :connections
20
- attr_accessor :channels, :nickname, :server, :port, :nicks, :pass, :disconnect_expected, :original_opts
18
+ cattr_accessor :events, :configuration, :is_setup, :connections, :development
19
+ attr_accessor :channels, :nickname, :server, :port, :nicks, :pass,
20
+ :disconnect_expected, :connection_config
21
21
 
22
22
  # Set the default values for the variables
23
- self.events = []
24
- self.configuration = OpenStruct.new
25
- self.configuration.channels = []
26
- self.connections = []
27
-
23
+ @@events = []
24
+ @@configuration = Marvin::Nash.new
25
+ @@connections = []
26
+ @@development = false
27
+
28
28
  # Initializes the instance variables used for the
29
29
  # current connection, dispatching a :client_connected event
30
30
  # once it has finished. During this process, it will
@@ -32,78 +32,79 @@ module Marvin
32
32
  def process_connect
33
33
  self.class.setup
34
34
  logger.info "Initializing the current instance"
35
- self.channels = []
36
- self.connections << self
35
+ @channels = []
36
+ connections << self
37
37
  logger.info "Setting the client for each handler"
38
- self.handlers.each { |h| h.client = self if h.respond_to?(:client=) }
38
+ setup_handlers
39
39
  logger.info "Dispatching the default :client_connected event"
40
40
  dispatch :client_connected
41
41
  end
42
42
 
43
43
  def process_disconnect
44
- logger.info "Handling disconnect for #{self.server}:#{self.port}"
45
- self.connections.delete(self) if self.connections.include?(self)
44
+ logger.info "Handling disconnect for #{host_with_port}"
45
+ connections.delete(self)
46
46
  dispatch :client_disconnected
47
- unless self.disconnect_expected
48
- logger.warn "Lost connection to server - adding reconnect"
49
- self.class.add_reconnect self.original_opts
47
+ unless @disconnect_expected
48
+ logger.warn "Unexpectly lost connection to server; adding reconnect"
49
+ self.class.add_reconnect @connection_config
50
50
  else
51
- Marvin::Loader.stop! if self.connections.blank?
51
+ Marvin::Loader.stop! if connections.blank?
52
+ end
53
+ end
54
+
55
+ def setup_handlers
56
+ handlers.each { |h| h.client = self if h.respond_to?(:client=) }
57
+ end
58
+
59
+ def process_development
60
+ if @@development
61
+ Marvin::Reloading.reload!
62
+ setup_handlers
52
63
  end
53
64
  end
54
65
 
66
+ def dispatch(*args)
67
+ process_development
68
+ super
69
+ end
70
+
55
71
  # Sets the current class-wide settings of this IRC Client
56
72
  # to either an OpenStruct or the results of #to_hash on
57
73
  # any other value that is passed in.
58
74
  def self.configuration=(config)
59
- @@configuration = config.is_a?(OpenStruct) ? config : OpenStruct.new(config.to_hash)
75
+ config = Marvin::Nash.new(config.to_hash) unless config.is_a?(Marvin::Nash)
76
+ @@configuration = config.normalized
77
+ end
78
+
79
+ def self.setup?
80
+ @setup ||= false
60
81
  end
61
82
 
62
- # Initializes class-wide settings and those that
63
- # are required such as the logger. by default, it
64
- # will convert the channel option of the configuration
65
- # to be channels - hence normalising it into a format
66
- # that is more widely used throughout the client.
67
83
  def self.setup
68
- return if self.is_setup
69
- if configuration.logger.blank?
70
- require 'logger'
71
- configuration.logger = Marvin::Logger.logger
84
+ return if setup?
85
+ configure
86
+ end
87
+
88
+ def self.configure
89
+ config = Marvin::Nash.new
90
+ config.merge! Marvin::Settings.configuration
91
+ if block_given?
92
+ yield(nash = Marvin::Nash.new)
93
+ config.merge! nash
72
94
  end
73
- self.logger = self.configuration.logger
74
- self.is_setup = true
95
+ @@configuration = config
96
+ # Help is only currently available on an instance running
97
+ # distributed handler.
98
+ Marvin::CoreCommands.register! unless Marvin::Distributed::Handler.registered?
99
+ @setup = true
75
100
  end
76
101
 
77
102
  ## Handling all of the the actual client stuff.
78
103
 
79
104
  def receive_line(line)
80
105
  dispatch :incoming_line, :line => line
81
- event = Marvin::Settings.default_parser.parse(line)
82
- dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
83
- end
84
-
85
- # Default handlers
86
-
87
- # The default handler for all things initialization-related
88
- # on the client. Usually, this will send the user command,
89
- # set out nick, join all of the channels / rooms we wish
90
- # to be in and if a password is specified in the configuration,
91
- # it will also attempt to identify us.
92
- def handle_client_connected(opts = {})
93
- logger.info "About to handle client connected"
94
- # If the pass is set
95
- unless self.pass.blank?
96
- logger.info "Sending pass for connection"
97
- command :pass, self.pass
98
- end
99
- # IRC Connection is establish so we send all the required commands to the server.
100
- logger.info "Setting default nickname"
101
- default_nickname = self.nicks.shift
102
- nick default_nickname
103
- logger.info "sending user command"
104
- command :user, self.configuration.user, "0", "*", Marvin::Util.last_param(self.configuration.name)
105
- rescue Exception => e
106
- Marvin::ExceptionTracker.log(e)
106
+ event = Marvin::Settings.parser.parse(line)
107
+ dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
107
108
  end
108
109
 
109
110
  def default_channels
@@ -115,145 +116,30 @@ module Marvin
115
116
  end
116
117
 
117
118
  def host_with_port
118
- @host_with_port ||= "#{self.server}:#{self.port}"
119
+ @host_with_port ||= "#{server}:#{port}"
119
120
  end
120
121
 
121
122
  def nicks
122
123
  if @nicks.blank? && !@nicks_loaded
123
124
  logger.info "Setting default nick list"
124
125
  @nicks = []
125
- @nicks << self.configuration.nick
126
- @nicks += self.configuration.nicks.to_a unless self.configuration.nicks.blank?
126
+ @nicks << configuration.nick if configuration.nick?
127
+ @nicks += configuration.nicks.to_a if configuration.nicks?
127
128
  @nicks.compact!
129
+ raise "No initial nicks for #{host_with_port}" if @nicks.blank?
128
130
  @nicks_loaded = true
129
131
  end
130
132
  return @nicks
131
133
  end
132
134
 
133
- # The default response for PING's - it simply replies
134
- # with a PONG.
135
- def handle_incoming_ping(opts = {})
136
- logger.info "Received Incoming Ping - Handling with a PONG"
137
- pong(opts[:data])
138
- end
139
-
140
- # TODO: Get the correct mapping for a given
141
- # Code.
142
- def handle_incoming_numeric(opts = {})
143
- case opts[:code]
144
- when Marvin::IRC::Replies[:RPL_WELCOME]
145
- handle_welcome
146
- when Marvin::IRC::Replies[:ERR_NICKNAMEINUSE]
147
- handle_nick_taken
148
- end
149
- code = opts[:code].to_i
150
- args = Marvin::Util.arguments(opts[:data])
151
- dispatch :incoming_numeric_processed, :code => code, :data => args
152
- end
153
-
154
- def handle_welcome
155
- logger.info "Say hello to my little friend - Got welcome"
156
- # If a password is specified, we will attempt to message
157
- # NickServ to identify ourselves.
158
- say ":IDENTIFY #{self.configuration.password}", "NickServ" unless self.configuration.password.blank?
159
- # Join the default channels IF they're already set
160
- # Note that Marvin::IRC::Client.connect will set them AFTER this stuff is run.
161
- self.default_channels.each { |c| self.join(c) }
162
- end
135
+ # Break it down into a couple of different files.
136
+ require 'marvin/client/default_handlers'
137
+ require 'marvin/client/actions'
163
138
 
164
- # The default handler for when a users nickname is taken on
165
- # on the server. It will attempt to get the nicknickname from
166
- # the nicknames part of the configuration (if available) and
167
- # will then call #nick to change the nickname.
168
- def handle_nick_taken
169
- logger.info "Nickname '#{self.nickname}' on #{self.server} taken, trying next."
170
- logger.info "Available Nicknames: #{self.nicks.empty? ? "None" : self.nicks.join(", ")}"
171
- if !self.nicks.empty?
172
- logger.info "Getting next nickname to switch"
173
- next_nick = self.nicks.shift # Get the next nickname
174
- logger.info "Attemping to set nickname to '#{next_nick}'"
175
- nick next_nick
176
- else
177
- logger.fatal "No Nicknames available - QUITTING"
178
- quit
179
- end
180
- end
181
-
182
- ## General IRC Functions
183
-
184
- # Sends a specified command to the server.
185
- # Takes name (e.g. :privmsg) and all of the args.
186
- # Very simply formats them as a string correctly
187
- # and calls send_data with the results.
188
- def command(name, *args)
189
- # First, get the appropriate command
190
- name = name.to_s.upcase
191
- args = args.flatten.compact
192
- irc_command = "#{name} #{args.join(" ").strip}\r\n"
193
- send_line irc_command
194
- end
195
-
196
- def join(channel)
197
- channel = Marvin::Util.channel_name(channel)
198
- # Record the fact we're entering the room.
199
- # TODO: Refactor to only add the channel when we receive confirmation we've joined.
200
- self.channels << channel
201
- command :JOIN, channel
202
- logger.info "Joined channel #{channel}"
203
- dispatch :outgoing_join, :target => channel
204
- end
205
-
206
- def part(channel, reason = nil)
207
- channel = Marvin::Util.channel_name(channel)
208
- if self.channels.include?(channel)
209
- command :part, channel, Marvin::Util.last_param(reason)
210
- dispatch :outgoing_part, :target => channel, :reason => reason
211
- logger.info "Parted from room #{channel}#{reason ? " - #{reason}" : ""}"
212
- else
213
- logger.warn "Tried to disconnect from #{channel} - which you aren't a part of"
214
- end
215
- end
216
-
217
- def quit(reason = nil)
218
- self.disconnect_expected = true
219
- logger.info "Preparing to part from #{self.channels.size} channels"
220
- self.channels.to_a.each do |chan|
221
- logger.info "Parting from #{chan}"
222
- self.part chan, reason
223
- end
224
- logger.info "Parted from all channels, quitting"
225
- command :quit
226
- dispatch :quit
227
- # Remove the connections from the pool
228
- self.connections.delete(self)
229
- logger.info "Quit from server"
230
- end
231
-
232
- def msg(target, message)
233
- command :privmsg, target, Marvin::Util.last_param(message)
234
- logger.info "Message sent to #{target} - #{message}"
235
- dispatch :outgoing_message, :target => target, :message => message
236
- end
237
-
238
- def action(target, message)
239
- action_text = Marvin::Util.last_param "\01ACTION #{message.strip}\01"
240
- command :privmsg, target, action_text
241
- dispatch :outgoing_action, :target => target, :message => message
242
- logger.info "Action sent to #{target} - #{message}"
243
- end
244
-
245
- def pong(data)
246
- command :pong, data
247
- dispatch :outgoing_pong
248
- logger.info "PONG sent to #{data}"
249
- end
139
+ protected
250
140
 
251
- def nick(new_nick)
252
- logger.info "Changing nickname to #{new_nick}"
253
- command :nick, new_nick
254
- self.nickname = new_nick
255
- dispatch :outgoing_nick, :new_nick => new_nick
256
- logger.info "Nickname changed to #{new_nick}"
141
+ def util
142
+ Marvin::Util
257
143
  end
258
144
 
259
145
  end
@@ -1,27 +1,25 @@
1
1
  module Marvin
2
- # An abstract class for an IRC protocol
3
- # Parser. Used as a basis for expirimentation.
4
2
  class AbstractParser
5
3
 
6
- def self.parse(line)
7
- return self.new(line.strip).to_event
8
- end
9
-
10
4
  attr_accessor :line, :command, :event
11
5
 
12
6
  # Instantiates a parser instance, attempts to
13
7
  # parse it for it's command and it's event.
14
8
  def initialize(line)
15
- self.line = line
16
- self.command = self.class.parse!(line)
17
- self.event = self.command.to_event unless self.command.blank?
9
+ @line = line
10
+ @command = self.class.parse!(line)
11
+ @event = @command.to_event unless @command.blank?
18
12
  end
19
13
 
20
14
  def to_event
21
- self.event
15
+ @event
16
+ end
17
+
18
+ def self.parse(line)
19
+ new(line.strip).to_event
22
20
  end
23
21
 
24
- private
22
+ protected
25
23
 
26
24
  def self.parse!(line)
27
25
  raise NotImplementedError, "Must be implemented in a subclass"