Otto - 1.0 (2024-04-05)
Auto-define your rack-apps in plain-text.
Overview
Apps built with Otto have three, basic parts: a rackup file, a ruby file, and a routes file. If you've built a Rack app before, then you've seen a rackup file before. The ruby file is your actual app and the routes file is what Otto uses to map URI paths to a Ruby class and method.
A barebones app directory looks something like this:
$ cd myapp
$ ls
config.ru app.rb routes
See the examples/ directory for a working app.
Routes
The routes file is just a plain-text file which defines the end points of your application. Each route has three parts:
- HTTP verb (GET, POST, PUT, DELETE or HEAD)
- URI path
- Ruby class and method to call
Here is an example:
GET / App#index
POST / App#receive_feedback
GET /redirect App#redirect
GET /robots.txt App#robots_text
GET /product/:prodid App#display_product
# You can also define these handlers when no
# route can be found or there's a server error. (optional)
GET /404 App#not_found
GET /500 App#server_error
App
There is nothing special about the Ruby class. The only requirement is that the first two arguments to initialize be a Rack::Request object and a Rack::Response object. Otherwise, you can do anything you want. You're free to use any templating engine, any database mapper, etc. There is no magic.
class App
attr_reader :req, :res
# Otto creates an instance of this class for every request
# and passess the Rack::Request and Rack::Response objects.
def initialize req, res
@req, @res = req, res
end
def index
res.header['Content-Type'] = "text/html; charset=utf-8"
lines = [
'<img src="/img/otto.jpg" /><br/><br/>',
'Send feedback:<br/>',
'<form method="post"><input name="msg" /><input type="submit" /></form>',
'<a href="/product/100">A product example</a>'
]
res.body = lines.join($/)
end
def receive_feedback
res.body = req.params.inspect
end
def redirect
res.redirect '/robots.txt'
end
def robots_text
res.header['Content-Type'] = "text/plain"
rules = 'User-agent: *', 'Disallow: /private'
res.body = rules.join($/)
end
def display_product
res.header['Content-Type'] = "application/json; charset=utf-8"
prodid = req.params[:prodid]
res.body = '{"product":%s,"msg":"Hint: try another value"}' % [prodid]
end
def not_found
res.status = 404
res.body = "Item not found!"
end
def server_error
res.status = 500
res.body = "There was a server error!"
end
end
Rackup
There is also nothing special about the rackup file. It just builds a Rack app using your routes file.
require 'otto'
require 'app'
app = Otto.new("./routes")
map('/') {
run app
}
See the examples/ directory for a working app.
Installation
Get it in one of the following ways:
$ gem install otto
[ Add it to yer Gemfile]
$ bundle install
$ git clone git://github.com/delano/otto.git
You can also download via tarball or zip.
More Information
In the wild
Services that use Otto:
- Onetime Secret -- A safe way to share sensitive data.
License
See LICENSE.txt