Building web framework with Rack
-
Upload
sickill -
Category
Technology
-
view
3.986 -
download
8
description
Transcript of Building web framework with Rack
![Page 1: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/1.jpg)
Building web frameworkwith Rack
Marcin Kulik
EuRuKo, 2010/05/30
![Page 2: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/2.jpg)
I am:Senior developer @ Lunar Logic Polska -agile Ruby on Rails development services
Working with web for 10 years
Using Ruby, Python, Java and others - inlove with Ruby since 2006
![Page 3: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/3.jpg)
Open Source contributor:CodeRack.org - Rack middlewarerepository
Open File Fast - Netbeans and JEditplugin
racksh - console for Rack apps
and many more (checkgithub.com/sickill)
![Page 4: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/4.jpg)
Why would you needanother framework?
"Because world needs yet another framework ;-)" - Tomash
![Page 5: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/5.jpg)
No, you probably don't needit actually :)
![Page 6: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/6.jpg)
Several mature frameworks
Tens of custom/experimental ones
"Don't reinvent the wheel", right?
But...
![Page 7: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/7.jpg)
But it's so easy that youshould at least try
![Page 8: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/8.jpg)
Rack provides everything you'll need, isextremely simple but extremelypowerful
It will help you to better understandHTTP
It will make you better developer
Your custom framework will be thefastest one *
It's fun! A lot of fun :)
![Page 9: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/9.jpg)
What is Rack?
![Page 10: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/10.jpg)
Ruby web applications interface
library
![Page 11: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/11.jpg)
Simplest Rack applicationrun lambda do |env| [200, { "Content-type" => "text/plain" }, ["Hello"]]end
![Page 12: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/12.jpg)
Simplest Rack middlewareclass EurukoMiddleware def initialize(app) @app = app end def call(env) env['euruko'] = 2010 @app.call endend
![Page 13: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/13.jpg)
Let's transform it intoframework!
![Page 14: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/14.jpg)
How does typical webframework look like?
![Page 15: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/15.jpg)
Rails
Merb
Pylons
Django
Rango
![Page 16: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/16.jpg)
Looks like MVC, more or less
![Page 17: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/17.jpg)
What features we'd like tohave?
![Page 18: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/18.jpg)
dependencies management
RESTful routing
controllers (session, flash messages)
views (layouts, templates, partials)
ORM
authentication
testing
console
![Page 19: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/19.jpg)
Available Rack middlewareand tools we can use
![Page 20: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/20.jpg)
(1/8) Gem dependencymanagement
![Page 22: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/22.jpg)
# Gemfilesource "http://gemcutter.org"gem "rack"# config.rurequire "bundler"Bundler.setupBundler.require
![Page 23: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/23.jpg)
(2/8) Routing
![Page 24: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/24.jpg)
Usher"Pure ruby general purpose router with interfaces for rails, rack,
email or choose your own adventure"
github.com/joshbuddy/usher
![Page 25: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/25.jpg)
# Gemfilegem "usher"# config.rurequire APP_ROOT / "config" / "router.rb"run Foobar::Router
![Page 26: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/26.jpg)
# config/router.rbmodule Foobar Router = Usher::Interface.for(:rack) do get('/').to(HomeController.action(:welcome)).name(:root) # root URL add('/login').to(SessionController.action(:login)).name(:login) # login get('/logout').to(SessionController.action(:logout)).name(:logout) # logout ... default ExceptionsController.action(:not_found) # 404 endend
![Page 27: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/27.jpg)
(3/8) Controller
![Page 28: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/28.jpg)
Let's build our basecontroller
every action is valid Rack endpoint
value returned from action becomesbody of the response
![Page 29: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/29.jpg)
# lib/base_controller.rbmodule Foobar class BaseController def call(env) @request = Rack::Request.new(env) @response = Rack::Response.new resp_text = self.send(env['x-rack.action-name']) @response.write(resp_text) @response.finish end def self.action(name) lambda do |env| env['x-rack.action-name'] = name self.new.call(env) end end endend
![Page 30: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/30.jpg)
# config.rurequire APP_ROOT / "lib" / "base_controller.rb"Dir[APP_ROOT / "app" / "controllers" / "*.rb"].each do |f| require fend
![Page 31: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/31.jpg)
Now we can createUsersController
![Page 32: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/32.jpg)
# app/controllers/users_controller.rbclass UsersController < Foobar::BaseController def index "Hello there!" endend
![Page 33: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/33.jpg)
Controllers also need following:session access
setting flash messages
setting HTTP headers
redirects
url generation
![Page 34: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/34.jpg)
rack-contrib"Contributed Rack Middleware and Utilities"
github.com/rack/rack-contrib
rack-flash"Simple flash hash implementation for Rack apps"
nakajima.github.com/rack-flash
![Page 35: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/35.jpg)
# Gemfilegem "rack-flash"gem "rack-contrib", :require => 'rack/contrib'# config.ruuse Rack::Flashuse Rack::Session::Cookieuse Rack::MethodOverrideuse Rack::NestedParams
![Page 36: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/36.jpg)
# lib/base_controller.rbmodule Foobar class BaseController def status=(code); @response.status = code; end def headers; @response.header; end def session; @request.env['rack.session']; end def flash; @request.env['x-rack.flash']; end def url(name, opts={}); Router.generate(name, opts); end def redirect_to(url) self.status = 302 headers["Location"] = url "You're being redirected" end endend
![Page 37: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/37.jpg)
Now we can use #session,#flash and #redirect_to
![Page 38: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/38.jpg)
# app/controllers/users_controller.rbclass UsersController < Foobar::BaseController def openid if session["openid.url"] flash[:notice] = "Cool!" redirect_to "/cool" else render end endend
![Page 39: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/39.jpg)
(4/8) Views
![Page 40: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/40.jpg)
Tilt"Generic interface to multiple Ruby template engines"
github.com/rtomayko/tilt
![Page 41: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/41.jpg)
# Gemfilegem "tilt"
![Page 42: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/42.jpg)
# lib/base_controller.rbmodule Foobar class BaseController def render(template=nil) template ||= @request.env['x-rack.action-name'] views_path = "#{APP_ROOT}/app/views" template_path = "#{views_path}/#{self.class.to_s.underscore}/" + "#{template}.html.erb" layout_path = "#{views_path}/layouts/application.html.erb" Tilt.new(layout_path).render(self) do Tilt.new(template_path).render(self) end end endend
![Page 43: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/43.jpg)
(5/8) ORM
![Page 44: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/44.jpg)
DataMapper"DataMapper is a Object Relational Mapper written in Ruby. Thegoal is to create an ORM which is fast, thread-safe and feature
rich."
datamapper.org
![Page 45: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/45.jpg)
# Gemfilegem "dm-core"gem "dm-..."# app/models/user.rbclass User include DataMapper::Resource property :id, Serial property :login, String, :required => true property :password, String, :required => trueend# config.ruDir[APP_ROOT / "app" / "models" / "*.rb"].each do |f| require fend
![Page 46: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/46.jpg)
(6/8) Authentication
![Page 47: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/47.jpg)
Warden"General Rack Authentication Framework"
github.com/hassox/warden
![Page 48: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/48.jpg)
# Gemfilegem "warden"# config.ruuse Warden::Manager do |manager| manager.default_strategies :password manager.failure_app = ExceptionsController.action(:unauthenticated)endrequire "#{APP_ROOT}/lib/warden.rb"
![Page 49: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/49.jpg)
# lib/warden.rbWarden::Manager.serialize_into_session do |user| user.idendWarden::Manager.serialize_from_session do |key| User.get(key)endWarden::Strategies.add(:password) do def authenticate! u = User.authenticate( params["username"], params["password"] ) u.nil? ? fail!("Could not log in") : success!(u) endend
![Page 50: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/50.jpg)
# lib/base_controller.rbmodule Foobar class BaseController def authenticate! @request.env['warden'].authenticate! end def logout!(scope=nil) @request.env['warden'].logout(scope) end def current_user @request.env['warden'].user end endend
![Page 51: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/51.jpg)
Now we can guard our action:# app/controllers/users_controller.rbclass UsersController < Foobar::BaseController def index authenticate! @users = User.all(:id.not => current_user.id) render endend
![Page 52: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/52.jpg)
(7/8) Testing
![Page 53: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/53.jpg)
rack-test"Rack::Test is a small, simple testing API for Rack apps. It can be
used on its own or as a reusable starting point for Webframeworks and testing libraries to build on."
github.com/brynary/rack-test
![Page 54: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/54.jpg)
# Gemfilegem "rack-test"
![Page 55: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/55.jpg)
require "rack/test"class UsersControllerTest < Test::Unit::TestCase include Rack::Test::Methods def app Foobar::Router.new end def test_redirect_from_old_dashboard get "/old_dashboard" follow_redirect! assert_equal "http://example.org/new_dashboard", last_request.url assert last_response.ok? endend
![Page 56: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/56.jpg)
(8/8) Console
![Page 57: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/57.jpg)
racksh (aka Rack::Shell)"racksh is a console for Rack based ruby web applications. It's
like Rails script/console or Merb's merb -i, but for any app builton Rack"
github.com/sickill/racksh
![Page 58: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/58.jpg)
Installation
![Page 59: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/59.jpg)
gem install racksh
![Page 60: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/60.jpg)
Example racksh session
![Page 61: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/61.jpg)
$ rackshRack::Shell v0.9.7 started in development environment.>> $rack.get "/"=> #<Rack::MockResponse:0xb68fa7bc @body="<html>...", @headers={"Content-Type"=>"text/html", "Content-Length"=>"1812"}, @status=200, ...>> User.count=> 123
![Page 62: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/62.jpg)
Questions?
![Page 63: Building web framework with Rack](https://reader033.fdocuments.us/reader033/viewer/2022042813/54bd18c84a7959766e8b459f/html5/thumbnails/63.jpg)
That's it!Example code available at: github.com/sickill/example-rack-
framework
email: marcin.kulik at gmail.com / www: ku1ik.com / twitter:@sickill