Code Snippets

Put your interesting code snippets here. Please include a description of what is special about said snippet.

You can add code highlighting as follows:

{{{
#!ruby
def hello_world
  puts "hi"
end
}}}

results in

def hello_world
  puts "hi"
end

Non-snippet Snippets

Feel free to turn code found here into additional snippets

http://rubyeventmachine.com/browser/version_0

Small client Example

    class Echo < EventMachine::Connection
     def initialize(*args)
      super
      # stuff here...
     end
     
     def receive_data(data)
      p data
     end
    end
    EventMachine::run {
     EventMachine::connect '127.0.0.1', 8081, Echo
    }

Small server Example

require 'eventmachine'

 module EchoServer
   def post_init
     puts "-- someone connected to the echo server!"
   end

   def receive_data data
     send_data ">>>you sent: #{data}"
   end

 end

 EventMachine::run {
   EventMachine::start_server "127.0.0.1", 8081, EchoServer
   puts 'running echo server on 8081'
 }

EventMachine, Telnet Style

EventMachine (EM) can respond to keyboard events. This gives your event-driven programs the ability to respond to input from local users.

Programming EM to handle keyboard input in Ruby is simplicity itself. Just use EventMachine#open_keyboard, and supply the name of a Ruby module or class that will receive the input:

 require 'rubygems'
 require 'eventmachine'
 
 module MyKeyboardHandler
        def receive_data keystrokes
                puts "I received the following data from the keyboard: #{keystrokes}"
        end
 end
 
 EM.run {
        EM.open_keyboard(MyKeyboardHandler)
 }

If you want EM to send line-buffered keyboard input to your program, just include the LineText?2 protocol module in your handler class or module:

 require 'rubygems'
 require 'eventmachine'
 
 module MyKeyboardHandler
        include EM::Protocols::LineText2
        def receive_line data
                puts "I received the following line from the keyboard: #{data}"
        end
 end
 
 EM.run {
        EM.open_keyboard(MyKeyboardHandler)
 }

As we said, simplicity itself. You can call EventMachine#open_keyboard at any time while the EM reactor loop is running. In other words, the method invocation may appear anywhere in an EventMachine#run block, or in any code invoked in the #run block.

Safe run in any circumstances

N.B. this is no longer required for a lot of apps, as of EM 0.12 you can now stack run blocks, i.e. EM::run{ EM::run {} } does not raise. For threaded apps there may still be some requirement, however a good pattern for managable code is to push the call to #run to the top of your application stack, and do your threaded work using EM::defer where possible.

module EventMachine
  def EventMachine::safe_run(background = nil, &block)
    if EM::reactor_running?
      # Attention: here we loose the ability to catch 
      # immediate connection errors.
      EM::next_tick(&block)
      sleep unless background # this blocks the thread as it was inside a reactor
    else
      if background
        $em_reactor_thread = Thread.new do
          EM::run(&block)
        end
      else
        EM::run(&block)
      end
    end
  end
end

Usage:

EM::safe_run(:background) do 
  EM::start_server(host, port, server_klass)
  EM::connect(host, port, client_klass)
end

Use this snippet if you'd like to design your library in a way compatible with different apps: both event-driven and threaded.

Writing out to clients before Exit

Let connections finish their work before stopping EM for good.

class Server
  attr_accessor :connections
  
  def initialize
    @connections = []
    # ...
  end
  
  def start
    @signature = EventMachine.start_server('0.0.0.0', 3000, Connection) do |con|
      con.server = self
    end
  end
  
  def stop
    EventMachine.stop_server(@signature)
    
    unless wait_for_connections_and_stop
      # Still some connections running, schedule a check later
      EventMachine.add_periodic_timer(1) { wait_for_connections_and_stop }
    end
  end

  def wait_for_connections_and_stop
    if @connections.empty?
      EventMachine.stop
      true
    else
      puts "Waiting for #{@connections.size} connection(s) to finish ..."
      false
    end
  end
end

class Connection < EventMachine::Connection
  attr_accessor :server
  
  # ...
  
  def unbind
    server.connections.delete(self)
  end
end

EventMachine::run {
  s = Server.new
  s.start
  puts "New server listening"
}



Start a server on an unassigned port

require ‘socket’
 
EM.run {
  srvr = EM.start_server “0.0.0.0”, 0
  p Socket.unpack_sockaddr_in( EM.get_sockname( srvr ))
}

determine client's port

    port, *ip_parts = get_peername[2,6].unpack "nC4"
    ip = ip_parts.join('.')

or

    require 'socket'
    port, ip = Socket.unpack_sockaddr_in(get_peername)

More complicated example

    class Echo < EventMachine::Connection
     def initialize(*args)
      super
      # stuff here...
     end
     
     def receive_data(data)
      p data
      send_data data
      close_connection_after_writing 
     end

     def unbind
       p ' connection totally closed'
     end
    end
    EventMachine::connect '127.0.0.1', 22, Echo {|conn| }

EventMachine over a Serial Port

It is actually possible to use Guilliame Perionnet's ruby-serialport library with (the pure Ruby) EventMachine. The following code works with EventMachine 0.12.2 and ruby-serialport 0.7.0:

  $eventmachine_library = :pure_ruby # need to force pure ruby
  require 'eventmachine'
  gem_original_require 'serialport'
  require 'smsrelay/gsmpdu'

  module EventMachine
    class EvmaSerialPort < StreamObject
      def self.open(dev, baud, databits, stopbits, parity)
        io = SerialPort.new(dev, baud, databits, stopbits, parity)
        return(EvmaSerialPort.new(io))
      end

      def initialize(io)
        super
      end

      ##
      # Monkeypatched version of EventMachine::StreamObject#eventable_read so
      # that EOFErrors from the SerialPort object (which the ruby-serialport
      # library uses to signal the fact that there is no more data available
      # for reading) do not cause the connection to unbind.
      def eventable_read
        @last_activity = Reactor.instance.current_loop_time
        begin
          if io.respond_to?(:read_nonblock)
            10.times {
              data = io.read_nonblock(4096)
              EventMachine::event_callback uuid, ConnectionData, data
            }
          else
            data = io.sysread(4096)
            EventMachine::event_callback uuid, ConnectionData, data
          end
        rescue Errno::EAGAIN, Errno::EWOULDBLOCK, EOFError
          # no-op
        rescue Errno::ECONNRESET, Errno::ECONNREFUSED
          @close_scheduled = true
          EventMachine::event_callback uuid, ConnectionUnbound, nil
        end

      end

    end

    class << self
      def connect_serial(dev, baud, databits, stopbits, parity)
        EvmaSerialPort.open(dev, baud, databits, stopbits, parity).uuid
      end
    end

    def EventMachine::open_serial(dev, baud, databits, stopbits, parity,
                                  handler=nil)
      klass = if (handler and handler.is_a?(Class))
                handler
              else
                Class.new( Connection ) {handler and include handler}
              end
      s = connect_serial(dev, baud, databits, stopbits, parity)
      c = klass.new s
      @conns[s] = c
      block_given? and yield c
      c
    end

    class Connection
      # This seems to be necessary with EventMachine 0.12.x
      def associate_callback_target(sig)
        return(nil)
      end
    end
  end

Using EventMachine with GTK+

GTK+ applications generally make use of a blocking event loop ( gtk_main / Gtk::main ) to do their work, which interacts poorly with EventMachine. The way around it seems to be to explicitly "give it a tick", like so:

require 'gtk2'
require 'eventmachine'
class MyApp

  def initialize
    EM::connect ...
  end
end

EM::run do
  client = MyApp.new
  give_tick = proc { Gtk::main_iteration; EM.next_tick(give_tick); }
  give_tick.call
end

This avoids the blocking event loop (which stops EM from working) by running one iteration of its main loop every tick of EventMachine. This ensures GTK events are processed in a timely fashion without blocking EM from doing its work.

There might be some way to use gtk_idle_add() to run EM inside GTK's event loop - but I've not had any success with that.