8 minutes on rack

35
8 minutes on Rack Dan Webb ([email protected] )

Upload: danwrong

Post on 26-Jan-2015

24.553 views

Category:

Technology


3 download

DESCRIPTION

From Ruby Manor 2008

TRANSCRIPT

Page 2: 8 Minutes On Rack

Web Framework

Page 3: 8 Minutes On Rack

Web Server

Page 4: 8 Minutes On Rack

Library

Page 5: 8 Minutes On Rack

A Convention

Page 6: 8 Minutes On Rack

If you have a Ruby object...

Page 7: 8 Minutes On Rack

that has a call method which takes one argument...

app.call(env)

Page 8: 8 Minutes On Rack

and that method returns an array with 3 elements...

[200, { 'Content-Type' => 'text/plain' }, 'Hello World!']

Page 9: 8 Minutes On Rack

then you can connect it to any web server that supports Rack

require 'thin'Rack::Handler::Thin.run(app, :Port => 4000)

Page 10: 8 Minutes On Rack

and you've got yourself a web application

Page 11: 8 Minutes On Rack

Fin

Page 12: 8 Minutes On Rack

app = Proc.new do |env| [200, { 'Content-Type' => 'text/plain' }, 'Hello World!']end

require 'rubygems'require 'thin'Rack::Handler::Thin.run(app, :Port => 4000)

Page 13: 8 Minutes On Rack

class HelloWorld def initialize(name) @name = name end def call(env) [200, { 'Content-Type' => 'text/plain' }, "Hello #{@name}!"] endend

require 'rubygems'require 'rack'Rack::Handler::Mongrel.run(HelloWorld.new("Dan"), :Port => 4000)

Page 14: 8 Minutes On Rack

// Courtesy of Pratik Naik! #include "ruby.h" VALUE method_call(VALUE self, VALUE env) { VALUE response = rb_ary_new(); VALUE headers = rb_hash_new(); rb_hash_aset(headers, rb_str_new2("Content-Type"), rb_str_new2("text/plain")); rb_ary_push(response, INT2NUM(200)); rb_ary_push(response, headers); rb_ary_push(response, rb_str_new2("Hello World!")); return response;} void Init_rock() { VALUE Rock = rb_define_class("Rock", rb_cObject); rb_define_method(Rock, "call", method_call, 1);}

// run.rbrequire 'rock'require 'thin'Rack::Handler::Thin.run Rock.new, :Port => 4000

Page 15: 8 Minutes On Rack

def call(env)

Page 16: 8 Minutes On Rack

{ "SERVER_NAME"=>"localhost", "HTTP_ACCEPT_ENCODING"=>"gzip,deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en- GB; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4", "PATH_INFO"=>"/", "SCRIPT_NAME"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "HTTP_ACCEPT_LANGUAGE"=>"en-gb,en;q=0.5", "HTTP_HOST"=>"localhost:4000", "REMOTE_ADDR"=>"127.0.0.1", "HTTP_KEEP_ALIVE"=>"300", "REQUEST_PATH"=>"/", "SERVER_SOFTWARE"=>"thin 0.8.2 codename Double Margarita", "HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.7", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"/", "SERVER_PORT"=>"4000", "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.2", "HTTP_ACCEPT"=>"text/html,application/xhtml+xml,application/xml;q=0.9, */*;q=0.8", "HTTP_CONNECTION"=>"keep-alive", "REQUEST_METHOD"=>"GET"}

Page 17: 8 Minutes On Rack

[200, { 'Content-Type' => 'text/plain' }, "Hello #{@name}!"]

Status Code

Page 18: 8 Minutes On Rack

[200, { 'Content-Type' => 'text/plain' }, "Hello #{@name}!"]

HTTP Headers

Page 19: 8 Minutes On Rack

[200, { 'Content-Type' => 'text/plain' }, "Hello #{@name}!"]

Response Body

Page 20: 8 Minutes On Rack

Response body can be any object that respond_to?(:each)

file = File.new('myfile.xml')[200, { 'Content-Type' => 'application/xml' }, file]

Page 21: 8 Minutes On Rack

class StreamingFile def initialize(file) @file = file end def length File.size(@file) end def last_modified File.mtime(@file).rfc822 end def each File.open(@file, "rb") do |file| while part = file.read(8192) yield part end File.delete(@file) end end

Page 22: 8 Minutes On Rack

[200, { 'Content-Type' => 'audio/mp3', 'Content-Length' => file.length.to_s }, file]

Page 23: 8 Minutes On Rack

Duck typing!

• Streaming• Clean up after response sent• Complex responses• Loads more...

Page 24: 8 Minutes On Rack

Why?

Page 25: 8 Minutes On Rack

Common interface

Page 26: 8 Minutes On Rack

• Passenger• Mongrel• CGI• SCGI• FastCGI• Thin• Ebb• Fuzed• Webrick• Litespeed

Page 27: 8 Minutes On Rack

Write once, serve however...

Page 28: 8 Minutes On Rack

Convienient way to write

micro apps

Page 29: 8 Minutes On Rack

Example: Development

Server

Page 30: 8 Minutes On Rack
Page 31: 8 Minutes On Rack

class StaticOrRedirect def initialize(options={}) @redirect_base = options[:redirect_base] root = options[:root] || Dir.pwd @file_server = Rack::File.new(root) end

def call(env) path = env["PATH_INFO"] resp = @file_server.call(env) if resp.first == 404 [302, { 'Content-Type' => 'text/plain', 'Location' => "#{@redirect_base}#{env['PATH_INFO']}" }, 'Not here!'] else resp end endend

Rack::Handler::Thin.run( StaticOrRedirect.new( :redirect_base => 'http://bbc.co.uk' ))

Page 32: 8 Minutes On Rack

There's more...

• The Rack Gem• Middleware• Rack and Passenger• rackup

Page 33: 8 Minutes On Rack

rack.rubyforge.org

Page 34: 8 Minutes On Rack

danwebb.net

Page 35: 8 Minutes On Rack

Questions?