Sutto-marvin 0.4.0 → 0.8.0.0

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.
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"