Ruby MVC from scratch with Rack
-
Upload
donschado -
Category
Technology
-
view
801 -
download
1
description
Transcript of Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
I
Marco Schaden | @donschado | 23.08.2014RedFrog Conf
there was a rack applicationhandling 10.000+ req/sec
once upon a time
http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html
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
Rack is the foundation of all modern Ruby web frameworks
http://chneukirchen.org/talks/euruko-2007/neukirchen07introducingrack.pdf
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
Write once, run "everywhere"
WEBrick!Thin!Puma!
Unicorn!Passenger!
Torqbox / Torquebox!Trinidad!Mongrel!
Pow!CGI!SCGI!
FastCGI!Ebb!
Fuzed!Litespeed!
…
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
<<"show"me"the"code">>
! ->(env) { }
! ->(env) { }[ ]
! ->(env) { }[ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
! ->(env) { }
*run means "call that object for each request"
run [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
! ->(env) { }
*run means "call that object for each request"
# config.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
! ->(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.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
! ->(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.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
HTML + ERB
# config.rurun -> e { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }
# config.rurun -> e { Rack::Response.new('Hello World!') }
# config.rurun -> e { Rack::Response.new(view) }
# 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
# 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>
# 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) }
Current time: 2014-08-23 10:54:29 +0200
</introduction>
MVC
froscon-rack-mvc
frack-mvc
frack-mvc"#$ Gemfile#$ app" &$ views" #$ layouts" " &$ application.html.erb" &$ users" &$ index.html.erb&$ config.ru
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'
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>
frack-mvc"#$ Gemfile#$ app" &$ views" #$ layouts" " &$ application.html.erb" &$ users" &$ index.html.erb&$ config.ru
<h2>users#index</h2>
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
*use adds a middleware to the rack application stack created by Rack::Builder.
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
Rack::Response.new(env)
*use adds a middleware to the rack application stack created by Rack::Builder.
["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>]
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
env
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!
end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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 endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
application#layout!!users#index
application#layout!!users#index
but can I haz style?
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun 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
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; }
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>
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">
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!!use Rack::CommonLoggeruse Rack::ContentLengthrun 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
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!!use Rack::CommonLoggeruse Rack::ContentLengthrun 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
application#layout !users#index
application#layout !users#index
what about simple routing?
and list some users?
["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?
$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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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) 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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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
$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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
if env['PATH_INFO'] == '/'
elseRack::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
$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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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
$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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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
$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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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
<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
<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
not sure if MVC…
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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
render 'users/index')@users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne']
Rack::Response.new( else Rack::Response.new('Not found', 404) end end
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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
Rack::Response.new( else Rack::Response.new('Not found', 404) end end
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 endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
Rack::Response.new( else Rack::Response.new('Not found', 404) end end
UsersController.new.index)
$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!!!!!!!!!!!! endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application
frack-mvc"#$ Gemfile#$ app" &$ views" #$ layouts" " &$ application.html.erb" &$ users" &$ index.html.erb#$ public" #$ css" " &$ style.css" #$ images" &$ js&$ config.ru
endend
class BaseControllerdef render(view) render_template('layouts/application') do render_template(view) endend!def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block)end
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 endend!!!!!!!!!!!!!!!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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::BaseControllerdef index
@users = User.allrender 'users/index'
endend
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 endend!!!!!!!!!!!!!!!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun 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::BaseControllerdef index
@users = User.allrender 'users/index'
endend
class Userdef self.all
['Anthony Stark', 'Peter Parker', 'Bruce Wayne']end
end
PROVE IT!
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
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
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' dobefore { visit '/' }
it 'renders layout' doexpect(page).to have_content('application#layout')
end
it 'renders index view' doexpect(page).to have_content('users#index')
end
it 'shows a list of users' doexpect(page).to have_selector('li',text: /Stark|Parker|Wayne/, count: 3)
endend
&$ config.ru
$ 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
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 endend!class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend!class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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 endend!class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend!class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
REFACTOR ALL THE FRACK
!" &$ 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
" #$ 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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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' endend
class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend
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
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::CommonLoggeruse Rack::ContentLengthrun Frack::Application
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
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)
endend
erb"path
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)
endend
*"path
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)
endend
path
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)
endend
file( )path
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)
endend
def file(path)Dir[ ]
end
file( )path
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)
endend
def file(path)Dir[ ]
endFile.join('app', 'views', "#{path}.html.*")
file( )path
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)
endend
def file(path)Dir[ ]
endFile.join('app', 'views', "#{path}.html.*") .first
file( )path
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)
endend
def file(path)Dir[ ]
endFile.join('app', 'views', "#{path}.html.*") .first
file( )path
AWESOME!support all the template engines
better routing?magic?
MVC
What if the router could be middleware?
Middleware Stack
*a middleware is a rack application that wraps up an inner application.
Middleware Stack
HT
TP
requ
est
*a middleware is a rack application that wraps up an inner application.
Middleware Stack
use Rack::Static
use Rack::CommonLogger
use Rack::ContentLength
run Frack::Application
HT
TP
requ
est
*a middleware is a rack application that wraps up an inner application.
Middleware Stack
use Rack::Static
use Rack::CommonLogger
use Rack::ContentLength
run Frack::Application
HT
TP
requ
est
HT
TP
resp
onse
*a middleware is a rack application that wraps up an inner application.
Middleware Stack
use Rack::Static
use Rack::CommonLogger
use Rack::ContentLength
run Frack::Application
HT
TP
requ
est
HT
TP
resp
onse
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 endend
*a middleware is a rack application that wraps up an inner application.
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::CommonLoggeruse Rack::ContentLength!run Frack::Application
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::CommonLoggeruse Rack::ContentLength!run Frack::Applicationuse Frack::Router
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
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'
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 endend
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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)
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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)
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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' },
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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' },
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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' },
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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)
elseRack::Response.new('Not found', 404)
end
ROUTES = {'/' =>
}
app.call(env)
{ 'controller' => 'users', 'action' => 'index' },
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend
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)
elseRack::Response.new('Not found', 404)
end
ROUTES = {'/' =>
}
app.call(env)
'users#index'
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend
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)
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend
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)
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend
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)
module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend
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)
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'] == '/'
elseRack::Response.new('Not found', 404)
end
UsersController.new.index)Rack::Response.new(
end endend
def call(env)
end
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 endend
def call(env)
end
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 endend
def call(env)
end
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 endend
def call(env)
end
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 endend
def call(env)
attr_accessor :env
self.env = env
end
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 endend
def call(env)
attr_accessor :env
self.env = env
end
def dispatchcontroller.new.public_send(env['action'])
end
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 endend
def call(env)
attr_accessor :env
self.env = env
end
def dispatchcontroller.new.public_send(env['action'])
end
def controller
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 endend
def call(env)
attr_accessor :env
self.env = env
end
def dispatchcontroller.new.public_send(env['action'])
end
def controllerObject.const_get(env['controller'].capitalize + 'Controller')
end
What if the router could take a block?
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::CommonLoggeruse Rack::ContentLength!!!!
use Frack::Routerrun Frack::Application
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::CommonLoggeruse Rack::ContentLength!!!!
use Frack::Router domatch '/' => 'users#index'
end
run Frack::Application
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
endend
ROUTES
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
endend
ROUTES
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
endend
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
endend
, &block)
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
endend
, &block)
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
endend
, &block)
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
endend
, &block)
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
endend
, &block)
in ~ 50-100 LOCMVC
I haven't shown you all of it
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.
yes, you should definitely do this at home
but maybe not in production
love the Rails core team for their amazing work
2014.RailsCamp.de
Marco Schaden | @donschado | 23.08.2014RedFrog Conf
kthxbye
Marco Schaden | @donschado | 23.08.2014RedFrog Conf
Marco @DonSchado - 17 Std.rackup -r rack/lobster -b 'run Rack::Lobster.new'
Backup
Appendix: Rack in the wild
http
://gu
ides
.ruby
onra
ils.o
rg/ra
ils_o
n_ra
ck.ht
ml
\m/ActionController ::Metal
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
get 'hello', to: HelloController.action(:index)
*returns a valid Rack application for the Rails router to dispatch to
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
get 'hello', to: HelloController.action(:index)
OMG WHY?
*returns a valid Rack application for the Rails router to dispatch to
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
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
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
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
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
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
http://api.rubyonrails.org/classes/ActionController/Metal.html
class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend
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::Instrumentationend
Backup Backup
http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html
"every possible rack server on every possible Ruby, every possible web framework"
Spoiler Alert!
"The fastest framework is Rack. !Plain old Rack with no framework at all."
Spoiler Alert!
"The fastest framework is Rack. !Plain old Rack with no framework at all."
Ruby 2.1 + Thin + Rack can hit 6301 req/sec
Spoiler Alert!
"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.
Spoiler Alert!
"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
Spoiler Alert!
"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!
Spoiler spoiler Alert!
"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"
Spoiler spoiler Alert!
"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"
the fastest:
Spoiler spoiler Alert!
+
"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"
the fastest:
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:
*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
# hello_world.rbrequire 'rack'!!!!!!!!
app = Rack::Builder.new do !!!end
$ ruby hello_world.rb
# config.rurun ->(env) { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }
$ rackup
map '/' do! end
Rack::Handler::WEBrick.run app, :Port => 9292
run ->(env) { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }
use Rack::CommonLogger
$ ruby -r rack -e 'Rack::Handler::Thin.run lambda { |env| [200, {}, ["ok"]] }'
$ rackup -b 'run proc { [200, {}, [Time.now.to_s]] }'
for the curious:
that’s all