Class: Butler::IRC::Parser

Inherits:
Object
  • Object
show all
Includes:
Log::Comfort
Defined in:
lib/butler/irc/parser.rb,
lib/butler/irc/parser/command.rb

Overview

Parses messages, automatically converts provides a parser that automatically connects users and channels regarding who myself is (out_of_sight, back_in_sight for users) allows creation of dialogs from privmsg and notice messages

Defined Under Namespace

Modules: ParseError Classes: Command, InvalidMessageFormat, UnknownCommand

Constant Summary collapse

BasePath =

enables chdirs, path to the command-sets

(File.expand_path(File.dirname(__FILE__))+'/parser').freeze

Instance Attribute Summary collapse

Attributes included from Log::Comfort

#logger

Instance Method Summary collapse

Methods included from Log::Comfort

#debug, #error, #exception, #fail, #info, #log, #warn

Constructor Details

#initialize(client, users, channels, *command_sets) ⇒ Parser

Returns a new instance of Parser.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/butler/irc/parser.rb', line 54

def initialize(client, users, channels, *command_sets)
	@logger       = nil
	@client       = client
	@users        = users
	@channels     = channels
	@msg_identify = false
	@command_sets = command_sets
	@isupport     = OpenStruct.new(
		"nicklen"      => 8,
		"channellen"   => 50,
		"prefixes"     => "@+"
	)
	
	reset
end

Instance Attribute Details

#channelsObject (readonly)

Returns the value of attribute channels.



47
48
49
# File 'lib/butler/irc/parser.rb', line 47

def channels
  @channels
end

#clientObject (readonly)

Returns the value of attribute client.



45
46
47
# File 'lib/butler/irc/parser.rb', line 45

def client
  @client
end

#commandsObject (readonly)

Returns the value of attribute commands.



48
49
50
# File 'lib/butler/irc/parser.rb', line 48

def commands
  @commands
end

#expressionObject (readonly)

Returns the value of attribute expression.



49
50
51
# File 'lib/butler/irc/parser.rb', line 49

def expression
  @expression
end

#isupportObject (readonly)

Returns the value of attribute isupport.



50
51
52
# File 'lib/butler/irc/parser.rb', line 50

def isupport
  @isupport
end

#msg_identifyObject

Returns the value of attribute msg_identify.



52
53
54
# File 'lib/butler/irc/parser.rb', line 52

def msg_identify
  @msg_identify
end

#usersObject (readonly)

Returns the value of attribute users.



46
47
48
# File 'lib/butler/irc/parser.rb', line 46

def users
  @users
end

Instance Method Details

#add(raw, *args, &proc) ⇒ Object

Raises:

  • (IndexError)


100
101
102
103
# File 'lib/butler/irc/parser.rb', line 100

def add(raw, *args, &proc)
	raise IndexError, "Command #{raw} is already registered. Did you want 'alter'?" if @commands.has_key?(raw)
	@commands[raw.downcase] = Command.new(raw, *args, &proc)
end

#add_expression(name, value) ⇒ Object



92
93
94
# File 'lib/butler/irc/parser.rb', line 92

def add_expression(name, value)
	@expression[name] = value
end

#alter(raw, *args, &proc) ⇒ Object

Raises:

  • (IndexError)


105
106
107
108
# File 'lib/butler/irc/parser.rb', line 105

def alter(raw, *args, &proc)
	raise IndexError, "Command #{raw} is not registered. Did you want 'add'?" unless @commands.has_key?(raw)
	@commands[raw.downcase] = Command.new(raw, *args, &proc)
end

#alter_expression(name, value) ⇒ Object



96
97
98
# File 'lib/butler/irc/parser.rb', line 96

def alter_expression(name, value)
	@expression[name] = value
end

#inspectObject



110
111
112
# File 'lib/butler/irc/parser.rb', line 110

def inspect
	"#<%s:0x%x>" %  [self.class, object_id]
end

#leave_channel(message, reason1, reason2) ⇒ Object



158
159
160
161
162
163
164
165
166
167
# File 'lib/butler/irc/parser.rb', line 158

def leave_channel(message, reason1, reason2)
	if message.from && message.channel then
		message.from.delete_channel(message.channel, reason1)
		message.channel.delete_user(message.from, reason1)
		if message.from == @users.myself then
			@channels.delete(message.channel)
			@users.delete_channel(message.channel, reason2)
		end
	end
end

#load(*files) ⇒ Object

Raises:

  • (ArgumentError)


83
84
85
86
87
88
89
90
# File 'lib/butler/irc/parser.rb', line 83

def load(*files)
	raise ArgumentError, "Requires at least one argument." if files.empty?
	files.each { |name|
		file = name.include?('/') ? name : "#{BasePath}/#{name}.rb"
		instance_eval(File.read(file), file)
		info("Loaded command set #{file}")
	}
end

#reset(isupport = nil) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/butler/irc/parser.rb', line 74

def reset(isupport=nil)
	@isupport   = OpenStruct.new(isupport) if isupport
	@expression = OpenStruct.new
	@commands   = Hash.new { |h,k| raise IndexError, "Unknown command #{k}" }
	load(*@command_sets)
	@expression.simple_message  = /\A(?::([^ \0]+) )?([A-Za-z\d]+|\d{3})(?: (.*))?\z/
	@expression.simple_hostmask = /(#{expression.nick})(?:(?:!(#{expression.user}))?@(#{expression.host}))?/
end

#same_nick?(a, b) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/butler/irc/parser.rb', line 70

def same_nick?(a,b)
	a.to_str.strip_user_prefixes.downcase == b.to_str.strip_user_prefixes.downcase
end

#server_message(raw) ⇒ Object

parses an incomming message and returns a Message object from which you can easily access parsed data. Expects the newlines to be already chomped off.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/butler/irc/parser.rb', line 117

def server_message(raw)
	prefix, command, params, symbol, from = nil
	
	# Basic analysis of the message
	raise InvalidMessageFormat, raw unless matched = raw.match(@expression.simple_message)
	prefix, command, params	= *matched.captures
	command.downcase!
		
	# Parse prefix if possible (<nick>!<user>@<host>)
	from	= @users.create(*matched.captures) if prefix and matched = prefix.match(@expression.simple_hostmask)

	# in depth analyzis of the message
	parser  = @commands[command.downcase]
	symbol  = parser.symbol
	message	= Message.new(@client, symbol, raw, prefix, command, params)
	message.alter_member(:from, from)
	
	parser.create_fields(message)
	
	if message.for then
		if message.for.valid_channelname? then
			channel = @channels.create(message.for)
			message.alter_member(:channel, channel)
			message.alter_member(:for, channel)
		else
			message.alter_member(:for,	@users.create(message.for))
		end
	end
	message.alter_member(:channel, @channels.create(message.channel)) if message.channel
	
	parser.process(message, self)
	
	return message
rescue IndexError
		raise UnknownCommand, "Unknown command #{command}: #{raw.inspect}"
rescue => e
	e.extend ParseError
	e.prepend "Message: #{raw.inspect}"
	raise e
end