Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby MVC from scratch with Rack

DonSchado
August 23, 2014

Ruby MVC from scratch with Rack

Imagine for a while that Rails wouldn't exist. How would we write a MVC app from scratch?

Rack provides a minimal interface for developing web applications in Ruby. In fact it's the solid foundation of all major Ruby powered web frameworks.
During this talk we will dive deep into Rack. We will see the smallest possible Rack Application and learn how it works, by studying Rack internals. We will grow the Application step by step till we implement it in simple MVC style.

Code: https://github.com/DonSchado/Frack-MVC

DonSchado

August 23, 2014
Tweet

More Decks by DonSchado

Other Decks in Programming

Transcript

  1. Ruby MVC from scratch with Rack I Marco Schaden |

    @donschado | 23.08.2014 RedFrog Conf
  2. there was a rack application handling 10.000+ req/sec once upon

    a time http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html
  3. DISCLAIMER no live coding: but we write and refactor a

    lot of code! simple codez: examples try to be more obvious than "SOLID"! • a newbie will learn some cool tricks! • a pro will find a lot to complain ;)! !seriously: this presentation contains all the memes, sorry
  4. Rack 2.0, or Rack for the Future https://gist.github.com/raggi/11c3491561802e573a47 https://docs.google.com/document/d/
 1Ltwk-NJeJHIZy7yqLi5XBxAnclRqWwOQBOzb4EYJGO4/

    https://gist.github.com/rkh/d99f0bf820de79b8d59b https://github.com/tenderlove/the_metal http://tenderlovemaking.com/2011/03/03/rack-api-is-awkward.html
  5. http://chneukirchen.org/talks/euruko-2007/neukirchen07introducingrack.pdf • specification! • implementation! • minimal abstract API for

    HTTP! • Request: CGI environment! • Response: status, headers, body common interface between server and application
  6. Write once, run "everywhere" WEBrick! Thin! Puma! Unicorn! Passenger! Torqbox

    / Torquebox! Trinidad! Mongrel! Pow! CGI! SCGI! FastCGI! Ebb! Fuzed! Litespeed! …
  7. RackApp +call(env) A rack application is any Ruby object that

    responds to call. ! ! It takes the environment hash as argument! and returns an array of exactly three values: ! the status, the headers and the body*! ! *which must respond to each
  8. ! ->(env) { } *run means "call that object for

    each request" run [ ] 200, {'Content-Type' => 'text/html'}, ['Hello World!']
  9. ! ->(env) { } *run means "call that object for

    each request" # config.ru run [ ] 200, {'Content-Type' => 'text/html'}, ['Hello World!']
  10. ! ->(env) { } $ rackup 127.0.0.1 - - [23/Aug/2014

    10:50:07] "GET / HTTP/1.1" 200 - 0.0007 [2014-08-23 10:50:00] INFO WEBrick 1.3.1 [2014-08-23 10:50:00] INFO ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0] [2014-08-23 10:50:00] INFO WEBrick::HTTPServer#start: pid=11802 port=9292 *run means "call that object for each request" # config.ru run [ ] 200, {'Content-Type' => 'text/html'}, ['Hello World!']
  11. ! ->(env) { } $ rackup 127.0.0.1 - - [23/Aug/2014

    10:50:07] "GET / HTTP/1.1" 200 - 0.0007 [2014-08-23 10:50:00] INFO WEBrick 1.3.1 [2014-08-23 10:50:00] INFO ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0] [2014-08-23 10:50:00] INFO WEBrick::HTTPServer#start: pid=11802 port=9292 *run means "call that object for each request" SHIP IT # config.ru run [ ] 200, {'Content-Type' => 'text/html'}, ['Hello World!']
  12. # config.ru ! ! ! ! ! ! ! !

    ! ! ! ! ! ! ! ! run -> e { Rack::Response.new(view) } view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with HTML</title> </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html> HTML
  13. # config.ru ! ! ! ! ! ! ! !

    ! ! ! ! ! ! ! ! run -> e { Rack::Response.new(view) } require 'erb' view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html> HTML ERB</title> <h1>Current time: <%= Time.now %></h1>
  14. # config.ru ! ! ! ! ! ! ! !

    ! ! ! ! ! ! ! ! run -> e { Rack::Response.new(view) } require 'erb' view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html> HTML ERB</title> <h1>Current time: <%= Time.now %></h1> ERB.new(view).result) }
  15. MVC

  16. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru
  17. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru source "https://rubygems.org" ! gem 'rack' gem 'thin' gem 'tilt'
  18. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru <html> <head> <title>Frack MVC</title> </head> <body> <h1>application#layout</h1> <%= yield %> </body> </html>
  19. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru <h2>users#index</h2>
  20. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) # Your code goes here... end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application *use adds a middleware to the rack application stack created by Rack::Builder.
  21. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application Rack::Response.new(env) *use adds a middleware to the rack application stack created by Rack::Builder.
  22. ["SERVER_SOFTWARE",."thin.1.6.2.codename.Doc.Brown"] ["SERVER_NAME",."localhost"]["rack.input",. #<Rack::Lint::InputWrapper:0x007fc0421e1ea0. @input=#<StringIO:0x007fc0421fb940>>]["rack.version",.[1,. 0]]["rack.errors",.#<Rack::Lint::ErrorWrapper: 0x007fc0421e1cc0.@error=#<IO:<STDERR>>>] ["rack.multithread",.false]["rack.multiprocess",.false] ["rack.run_once",.false]["REQUEST_METHOD",."GET"] ["REQUEST_PATH",."/"]["PATH_INFO",."/"]["REQUEST_URI",."/"] ["HTTP_VERSION",."HTTP/1.1"]["HTTP_USER_AGENT",."curl/

    7.30.0"]["HTTP_HOST",."localhost:9292"]["HTTP_ACCEPT",."*/ *"]["GATEWAY_INTERFACE",."CGI/1.2"]["SERVER_PORT",."9292"] ["QUERY_STRING",.""]["SERVER_PROTOCOL",."HTTP/1.1"] ["rack.url_scheme",."http"]["SCRIPT_NAME",.""] ["REMOTE_ADDR",."127.0.0.1"]["async.callback",.#<Method:. Thin::Connection#post_process>]["async.close",. #<EventMachine::DefaultDeferrable:0x007fc0421fab08>]
  23. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application env
  24. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  25. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  26. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! def render(view) render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  27. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! def render(view) render_template('layouts/application') do render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  28. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  29. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  30. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index' end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  31. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index'
  32. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index' frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb ! ! ! ! ! &$ config.ru
  33. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index' frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb ! ! ! ! ! &$ config.ru #$ public " #$ css " " &$ style.css " #$ images " &$ js
  34. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru html { font-family: sans-serif; } h1 { color: #008040; } h2 { color: #ff0080; }
  35. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru <html> <head> <title>Frack MVC</title> ! </head> <body> <h1>application#layout</h1> <%= yield %> </body> </html>
  36. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru <html> <head> <title>Frack MVC</title> ! </head> <body> <h1>application#layout</h1> <%= yield %> </body> </html> <link rel="stylesheet" type="text/css" href="css/style.css">
  37. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! end end end ! ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index' frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  38. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') end end end end ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) Rack::Response.new( ) end ! ! ! ! ! ! ! ! ! ! end end end ! ! use Rack::CommonLogger use Rack::ContentLength run Frack::Application def render(view) render_template('layouts/application') do render_template(view) end end def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end render 'users/index' use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  39. ["SERVER_SOFTWARE",."thin.1.6.2.codename.Doc.Brown"] ["SERVER_NAME",."localhost"]["rack.input",. #<Rack::Lint::InputWrapper:0x007fc0421e1ea0. @input=#<StringIO:0x007fc0421fb940>>]["rack.version",.[1,. 0]]["rack.errors",.#<Rack::Lint::ErrorWrapper: 0x007fc0421e1cc0.@error=#<IO:<STDERR>>>] ["rack.multithread",.false]["rack.multiprocess",.false] ["rack.run_once",.false]["REQUEST_METHOD",."GET"] ["REQUEST_PATH",""/"]["PATH_INFO",""/"]["REQUEST_URI",."/"] ["HTTP_VERSION",."HTTP/1.1"]["HTTP_USER_AGENT",."curl/

    7.30.0"]["HTTP_HOST",."localhost:9292"]["HTTP_ACCEPT",."*/ *"]["GATEWAY_INTERFACE",."CGI/1.2"]["SERVER_PORT",."9292"] ["QUERY_STRING",.""]["SERVER_PROTOCOL",."HTTP/1.1"] ["rack.url_scheme",."http"]["SCRIPT_NAME",.""] ["REMOTE_ADDR",."127.0.0.1"]["async.callback",.#<Method:. Thin::Connection#post_process>]["async.close",. #<EventMachine::DefaultDeferrable:0x007fc0421fab08>] remember env?
  40. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  41. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  42. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application if env['PATH_INFO'] == '/' frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  43. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application if env['PATH_INFO'] == '/' else Rack::Response.new('Not found', 404) end frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  44. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) ! Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render( end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application if env['PATH_INFO'] == '/' else Rack::Response.new('Not found', 404) end &block) frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  45. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) ! Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render( end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application if env['PATH_INFO'] == '/' else Rack::Response.new('Not found', 404) end @users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] &block) frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  46. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) ! Rack::Response.new(render 'users/index') ! ! ! end ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render( end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application if env['PATH_INFO'] == '/' else Rack::Response.new('Not found', 404) end @users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] &block) self, frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  47. <h2>users#index</h2> ! ! ! ! ! frack-mvc " #$ Gemfile

    #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  48. <h2>users#index</h2> ! ! ! ! ! <ul> <% @users.each do

    |user| %> <li><%= user %></li> <% end %> </ul> frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru
  49. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application render 'users/index') @users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] Rack::Response.new( else Rack::Response.new('Not found', 404) end end
  50. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application Rack::Response.new( else Rack::Response.new('Not found', 404) end end
  51. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' ! ! ! ! ! def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application Rack::Response.new( else Rack::Response.new('Not found', 404) end end UsersController.new.index)
  52. $LOAD_PATH << '.' require 'rack' require 'tilt' ! module Frack

    class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end ! ! ! ! ! ! ! ! ! ! ! ! end end ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru end end class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end
  53. Rack::Response.new('Not found', 404) end end end end ! class BaseController

    def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end
  54. Rack::Response.new('Not found', 404) end end end end ! class BaseController

    def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js &$ config.ru class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end
  55. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js ! ! ! ! &$ config.ru
  56. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js ! ! ! ! #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru
  57. require 'spec_helper' ! Capybara.app = Rack::Builder.new do eval(File.read(File.expand_path('./config.ru'))) end !

    ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js ! ! ! ! #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru
  58. require 'spec_helper' ! Capybara.app = Rack::Builder.new do eval(File.read(File.expand_path('./config.ru'))) end !

    ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js ! ! ! ! #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb describe 'users#index' do before { visit '/' } it 'renders layout' do expect(page).to have_content('application#layout') end it 'renders index view' do expect(page).to have_content('users#index') end it 'shows a list of users' do expect(page).to have_selector('li', text: /Stark|Parker|Wayne/, count: 3) end end &$ config.ru
  59. $ rspec ! users#index renders layout renders index view shows

    a list of users ! Finished in 0.02326 seconds 3 examples, 0 failures ! Randomized with seed 13626
  60. module Frack class Application class << self def call(env) if

    env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end ! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end ! class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end frack-mvc " #$ Gemfile #$ app " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru
  61. frack-mvc " #$ Gemfile #$ app " &$ views "

    #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end ! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end end ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end ! class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end REFACTOR ALL THE FRACK
  62. ! " &$ views " #$ layouts " " &$

    application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru frack-mvc " #$ Gemfile #$ app
  63. " #$ controllers " " &$ users_controller.rb " #$ models

    " " &$ user.rb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb ! " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru frack-mvc " #$ Gemfile #$ app
  64. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end module Frack ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! end class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end
  65. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end require 'app/controllers/users_controller' module Frack ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! end class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end
  66. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end require 'app/models/user' require 'app/controllers/users_controller' module Frack ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! end class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end
  67. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! class UsersController < Frack::BaseController def index @users = User.all render 'users/index' end end class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] end end require 'app/models/user' require 'app/controllers/users_controller' require 'lib/frack' module Frack ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! end class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end class BaseController def render(view) render_template('layouts/application') do render_template(view) end end ! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end
  68. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength run Frack::Application
  69. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << File.expand_path(File.dirname(__FILE__)) ! require 'rack' require 'tilt' ! module Frack autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller' end
  70. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru "app/views/#{ }.html. ).render(self, &block) end end erb" path
  71. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru "app/views/#{ }.html. ).render(self, &block) end end *" path
  72. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end path
  73. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end file( ) path
  74. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end def file(path) Dir[ ] end file( ) path
  75. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end def file(path) Dir[ ] end File.join('app', 'views', "#{path}.html.*") file( ) path
  76. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end def file(path) Dir[ ] end File.join('app', 'views', "#{path}.html.*") .first file( ) path
  77. module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end

    end ! def render_template(path, &block) Tilt.new( end ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ).render(self, &block) end end def file(path) Dir[ ] end File.join('app', 'views', "#{path}.html.*") .first file( ) path AWESOME!
 support all the template engines
  78. MVC

  79. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application

    HTTP request *a middleware is a rack application that wraps up an inner application.
  80. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application

    HTTP request HTTP response *a middleware is a rack application that wraps up an inner application.
  81. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application

    HTTP request HTTP response module Rack class ContentLength def initialize(app) @app = app end ! def call(env) status, headers, body = @app.call(env) # [...] # headers['Content-Length'] = length.to_s # [...] [status, headers, body] end end end *a middleware is a rack application that wraps up an inner application.
  82. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength ! run Frack::Application
  83. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength ! run Frack::Application use Frack::Router
  84. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << File.expand_path(File.dirname(__FILE__)) ! require 'rack' require 'tilt' ! module Frack ! autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller' end
  85. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << File.expand_path(File.dirname(__FILE__)) ! require 'rack' require 'tilt' ! module Frack ! autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller' end autoload :Router, 'frack/router'
  86. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru module Frack class Router attr_reader :app ! def initialize(app) @app = app end ! def call(env) app.call(env) end end end
  87. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru app.call(env)
  88. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ROUTES = { '/' => } app.call(env)
  89. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru ROUTES = { '/' => } app.call(env) { 'controller' => 'users', 'action' => 'index' },
  90. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) ROUTES = { '/' => } app.call(env) { 'controller' => 'users', 'action' => 'index' },
  91. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!(mapping) ROUTES = { '/' => } app.call(env) { 'controller' => 'users', 'action' => 'index' },
  92. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!(mapping) else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) { 'controller' => 'users', 'action' => 'index' },
  93. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!(mapping) else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index'
  94. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' mapping)
  95. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) mapping)
  96. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) controller_action( ) mapping)
  97. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping)
  98. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) def controller_action(mapping) ! ! end or keep it simple…
  99. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) def controller_action(mapping) ! ! end or keep it simple… controller, action = mapping.split('#')
  100. module Frack class Router attr_reader :app ! ! ! !

    ! def initialize(app) @app = app end ! def call(env) ! ! ! ! ! end ! ! ! ! end end frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) def controller_action(mapping) ! ! end or keep it simple… controller, action = mapping.split('#') { 'controller' => controller, 'action' => action }
  101. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if env['PATH_INFO'] == '/' else Rack::Response.new('Not found', 404) end UsersController.new.index) Rack::Response.new( end end end def call(env) end
  102. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru UsersController.new.index) Rack::Response.new( end end end def call(env) end
  103. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru Rack::Response.new( end end end def call(env) end
  104. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru *dispatch) Rack::Response.new( end end end def call(env) end
  105. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru *dispatch) Rack::Response.new( end end end def call(env) attr_accessor :env self.env = env end
  106. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru *dispatch) Rack::Response.new( end end end def call(env) attr_accessor :env self.env = env end def dispatch controller.new.public_send(env['action']) end
  107. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru *dispatch) Rack::Response.new( end end end def call(env) attr_accessor :env self.env = env end def dispatch controller.new.public_send(env['action']) end def controller
  108. module Frack class Application class << self ! ! !

    ! ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru *dispatch) Rack::Response.new( end end end def call(env) attr_accessor :env self.env = env end def dispatch controller.new.public_send(env['action']) end def controller Object.const_get(env['controller'].capitalize + 'Controller') end
  109. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength ! ! ! ! use Frack::Router run Frack::Application
  110. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH << '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::CommonLogger use Rack::ContentLength ! ! ! ! use Frack::Router do match '/' => 'users#index' end run Frack::Application
  111. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) def initialize(app) @app = app end end ROUTES
  112. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end ROUTES = { '/' => } app.call(env) 'users#index' def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes def initialize(app) @app = app end end ROUTES
  113. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes routes def initialize(app) @app = app end end
  114. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes routes def initialize(app) @app = app end end , &block)
  115. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes @routes = {} routes def initialize(app) @app = app end end , &block)
  116. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes @routes = {} instance_eval(&block) if block_given? routes def initialize(app) @app = app end end , &block)
  117. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes @routes = {} instance_eval(&block) if block_given? routes def match(route) def initialize(app) @app = app end end , &block)
  118. module Frack class Router attr_reader :app ! ! ! !

    ! ! ! end ! def call(env) ! ! ! ! ! end ! ! ! ! ! ! ! ! ! frack-mvc " #$ Gemfile #$ app " #$ controllers " " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end app.call(env) def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end controller_action( ) mapping) , :routes @routes = {} instance_eval(&block) if block_given? routes def match(route) self.routes.merge!(route) end def initialize(app) @app = app end end , &block)
  119. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH.unshift '.' ! require 'lib/frack' require 'app/controllers/users_controller' require 'app/models/user' ! # use Rack::CommonLogger use Rack::Static, root: 'public', urls: ['/images', '/js', '/css'] use Rack::ContentLength use Frack::Router do match '/' => 'users#index' end ! run Frack::Application
  120. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) ! require 'rack' require 'erb' require 'tilt' ! module Frack autoload :Router, 'frack/router' autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller' end
  121. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru module Frack class Router attr_reader :app, :routes ! def initialize(app, &block) @app = app @routes = {} instance_eval(&block) if block_given? end ! def call(env) if (mapping = routes[env['PATH_INFO']]) env.merge!(controller_action(mapping)) app.call(env) else Rack::Response.new('Not found', 404) end end ! def controller_action(mapping) controller, action = mapping.split('#') { 'controller' => controller, 'action' => action } end ! def match(route) self.routes.merge!(route) end end end
  122. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru module Frack class Application class << self attr_accessor :env ! def call(env) self.env = env Rack::Response.new(*dispatch) end ! def dispatch controller.new(env).public_send(env['action']) end ! def controller Object.const_get(env['controller'].capitalize + 'Controller') end end end end
  123. frack-mvc " #$ Gemfile #$ app " #$ controllers "

    " &$ users_controller.rb " #$ models " " &$ user.rb " &$ views " #$ layouts " " &$ application.html.erb " &$ users " &$ index.html.erb #$ lib " #$ frack " " #$ application.rb " " #$ base_controller.rb " " &$ router.rb " &$ frack.rb #$ public " #$ css " " &$ style.css " #$ images " &$ js #$ spec " #$ integration " " &$ user_spec.rb " &$ spec_helper.rb &$ config.ru module Frack class BaseController attr_reader :env ! def initialize(env) @env = env end ! def render(view) render_template(layout) do render_template(view) end end ! def render_template(path, &block) Tilt.new(file(path)).render(self, &block) end ! def file(path) Dir[File.join('app', 'views', "#{path}.html.*")].first end ! def layout File.join('layouts', 'application') end end end
  124. Challenges for the curious ones: ! • params! • redirect_to!

    • partial rendering! • implicit call to render! • routing with placeholders! • routing with specific http verbs! • error handling! • session management! • flash messages! • persistence! • security stuff and protection! • different mime types! • url helper! • better class loading / autoloading! • asset management Rebuilding Rails features, is a great opportunity to learn how they work.
  125. YES, you should definitely do this at home *but maybe

    not in production or just <3 the Rails core team definitely checkout: http://lotusrb.org/ WHY? maybe you come up with the next big framework…
  126. Marco Schaden | @donschado | 23.08.2014 RedFrog Conf Marco @DonSchado

    - 17 Std.
 rackup -r rack/lobster -b 'run Rack::Lobster.new'
  127. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) *returns a valid Rack application for the Rails router to dispatch to
  128. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) OMG WHY? *returns a valid Rack application for the Rails router to dispatch to
  129. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) • maybe to extract lightweight micro services OMG WHY? *returns a valid Rack application for the Rails router to dispatch to
  130. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) • maybe to extract lightweight micro services • to improve the performance of any API endpoint OMG WHY? *returns a valid Rack application for the Rails router to dispatch to
  131. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) • maybe to extract lightweight micro services • to improve the performance of any API endpoint • because all benefits of rails are "just a few" includes away OMG WHY? *returns a valid Rack application for the Rails router to dispatch to
  132. http://api.rubyonrails.org/classes/ActionController/Metal.html class HelloController < ActionController::Metal def index self.response_body = "Hello

    World!" end end get 'hello', to: HelloController.action(:index) • maybe to extract lightweight micro services • to improve the performance of any API endpoint • because all benefits of rails are "just a few" includes away OMG WHY? *returns a valid Rack application for the Rails router to dispatch to class HelloController < ActionController::Metal include AbstractController::Rendering include ActionView::Layouts append_view_path "#{Rails.root}/app/views" ! def index render "hello/index" end ! # Ensure ActiveSupport::Notifications events are fired include ActionController::Instrumentation end
  133. "The fastest framework is Rack. ! Plain old Rack with

    no framework at all." Ruby 2.1 + Thin + Rack can hit 6301 req/sec => Sinatra only manages !! ! 2505 req/sec. => Rails only does ! ! ! ! 1455 req/sec "So, by simply using those frameworks on top of Rack, 
 you give up over 60% of your maximum possible throughput." Spoiler Alert!
  134. Spoiler spoiler Alert! On a plain old Rack app it

    did 10.159 req/sec. + "Standard Ruby + Thin/Unicorn + Rails ! is about the slowest possible combination" the fastest:
  135. *I think these benchmarks are a little bit unfair, !

    when you compare a full rails stack vs. a rack one-liner.! But I think the main message is valid:! Do you need the full stack for every request? Logging Sessions Cookies Security Caching Error Handling Routing