SlideShare una empresa de Scribd logo
1 de 175
Descargar para leer sin conexión
Ruby MVC from scratch with Rack
I
Marco Schaden | @donschado | 23.08.2014RedFrog Conf
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
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.ru
run [ 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ]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.ru
run [ 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ]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.ru
run [ 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
, read it: https://github.com/rack/rack
How does it work?
seriously
HTML + ERB
# config.ru	
run -> e { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }
# config.ru	
run -> e { Rack::Response.new('Hello World!') }
# config.ru	
run -> 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	
end	
end	
!
use Rack::CommonLogger	
use Rack::ContentLength	
run 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	
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.
["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	
end	
end	
!
use Rack::CommonLogger	
use Rack::ContentLength	
run 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	
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
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
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
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
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
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
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
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	
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
$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
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	
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
$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
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	
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
$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
$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
$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
$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
$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
<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	
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
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
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)
$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
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
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
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' 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
$ 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	
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
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
!
"  &$ 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'	
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
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
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
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
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
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
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
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)
end	
end
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)
end	
end
*"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)
end	
end
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)
end	
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)
end	
end
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)
end	
end
def file(path)
Dir[ ]
end
File.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)
end	
end
def file(path)
Dir[ ]
end
File.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)
end	
end
def file(path)
Dir[ ]
end
File.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
HTTPrequest
*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
HTTPrequest
*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
HTTPrequest
HTTPresponse
*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
HTTPrequest
HTTPresponse
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.
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
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
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	
end	
end
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)
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)
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' },
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' },
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' },
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' },
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'
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)
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)
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)
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)
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
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
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
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
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
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
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
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
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::CommonLogger	
use Rack::ContentLength	
!
!
!
!
use Frack::Router
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::CommonLogger	
use Rack::ContentLength	
!
!
!
!
use Frack::Router do
match '/' => '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
end	
end
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
end	
end
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
end	
end
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)
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)
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)
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)
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)
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://guides.rubyonrails.org/rails_on_rack.html
m/ActionController::Metal
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
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
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
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack
Ruby MVC from scratch with Rack

Más contenido relacionado

La actualidad más candente

Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain Points
Steven Evatt
 

La actualidad más candente (20)

Nodejs.meetup
Nodejs.meetupNodejs.meetup
Nodejs.meetup
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
 
A Toda Maquina Con Ruby on Rails
A Toda Maquina Con Ruby on RailsA Toda Maquina Con Ruby on Rails
A Toda Maquina Con Ruby on Rails
 
Mastering Grunt
Mastering GruntMastering Grunt
Mastering Grunt
 
Sinatra for REST services
Sinatra for REST servicesSinatra for REST services
Sinatra for REST services
 
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain Points
 
Ruby on Rails Presentation
Ruby on Rails PresentationRuby on Rails Presentation
Ruby on Rails Presentation
 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3
 
Sinatra Rack And Middleware
Sinatra Rack And MiddlewareSinatra Rack And Middleware
Sinatra Rack And Middleware
 
Debugging on rails
Debugging on railsDebugging on rails
Debugging on rails
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
 
BP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesBP-6 Repository Customization Best Practices
BP-6 Repository Customization Best Practices
 
WP Weekend #2 - Corcel, aneb WordPress přes Laravel
WP Weekend #2 - Corcel, aneb WordPress přes LaravelWP Weekend #2 - Corcel, aneb WordPress přes Laravel
WP Weekend #2 - Corcel, aneb WordPress přes Laravel
 
CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and Webpack
 
Write php deploy everywhere tek11
Write php deploy everywhere   tek11Write php deploy everywhere   tek11
Write php deploy everywhere tek11
 
Developing OpenResty Framework
Developing OpenResty FrameworkDeveloping OpenResty Framework
Developing OpenResty Framework
 
Ajax Security
Ajax SecurityAjax Security
Ajax Security
 

Destacado (9)

What is Rack ?
What is Rack ?What is Rack ?
What is Rack ?
 
Why Hanami? @ 1º Hanami Sao Paulo meetup
Why Hanami? @ 1º Hanami Sao Paulo meetupWhy Hanami? @ 1º Hanami Sao Paulo meetup
Why Hanami? @ 1º Hanami Sao Paulo meetup
 
Rack By Example
Rack By ExampleRack By Example
Rack By Example
 
Introducing Rack
Introducing RackIntroducing Rack
Introducing Rack
 
Programming & The Web & Programming the Web
Programming & The Web & Programming the WebProgramming & The Web & Programming the Web
Programming & The Web & Programming the Web
 
Introduction to Web Programming
Introduction to Web ProgrammingIntroduction to Web Programming
Introduction to Web Programming
 
The web and programming: an introduction - Simple, short and friendly
The web and programming: an introduction - Simple, short and friendly The web and programming: an introduction - Simple, short and friendly
The web and programming: an introduction - Simple, short and friendly
 
Model View Controller (MVC)
Model View Controller (MVC)Model View Controller (MVC)
Model View Controller (MVC)
 
Mvc architecture
Mvc architectureMvc architecture
Mvc architecture
 

Similar a Ruby MVC from scratch with Rack

A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Tom Croucher
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018
Ortus Solutions, Corp
 

Similar a Ruby MVC from scratch with Rack (20)

Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middleware
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Rack
RackRack
Rack
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
 
Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
8 Minutes On Rack
8 Minutes On Rack8 Minutes On Rack
8 Minutes On Rack
 
Rack
RackRack
Rack
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
hacking with node.JS
hacking with node.JShacking with node.JS
hacking with node.JS
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web apps
 
Socket.IO
Socket.IOSocket.IO
Socket.IO
 
Intro to Node
Intro to NodeIntro to Node
Intro to Node
 
Plack at YAPC::NA 2010
Plack at YAPC::NA 2010Plack at YAPC::NA 2010
Plack at YAPC::NA 2010
 
Into The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerInto The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and docker
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018
 

Más de DonSchado (6)

The return of an old enemy
The return of an old enemyThe return of an old enemy
The return of an old enemy
 
Decorator & Presenter Design Pattern
Decorator & Presenter Design PatternDecorator & Presenter Design Pattern
Decorator & Presenter Design Pattern
 
Ruby's require, autoload and load methods
Ruby's require, autoload and load methodsRuby's require, autoload and load methods
Ruby's require, autoload and load methods
 
A taste of Computer Science
A taste of Computer ScienceA taste of Computer Science
A taste of Computer Science
 
Mutation testing with the mutant gem
Mutation testing with the mutant gemMutation testing with the mutant gem
Mutation testing with the mutant gem
 
Rails - How does it work?
Rails - How does it work?Rails - How does it work?
Rails - How does it work?
 

Último

Último (20)

GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 

Ruby MVC from scratch with Rack

  • 1. Ruby MVC from scratch with Rack I Marco Schaden | @donschado | 23.08.2014RedFrog 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.
  • 5. Rack is the foundation of all modern Ruby web frameworks
  • 7. 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
  • 8. Write once, run "everywhere" WEBrick! Thin! Puma! Unicorn! Passenger! Torqbox /Torquebox! Trinidad! Mongrel! Pow! CGI! SCGI! FastCGI! Ebb! Fuzed! Litespeed! …
  • 9. 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
  • 11. ! ->(env) { }
  • 12. ! ->(env) { }[ ]
  • 13. ! ->(env) { }[ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
  • 14. ! ->(env) { } *run means "call that object for each request" run [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
  • 15. ! ->(env) { } *run means "call that object for each request" # config.ru run [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']
  • 16. ! ->(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!']
  • 17. ! ->(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!']
  • 18. , read it: https://github.com/rack/rack How does it work? seriously
  • 20. # config.ru run -> e { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }
  • 21. # config.ru run -> e { Rack::Response.new('Hello World!') }
  • 22. # config.ru run -> e { Rack::Response.new(view) }
  • 23. # 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
  • 24. # 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>
  • 25. # 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) }
  • 26. Current time: 2014-08-23 10:54:29 +0200
  • 28. MVC
  • 31. frack-mvc " #$ Gemfile #$ app "  &$ views "   #$ layouts "   "  &$ application.html.erb "   &$ users "   &$ index.html.erb &$ config.ru
  • 32. 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'
  • 33. 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>
  • 34. frack-mvc " #$ Gemfile #$ app "  &$ views "   #$ layouts "   "  &$ application.html.erb "   &$ users "   &$ index.html.erb &$ config.ru <h2>users#index</h2>
  • 35. 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.
  • 36. 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.
  • 37. ["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>]
  • 38. 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
  • 39. 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
  • 40. 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
  • 41. 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
  • 42. 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
  • 43. 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
  • 44. 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
  • 45. 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
  • 48. $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
  • 49. $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
  • 50. 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; }
  • 51. 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>
  • 52. 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">
  • 53. $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
  • 54. $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
  • 56. application#layout ! users#index what about simple routing? and list some users?
  • 57. ["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?
  • 58. $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
  • 59. $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
  • 60. $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
  • 61. $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
  • 62. $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
  • 63. $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
  • 64. <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
  • 65. <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
  • 66.
  • 67.
  • 68. not sure if MVC…
  • 69. 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
  • 70. 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
  • 71. 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)
  • 72. $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
  • 73. 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
  • 74. 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
  • 75.
  • 77. 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
  • 78. 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
  • 79. 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
  • 80. $ 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
  • 81. 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
  • 82. 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
  • 83. ! "  &$ 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
  • 84. " #$ 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
  • 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 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 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
  • 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 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 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
  • 87. 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
  • 88. 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
  • 89. 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
  • 90. 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
  • 91. 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
  • 92. 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
  • 93. 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
  • 94. 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
  • 95. 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
  • 96. 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
  • 97. 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
  • 98. 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
  • 99. 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
  • 100. 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
  • 102. What if the router could be middleware?
  • 103. Middleware Stack *a middleware is a rack application that wraps up an inner application.
  • 104. Middleware Stack HTTPrequest *a middleware is a rack application that wraps up an inner application.
  • 105. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application HTTPrequest *a middleware is a rack application that wraps up an inner application.
  • 106. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application HTTPrequest HTTPresponse *a middleware is a rack application that wraps up an inner application.
  • 107. Middleware Stack use Rack::Static use Rack::CommonLogger use Rack::ContentLength run Frack::Application HTTPrequest HTTPresponse 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.
  • 108. 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
  • 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 ! run Frack::Application use Frack::Router
  • 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 << File.expand_path(File.dirname(__FILE__)) ! require 'rack' require 'tilt' ! module Frack ! autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller' end
  • 111. 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'
  • 112. 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
  • 113. 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)
  • 114. 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)
  • 115. 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' },
  • 116. 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' },
  • 117. 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' },
  • 118. 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' },
  • 119. 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'
  • 120. 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)
  • 121. 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)
  • 122. 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)
  • 123. 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)
  • 124. 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
  • 125. 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
  • 126. 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
  • 127. 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
  • 128. 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
  • 129. 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
  • 130. 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
  • 131. 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
  • 132. What if the router could take a block?
  • 133. 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
  • 134. 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
  • 135. 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
  • 136. 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
  • 137. 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
  • 138. 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)
  • 139. 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)
  • 140. 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)
  • 141. 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)
  • 142. 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)
  • 144.
  • 145. I haven't shown you all of it
  • 146. 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.
  • 147. yes, you should definitely do this at home but maybe not in production love the Rails core team for their amazing work
  • 149. Marco Schaden | @donschado | 23.08.2014RedFrog Conf kthxbye
  • 150. Marco Schaden | @donschado | 23.08.2014RedFrog Conf Marco @DonSchado - 17 Std.
 rackup -r rack/lobster -b 'run Rack::Lobster.new'
  • 151. Backup
  • 152. Appendix: Rack in the wild
  • 155. 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
  • 156. 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
  • 157. 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