At the lowest level, starting a shell is a matter of sending a "shell" request over a channel.

{{{lang=ruby,caption=Sending a shell request,number=true
Net::SSH.start( host ) do |session|

  session.open_channel do |channel|

    channel.on_success do
      puts "shell was started successfully!"
      channel.send_data "exit\n" # tell the shell to exit
    end
    channel.on_failure do
      puts "shell could not be started!"
    end
    channel.on_data do |ch,data|
      puts "recieved #{data} from shell"
    end
    channel.on_close do
      puts "shell terminated"
    end

    channel.send_request "shell", nil, true

  end

  session.loop

end
}}}

The @#send_request@ method accepts three parameters--the name of the request (in this case, "shell"), any additional data to send with the request (none, in this case), and whether or not you want the server to reply with the success or failure of the request. In general, it is a good idea to ask for the server to reply, so that you know when you can start sending data to the shell.

If you want to open a pty before starting the shell, you can use the #request_pty method of the channel:

{{{lang=ruby,number=true,caption=Opening a pty on a channel
Net::SSH.start( host ) do |session|

  session.open_channel do |channel|

    channel.on_success do
      puts "pty was requested successfully!"

      channel.on_success do
        puts "shell was started successfully!"
        channel.send_data "exit\n" # tell the shell to exit
      end

      channel.send_request "shell", nil, true
    end

    channel.on_failure do
      puts "shell could not be started!"
    end
    channel.on_data do |ch,data|
      puts "recieved #{data} from shell"
    end
    channel.on_close do
      puts "shell terminated"
    end

    channel.request_pty :want_reply => true

  end

  session.loop

end
}}}

First, the pty is requested (with an indicator to the server that it should return a "success" or "failure" notification). When the pty is successfully opened, the "on_success" callback is changed, and the shell is then requested.

It's a lot of hoops to jump through, but it gives you the finest-grained control over opening a shell. For most things, though, you can live with less control. For those tasks, there are the _shell_ and _sync_ services.