This module is responsible for the raw socket output, buffering of all “message” types of events, and exposing the magic to create a new output command + handler. All output methods are documented in the main Net::YAIL documentation.

Instance Public methods
act(target, message)

Buffers an :outgoing_act event. Target is user or channel, message is message.

# File lib/net/yail/output_api.rb, line 38
def act(target, message)
  buffer_output => :act, :target => target, :message => message)

Buffers the given event to be sent out when we are able to send something out to the given target. If buffering isn’t turned on, the event will be processed in the next loop of outgoing messages.

# File lib/net/yail/output_api.rb, line 18
def buffer_output(event)
  @privmsg_buffer_mutex.synchronize do
    @privmsg_buffer[] ||=
    @privmsg_buffer[].push event
create_command(command, output_base, *opts)

Creates an output command and its handler. output_base is a template of the command without any conditional arguments (for simple commands this is the full template). args is a list of argument symbols to determine how the event is built and handled. If an argument symbol is followed by a string, that string is conditionally appended to the output in the handler if the event has data for that argument.

I hate the hackiness here, but it’s so much easier to build the commands and handlers with an ugly one-liner than manually, and things like define_method seem to fall short with how much crap this needs to do.

# File lib/net/yail/output_api.rb, line 60
def create_command(command, output_base, *opts)
  event_opts = lambda {|text| text.gsub(%r:(\w+)/, '#{event.\1}') }

  output_base =

  # Create a list of actual arg symbols and templates for optional args
  args = []
  optional_arg_templates = {}
  last_symbol = nil
  for opt in opts
    case opt
    when Symbol
      args.push opt
      last_symbol = opt
    when String
      raise"create_command optional argument must have an argument symbol preceding them") unless last_symbol
      optional_arg_templates[last_symbol] =
      last_symbol = nil

  # Format strings for command args and event creation
  event_string = args.collect {|arg| ":#{arg} => #{arg}"}.join(",")
  event_string = ", #{event_string}" unless event_string.empty?
  args_string = args.collect {|arg| "#{arg} = ''"}.join(",")

  # Create the command function
  command_code = %Q
    def #{command}(#{args_string})
      dispatch => #{command.inspect}#{event_string})
  self.class.class_eval command_code

  # Create the handler piece by piece - wow how ugly this is!
  command_handler = :"magic_out_#{command}"
  handler_code = %Q
    def #{command_handler}(event)
      output_string = "#{output_base}"
  for arg in args
    if optional_arg_templates[arg]
      handler_code += %Q
        output_string += "#{optional_arg_templates[arg]}" unless event.#{arg}.to_s.empty?
  handler_code += %Q
      raw output_string

  self.class.class_eval handler_code

  # At least setting the callback isn't a giant pile of dumb
  set_callback :"outgoing_#{command}", self.method(command_handler)
ctcp(target, message)

Buffers an :outgoing_ctcp event. Target is user or channel, message is message.

# File lib/net/yail/output_api.rb, line 33
def ctcp(target, message)
  buffer_output => :ctcp, :target => target, :message => message)
msg(target, message)

Buffers an :outgoing_msg event. Could be used to send any privmsg, but you’re betting off using act and ctcp shortcut methods for those types. Target is a channel or username, message is the message.

# File lib/net/yail/output_api.rb, line 28
def msg(target, message)
  buffer_output => :msg, :target => target, :message => message)

Spits a raw string out to the server - in case a subclass wants to do something special on all output, please make all output go through this method. Don’t use puts manually. I will kill violaters. Legally speaking, that is.

# File lib/net/yail/output_api.rb, line 11
def raw(line)
  @socket.puts "#{line}\r\n"
whois(nick, server = nil)

WHOIS is tricky - it can optionally take a :target parameter, which is the first parameter if it’s present, rather than added to the parameter list. BAD SPECIFICATIONS! NO BISCUIT! (If it were more standard, we could just use #create_command)

Note that “nick” can actually be a comma-separated list of masks for whois querying.

# File lib/net/yail/output_api.rb, line 47
def whois(nick, server = nil)
  dispatch => :whois, :nick => nick, :server => server)