Sinatra allows the return values of route blocks to take many different forms.
How does Sinatra know how to extract status
, headers
, and body
from each type of return value?
Particularly, I'm looking for the source code (logic) that does this, because I'd like to do something similar.
The code you’re looking for is in the invoke
method:
def invoke
res = catch(:halt) { yield }
res = [res] if Fixnum === res or String === res
if Array === res and Fixnum === res.first
res = res.dup
status(res.shift)
body(res.pop)
headers(*res)
elsif res.respond_to? :each
body res
end
nil # avoid double setting the same response tuple twice
end
There are a couple of quirks to look out for. For example if you return a hash Sinatra will see that it responds to each and treat it as the body, but since it doesn’t yield strings this can cause an error or unexpected results when the webserver tries to send the content. Also the rack spec says this about the status: “When parsed as integer (to_i), it must be greater than or equal to 100” and so you should be able to pass a string like "200"
that will be converted with to_i
, but Sinatra only looks for Fixnums, which goes against its claim of “You can return any object that would either be a valid Rack response”.