Rack is "env variable goes in, array of [code, headers, body] comes out, here are some handy utils for handling grunt work". That's it. That's Rack. You can do whatever you please with it in the middle. That's all that a middleware is, and Rails itself is basically just a collection of Rack middlewares (procs) with some support libraries stapled on. That's a gross simplification, but at the end of the day, that's basically the heart and soul of the framework.
My point is that there are multiple levels of abstraction. Of course you don't have to re-write and re-implement boilerplate when you use Sinatra over Rack, just like you don't have to re-write and re-implement when you use Rails over Sinatra. "Rails bad, Sinatra good" is just silly, because it all boils down to what kind of tradeoff you're willing to make between what's done in framework versus what's done in your application.
https://gist.github.com/3719513
Did I miss something?
Rack is "env variable goes in, array of [code, headers, body] comes out, here are some handy utils for handling grunt work". That's it. That's Rack. You can do whatever you please with it in the middle. That's all that a middleware is, and Rails itself is basically just a collection of Rack middlewares (procs) with some support libraries stapled on. That's a gross simplification, but at the end of the day, that's basically the heart and soul of the framework.
My point is that there are multiple levels of abstraction. Of course you don't have to re-write and re-implement boilerplate when you use Sinatra over Rack, just like you don't have to re-write and re-implement when you use Rails over Sinatra. "Rails bad, Sinatra good" is just silly, because it all boils down to what kind of tradeoff you're willing to make between what's done in framework versus what's done in your application.