How to Flush HTML to The Wire in Sinatra

Is there a way to flush html to the wire in Sinatra

Update (2012-03-21)

As of Sinatra 1.3.0, you can use the new streaming API:

get '/' do
stream do |out|
out << "foo\n"
sleep 10
out << "bar\n"
end
end

Old Answer

Unfortunately you don't have a stream you can simply flush to (that would not work with Rack middleware). The result returned from a route block can simply respond to each. The Rack handler will then call each with a block and in that block flush the given part of the body to the client.

All rack responses have to always respond to each and always hand strings to the given block. Sinatra takes care of this for you, if you just return a string.

A simple streaming example would be:

require 'sinatra'

get '/' do
result = ["this", " takes", " some", " time"]
class << result
def each
super do |str|
yield str
sleep 0.3
end
end
end
result
end

Now you could simply place all your crawling in the each method:

require 'sinatra'

class Crawler
def initialize(url)
@url = url
end

def each
yield "opening url\n"
result = open @url
yield "seaching for foo\n"
if result.include? "foo"
yield "found it\n"
else
yield "not there, sorry\n"
end
end
end

get '/' do
Crawler.new 'http://mysite'
end

Streaming data from Sinatra/Rack application

Neither Webrick nor Thin support streaming that way. You could try Mongrel or Unicorn. If you want to use Thin or Rainbows!, you have to hook into the event loop in order to achieve streaming:

require 'sinatra'

class Stream
include EventMachine::Deferrable
def initialize
@counter = 0
end

def each(&block)
if @counter > 10
succeed
else
EM.next_tick do
yield counter
each(&block)
end
end
end
end

get '/' do
Stream.new
end

I recently wrote a EventSource implementation that way:

require 'sinatra'

class EventStream
include EventMachine::Deferrable
def each
count = 0
timer = EventMachine::PeriodicTimer.new(1) do
yield "data: #{count += 1}\n\n"
end
errback { timer.cancel }
end
end

get '/' do
EventMachine.next_tick do
request.env['async.callback'].call [
200, {'Content-Type' => 'text/event-stream'},
EventStream.new ]
end
[-1, {}, []]
end

If you want to use Webrick for Streaming: here is a patch.

Is there a way to retain an HTTP GET parameter in Sinatra without manually writing them in the links?

You could define a new HAML helper (like in that repository) and use it in your template like any other helpers. I think it is the most convenient way to achieve that.

Get absolute (base) url in sinatra

A couple things.

  1. set is a class level method, which means you are modifying the whole app's state with each request
  2. The above is a problem because potentially, the base url could be different on different requests eg http://foo.com and https://foo.com or if you have multiple domains pointed at the same app server using DNS

A better tactic might be to define a helper

helpers do
def base_url
@base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
end
end

If you need the base url outside of responding to queries(not in a get/post/put/delete block or a view), it would be better to set it manually somewhere.

Slim with embedded Ruby

A tag followed by text will output that text as the tag's contents. You can use string interpolation #{expression} inside the text to output variables.

Content text with a variable interpolated:

title #{yield(:title)} | Ruby on Rails Tutorial Sample App

You can also set the tag's contents to a ruby expression by using tag =.

title = yield(:title) + " | Ruby on Rails Tutorial Sample App"

Note that in this case this won't work if yield(:title) returns nil

When you have nested tags, you should put them on seperate lines.

Algorithm for finding the smallest power of two that's greater or equal to a given value

Here's my favorite. Other than the initial check for whether it's invalid (<0, which you could skip if you knew you'd only have >=0 numbers passed in), it has no loops or conditionals, and thus will outperform most other methods. This is similar to erickson's answer, but I think that my decrementing x at the beginning and adding 1 at the end is a little less awkward than his answer (and also avoids the conditional at the end).

/// Round up to next higher power of 2 (return x if it's already a power
/// of 2).
inline int
pow2roundup (int x)
{
if (x < 0)
return 0;
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x+1;
}


Related Topics



Leave a reply



Submit