Rack

57
Rack

description

By Meng Yan

Transcript of Rack

Page 1: Rack

Rack

Page 2: Rack

孟 岩

Page 3: Rack

Elan Meng

Page 4: Rack

Caibangzi.com

Page 5: Rack

IN-SRC Studio

Page 6: Rack

http://www.mengyan.org/blog/@dreamwords

Page 8: Rack

Thanks !!

Page 9: Rack

Rack Sales?

Page 10: Rack
Page 11: Rack

Overview

• Why Rack

• What’s Rack

• Rack Middleware

• Rails on Rack

• Example

• Q & A

Page 12: Rack

Problems

• Ruby is popular

• Different web servers (app servers)

• Different web frameworks

• each framework has to write it’s own handlers to different web servers

• Not only the handler

Page 13: Rack

We hate duplication!

Page 14: Rack

How?

Page 15: Rack

AbstractionInterface

Page 16: Rack

make the simplest possible API that

represents a generic web application

Page 17: Rack

Request -> Response

Page 18: Rack

Request• CGI Envrionment

• {"HTTP_USER_AGENT"=>"curl/7.12.2 ..." "REMOTE_HOST"=>"127.0.0.1", "PATH_INFO"=>"/", "HTTP_HOST"=>"ruby-lang.org", "SERVER_PROTOCOL"=>"HTTP/1.1", "SCRIPT_NAME"=>"", "REQUEST_PATH"=>"/", "REMOTE_ADDR"=>"127.0.0.1", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"http://ruby-lang.org/", "SERVER_PORT"=>"80", "HTTP_PRAGMA"=>"no-cache", "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_ACCEPT"=>"*/*", "REQUEST_METHOD"=>"GET"}

Page 19: Rack

ResponseHTTP/1.1 302

Found Date: Sat, 27 Oct 2007 10:07:53 GMT Server: Apache/2.0.54 (Debian GNU/Linux)mod_ssl/2.0.54 OpenSSL/0.9.7e Location: http://www.ruby-lang.org/ Content-Length: 209 Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <ahref="http://www.ruby-lang.org/">here</a>.</p> </body></html>

Page 20: Rack

What’s Rack• Duck-Type

• Ruby object that respond_to? :call

• One argument, the environment variable

• return values

• status - respond_to? :to_i

• headers - respond_to? :each, yield key/value

• body - respond_to? :each, yield string

Page 21: Rack

lambda { |env| [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => '16'}, ["Beijing on Rails"] ]}

Page 22: Rack

app = lambda { |env| [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => ’16’}, ["Beijing on Rails"] ]}

run app

Page 23: Rack

rackup config.ru

Page 24: Rack

curl http://localhost:9292/

Page 25: Rack

Beijing on Rails

Page 26: Rack

%w(rubygems rack).each { |dep| require dep } Rack::Handler::Mongrel.run(app, :Port => 3000)

Page 27: Rack

Rack Middleware

HTTPFramework

APP

Page 28: Rack

Rack Middleware

HTTPFramework

APP

Rack

Page 29: Rack

module Rack class BeijingOnRails def initialize(app) @app = app end

def call(env)... ...status, headers body = @app.call(env)... ...

[status, header, body] end endend

Page 30: Rack

app = Rack::CommonLogger.new( Rack::ShowExceptions.new(

Rack::ShowStatus.new( Rack::Lint.new(app))))

Page 31: Rack

Rack Middleware

HTTPFramework

APP

Middleware

Page 32: Rack

Rack Middleware

• Chain of Responsibilities

app = Rack::CommonLogger.new( Rack::ShowExceptions.new(

Rack::ShowStatus.new( Rack::Lint.new(app))))

Page 33: Rack

Rack Distribution

• Specification

• Handlers

• Adapters

• Middlewares

• Utilities

Page 34: Rack

Rack - Specification

• Rack::Lint

specify "notices status errors" do lambda { Rack::Lint.new(lambda { |env| ["cc", {}, ""] }).call(env({})) }.should.raise(Rack::Lint::LintError). message.should.match(/must be >=100 seen as integer/)

lambda { Rack::Lint.new(lambda { |env| [42, {}, ""] }).call(env({})) }.should.raise(Rack::Lint::LintError). message.should.match(/must be >=100 seen as integer/) end

Page 35: Rack

Rack - Handlers

• CGI

• FastCGI

• Mongrel

• WEBrick

• Thin

• Passenger

• Unicorn

Page 36: Rack

Rack - Adapters

• Camping

• Merb

• Rails

• Sinatra

• ......

Page 37: Rack

Rack - Middleware

• Rack::Static & Rack::File

• Rack::CommonLogger

• Rack::Reloader

• Rack::ShowExceptions

Page 38: Rack

Rack - Utilities

• Rackup

• a useful tool for running Rack applications

• Rackup::Builder

• DSL to configure middleware and build up applications easily

Page 39: Rack

app = Rack::Builder.new do

use Rack::CommonLogger use Rack::ShowExceptions use Rack::ShowStatususe Rack::Lintrun MyRackApp.new

end

Rack::Handler::Mongrel.run app, :Port => 8080

Page 40: Rack

Rails on Rack

Page 41: Rack

The most important change in Rails over the past year - its move to

become Rack-- Ben Scofield

Page 42: Rack

Rails on Rack

• first commit - Ezra & Josh on June 2008

Page 43: Rack

Rails on Rack

• Merb & Rails merge

• ActionController::Dispatcher.new

• ActionController::MiddlewareStack

• ActionController -> Rack Middleware

• ActionDispatch::Failsafe

• ActionDispatch::ShowExceptions

• Plugin -> Rack Middleware

• Hoptoad_notifier plugin -> Rack::Hoptoad.

Page 44: Rack

app = Rack::Builder.new { use Rails::Rack::LogTailer unless options[:detach] use Rails::Rack::Debugger if options[:debugger]

map "/" do use Rails::Rack::Static run ActionController::Dispatcher.new end}.to_app

Page 45: Rack

# RAILS_ROOT/config.rurequire "config/environment"

use Rails::Rack::LogTaileruse Rails::Rack::Staticrun ActionController::Dispatcher.new

rackup

Page 46: Rack

Metal

• bypass some of the normal overhead of the Rails stack

• specify certain routes and code to execute when those routes are hit.

• avoid the entirety of ActionController

• Rails::Rack::Metal

• ActionController::MiddlewareStack

Page 47: Rack

$ script/generate metal poller

class Poller def self.call(env) if env["PATH_INFO"] =~ /^\/poller/ [200, {"Content-Type" => "text/html"}, ["Hello, World!"]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end endend

Page 48: Rack

def call(env) @metals.keys.each do |app| result = app.call(env) return result unless result[0].to_i == 404 end @app.call(env)end

Rack::Metal

Page 49: Rack

Response Timer

Page 50: Rack

module Rack class Runtime def initialize(app, name = nil) @app = app @header_name = "X-Runtime" @header_name << "-#{name}" if name end

def call(env) start_time = Time.now status, headers, body = @app.call(env) request_time = Time.now - start_time

if !headers.has_key?(@header_name) headers[@header_name] = "%0.6f" % request_time end

[status, headers, body] end endend

Page 52: Rack

CodeRack

• http://coderack.org/

• a competition to develop most useful and top quality Rack middlewares.

• 1 DAY LEFT

Page 53: Rack

WRAP UP

Page 54: Rack

Rack is a beautiful thing- Ryan Bates

Page 55: Rack

References

• Introducing Rack - Christian Neukirchen

• http://rack.rubyforge.org/

• RailsCasts 151: Rack Middleware

• http://heroku.com/how/architecture

Page 56: Rack

Q & A

• Rack

• Ruby on Rails

• Caibangzi.com

• Mutual Fund & Investment

Page 57: Rack

Why not simply string

• Ruby 1.8

• String was a collection of bytes

• String’s :each method iterated over lines of data

• Ruby 1.9

• String is now a collection of encoded data. (Raw bytes and encoding information)

• :each has been removed from String and it’s no longer Enumerable