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.
set
is a class level method, which means you are modifying the whole app's state with each request- The above is a problem because potentially, the base url could be different on different requests eg
http://foo.com
andhttps://foo.com
or if you have multiple domains pointed at the same app server using DNS
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
Rails Routes: Nested, Member, Collection, Namespace, Scope and Customizable
How to Use Strong Parameters with an Objects Array in Rails
Devise with Ruby on Rails - Force User to Change Password on First Login
Can't Log into Active Admin. Any Way to Create an Admin User
Is It Still Advisable to Test Routes in Rails 4 with Minitest
How to Parse Days/Hours/Minutes/Seconds in Ruby
How to Downgrade My Rails Version
Posting Ruby Data in JSON Format with Net/Http
Explanation of Ruby Code for Building Trie Data Structures
Robust Way to Deploy a Rack Application (Sinatra)
Good Forms Helpers for Sinatra
How to Convert a Fraction to Float in Ruby
Inspect or Clean Up The Working Tree Error When Installing Ruby 2.1.3 on MAC Os X 10.9.5