ruby mvc from scratch with rack

Post on 19-May-2015

801 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Imagine for a while that Rails wouldn't exist. How would we write a MVC app from scratch? Rack provides a minimal interface for developing web applications in Ruby. In fact it's the solid foundation of all major Ruby powered web frameworks. During this talk we will dive deep into Rack. We will see the smallest possible Rack Application and learn how it works, by studying Rack internals. We will grow the Application step by step till we implement it in simple MVC style.

TRANSCRIPT

Ruby MVC from scratch with Rack

I

Marco Schaden | @donschado | 23.08.2014RedFrog Conf

there was a rack applicationhandling 10.000+ req/sec

once upon a time

http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html

DISCLAIMER

no live coding: but we write and refactor a lot of code!

simple codez: examples try to be more obvious than "SOLID"!• a newbie will learn some cool tricks!• a pro will find a lot to complain ;)!

!seriously: this presentation contains all the memes, sorry

Rack is the foundation of all modern Ruby web frameworks

http://chneukirchen.org/talks/euruko-2007/neukirchen07introducingrack.pdf

http://chneukirchen.org/talks/euruko-2007/neukirchen07introducingrack.pdf

• specification!• implementation!• minimal abstract API for HTTP!• Request: CGI environment!• Response: status, headers, body

common interface between

server and application

Write once, run "everywhere"

WEBrick!Thin!Puma!

Unicorn!Passenger!

Torqbox / Torquebox!Trinidad!Mongrel!

Pow!CGI!SCGI!

FastCGI!Ebb!

Fuzed!Litespeed!

RackApp

+call(env)

A rack application is any Ruby object that responds to call. !!

It takes the environment hash as argument!and returns an array of exactly three values: !

the status, the headers and the body*!!

*which must respond to each

<<"show"me"the"code">>

! ->(env) { }

! ->(env) { }[ ]

! ->(env) { }[ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']

! ->(env) { }

*run means "call that object for each request"

run [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']

! ->(env) { }

*run means "call that object for each request"

# config.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']

! ->(env) { }

$ rackup

127.0.0.1 - - [23/Aug/2014 10:50:07] "GET / HTTP/1.1" 200 - 0.0007

[2014-08-23 10:50:00] INFO WEBrick 1.3.1[2014-08-23 10:50:00] INFO ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0][2014-08-23 10:50:00] INFO WEBrick::HTTPServer#start: pid=11802 port=9292

*run means "call that object for each request"

# config.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']

! ->(env) { }

$ rackup

127.0.0.1 - - [23/Aug/2014 10:50:07] "GET / HTTP/1.1" 200 - 0.0007

[2014-08-23 10:50:00] INFO WEBrick 1.3.1[2014-08-23 10:50:00] INFO ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0][2014-08-23 10:50:00] INFO WEBrick::HTTPServer#start: pid=11802 port=9292

*run means "call that object for each request"

SHIP IT

# config.rurun [ ]200, {'Content-Type' => 'text/html'}, ['Hello World!']

, read it: https://github.com/rack/rack

How does it work?

seriously

HTML + ERB

# config.rurun -> e { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }

# config.rurun -> e { Rack::Response.new('Hello World!') }

# config.rurun -> e { Rack::Response.new(view) }

# config.ru!!!!!!!!!!!!!!!!run -> e { Rack::Response.new(view) }

view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with HTML</title> </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html>HTML

# config.ru!!!!!!!!!!!!!!!!run -> e { Rack::Response.new(view) }

require 'erb'

view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html>HTML

ERB</title>

<h1>Current time: <%= Time.now %></h1>

# config.ru!!!!!!!!!!!!!!!!run -> e { Rack::Response.new(view) }

require 'erb'

view = <<-HTML <!DOCTYPE html> <html> <head> <title>Rack with </head> <body> <div> <h1>Hello World!</h1> </div> </body> </html>HTML

ERB</title>

<h1>Current time: <%= Time.now %></h1>

ERB.new(view).result) }

Current time: 2014-08-23 10:54:29 +0200

</introduction>

MVC

froscon-rack-mvc

frack-mvc

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

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

source "https://rubygems.org"!gem 'rack'gem 'thin'gem 'tilt'

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

<html> <head> <title>Frack MVC</title> </head> <body> <h1>application#layout</h1> <%= yield %> </body></html>

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

<h2>users#index</h2>

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) # Your code goes here... end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

*use adds a middleware to the rack application stack created by Rack::Builder.

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

Rack::Response.new(env)

*use adds a middleware to the rack application stack created by Rack::Builder.

["SERVER_SOFTWARE",."thin.1.6.2.codename.Doc.Brown"]["SERVER_NAME",."localhost"]["rack.input",.#<Rack::Lint::InputWrapper:0x007fc0421e1ea0.@input=#<StringIO:0x007fc0421fb940>>]["rack.version",.[1,.0]]["rack.errors",.#<Rack::Lint::ErrorWrapper:0x007fc0421e1cc0.@error=#<IO:<STDERR>>>]["rack.multithread",.false]["rack.multiprocess",.false]["rack.run_once",.false]["REQUEST_METHOD",."GET"]["REQUEST_PATH",."/"]["PATH_INFO",."/"]["REQUEST_URI",."/"]["HTTP_VERSION",."HTTP/1.1"]["HTTP_USER_AGENT",."curl/7.30.0"]["HTTP_HOST",."localhost:9292"]["HTTP_ACCEPT",."*/*"]["GATEWAY_INTERFACE",."CGI/1.2"]["SERVER_PORT",."9292"]["QUERY_STRING",.""]["SERVER_PROTOCOL",."HTTP/1.1"]["rack.url_scheme",."http"]["SCRIPT_NAME",.""]["REMOTE_ADDR",."127.0.0.1"]["async.callback",.#<Method:.Thin::Connection#post_process>]["async.close",.#<EventMachine::DefaultDeferrable:0x007fc0421fab08>]

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

env

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

def render(view)

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

def render(view)render_template('layouts/application') do

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

def render(view)render_template('layouts/application') do

render_template(view)end

end

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

def render(view)render_template('layouts/application') do

render_template(view)end

end

def render_template(path, &block)

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! !!!!!

def render(view)render_template('layouts/application') do

render_template(view)end

end

def render_template(path, &block)Tilt.new("app/views/#{path}.html.erb").render(&block)

end

render 'users/index'

end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

application#layout!!users#index

application#layout!!users#index

but can I haz style?

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

def render(view) render_template('layouts/application') do render_template(view) end end

def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end

render 'users/index'

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

def render(view) render_template('layouts/application') do render_template(view) end end

def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end

render 'users/index'

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

#$ public" #$ css" " &$ style.css" #$ images" &$ js

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

html { font-family: sans-serif; }h1 { color: #008040; }h2 { color: #ff0080; }

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

<html> <head> <title>Frack MVC</title>! </head> <body> <h1>application#layout</h1> <%= yield %> </body></html>

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

<html> <head> <title>Frack MVC</title>! </head> <body> <h1>application#layout</h1> <%= yield %> </body></html>

<link rel="stylesheet" type="text/css" href="css/style.css">

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

def render(view) render_template('layouts/application') do render_template(view) end end

def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end

render 'users/index'

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new(render 'users/index') end end endend!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) Rack::Response.new( ) end!!!!!!!!!! end endend!!use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

def render(view) render_template('layouts/application') do render_template(view) end end

def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(&block) end

render 'users/index'

use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']

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

application#layout !users#index

application#layout !users#index

what about simple routing?

and list some users?

["SERVER_SOFTWARE",."thin.1.6.2.codename.Doc.Brown"]["SERVER_NAME",."localhost"]["rack.input",.#<Rack::Lint::InputWrapper:0x007fc0421e1ea0.@input=#<StringIO:0x007fc0421fb940>>]["rack.version",.[1,.0]]["rack.errors",.#<Rack::Lint::ErrorWrapper:0x007fc0421e1cc0.@error=#<IO:<STDERR>>>]["rack.multithread",.false]["rack.multiprocess",.false]["rack.run_once",.false]["REQUEST_METHOD",."GET"]["REQUEST_PATH",""/"]["PATH_INFO",""/"]["REQUEST_URI",."/"]["HTTP_VERSION",."HTTP/1.1"]["HTTP_USER_AGENT",."curl/7.30.0"]["HTTP_HOST",."localhost:9292"]["HTTP_ACCEPT",."*/*"]["GATEWAY_INTERFACE",."CGI/1.2"]["SERVER_PORT",."9292"]["QUERY_STRING",.""]["SERVER_PROTOCOL",."HTTP/1.1"]["rack.url_scheme",."http"]["SCRIPT_NAME",.""]["REMOTE_ADDR",."127.0.0.1"]["async.callback",.#<Method:.Thin::Connection#post_process>]["async.close",.#<EventMachine::DefaultDeferrable:0x007fc0421fab08>]

remember env?

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

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

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

if env['PATH_INFO'] == '/'

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

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

if env['PATH_INFO'] == '/'

elseRack::Response.new('Not found', 404)

end

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

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

if env['PATH_INFO'] == '/'

else Rack::Response.new('Not found', 404)end

&block)

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

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

if env['PATH_INFO'] == '/'

else Rack::Response.new('Not found', 404)end

@users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne']

&block)

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

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

if env['PATH_INFO'] == '/'

else Rack::Response.new('Not found', 404)end

@users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne']

&block)self,

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

<h2>users#index</h2>!!!!!

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

<h2>users#index</h2>!!!!!

<ul><% @users.each do |user| %>

<li><%= user %></li><% end %>

</ul>

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

not sure if MVC…

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' !!!!! def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

render 'users/index')@users = ['Anthony Stark', 'Peter Parker', 'Bruce Wayne']

Rack::Response.new( else Rack::Response.new('Not found', 404) end end

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' !!!!! def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

Rack::Response.new( else Rack::Response.new('Not found', 404) end end

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

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' !!!!! def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

Rack::Response.new( else Rack::Response.new('Not found', 404) end end

UsersController.new.index)

$LOAD_PATH << '.'require 'rack'require 'tilt'!module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end!!!!!!!!!!!! endend!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

endend

class BaseControllerdef render(view) render_template('layouts/application') do render_template(view) endend!def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block)end

Rack::Response.new('Not found', 404) end end end end! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end endend!!!!!!!!!!!!!!!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

class UsersController < Frack::BaseControllerdef index

@users = User.allrender 'users/index'

endend

Rack::Response.new('Not found', 404) end end end end! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end endend!!!!!!!!!!!!!!!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

class UsersController < Frack::BaseControllerdef index

@users = User.allrender 'users/index'

endend

class Userdef self.all

['Anthony Stark', 'Peter Parker', 'Bruce Wayne']end

end

PROVE IT!

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

#$ spec" #$ integration" " &$ user_spec.rb" &$ spec_helper.rb&$ config.ru

require 'spec_helper'!Capybara.app = Rack::Builder.new do eval(File.read(File.expand_path('./config.ru')))end!!!!!!!!!!!!!!!!!!

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

#$ spec" #$ integration" " &$ user_spec.rb" &$ spec_helper.rb&$ config.ru

require 'spec_helper'!Capybara.app = Rack::Builder.new do eval(File.read(File.expand_path('./config.ru')))end!!!!!!!!!!!!!!!!!!

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

#$ spec" #$ integration" " &$ user_spec.rb" &$ spec_helper.rb

describe 'users#index' dobefore { visit '/' }

it 'renders layout' doexpect(page).to have_content('application#layout')

end

it 'renders index view' doexpect(page).to have_content('users#index')

end

it 'shows a list of users' doexpect(page).to have_selector('li',text: /Stark|Parker|Wayne/, count: 3)

endend

&$ config.ru

$ rspec!users#index renders layout renders index view shows a list of users!Finished in 0.02326 seconds 3 examples, 0 failures!Randomized with seed 13626

module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end endend!class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend!class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

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

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

module Frack class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end! class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end endend!class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend!class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

REFACTOR ALL THE FRACK

!"  &$ views"   #$ layouts"   "  &$ application.html.erb"   &$ users"   &$ index.html.erb#$ public"  #$ css" " &$ style.css"  #$ images"  &$ js#$ spec"  #$ integration"  " &$ user_spec.rb"  &$ spec_helper.rb&$ config.ru

frack-mvc"#$ Gemfile#$ app

" #$ controllers" " &$ users_controller.rb" #$ models" " &$ user.rb

#$ lib" #$ frack" " #$ application.rb" " #$ base_controller.rb" " &$ router.rb" &$ frack.rb

!"  &$ views"   #$ layouts"   "  &$ application.html.erb"   &$ users"   &$ index.html.erb

#$ public"  #$ css" " &$ style.css"  #$ images"  &$ js#$ spec"  #$ integration"  " &$ user_spec.rb"  &$ spec_helper.rb&$ config.ru

frack-mvc"#$ Gemfile#$ app

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

require 'app/controllers/users_controller'

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

require 'app/models/user'require 'app/controllers/users_controller'

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

require 'app/models/user'require 'app/controllers/users_controller'require 'lib/frack'

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

require 'app/models/user'require 'app/controllers/users_controller'require 'lib/frack'

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class UsersController < Frack::BaseController def index @users = User.all render 'users/index' endend

class User def self.all ['Anthony Stark', 'Peter Parker', 'Bruce Wayne'] endend

require 'app/models/user'require 'app/controllers/users_controller'require 'lib/frack'

module Frack!! !!!!!!!!!!!!!!!!!!!!end

class Application class << self def call(env) if env['PATH_INFO'] == '/' Rack::Response.new(UsersController.new.index) else Rack::Response.new('Not found', 404) end end end end

class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new("app/views/#{path}.html.erb").render(self, &block) end end

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

$LOAD_PATH << '.'!require 'lib/frack'require 'app/controllers/users_controller'require 'app/models/user'!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLengthrun Frack::Application

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

$LOAD_PATH << File.expand_path(File.dirname(__FILE__))!require 'rack'require 'tilt'!module Frack autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller'end

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

"app/views/#{ }.html. ).render(self, &block)

endend

erb"path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

"app/views/#{ }.html. ).render(self, &block)

endend

*"path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

file( )path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

def file(path)Dir[ ]

end

file( )path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

def file(path)Dir[ ]

endFile.join('app', 'views', "#{path}.html.*")

file( )path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

def file(path)Dir[ ]

endFile.join('app', 'views', "#{path}.html.*") .first

file( )path

module Frack class BaseController def render(view) render_template('layouts/application') do render_template(view) end end! def render_template(path, &block) Tilt.new( end!!!!!

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

).render(self, &block)

endend

def file(path)Dir[ ]

endFile.join('app', 'views', "#{path}.html.*") .first

file( )path

AWESOME!support all the template engines

better routing?magic?

MVC

What if the router could be middleware?

Middleware Stack

*a middleware is a rack application that wraps up an inner application.

Middleware Stack

HT

TP

requ

est

*a middleware is a rack application that wraps up an inner application.

Middleware Stack

use Rack::Static

use Rack::CommonLogger

use Rack::ContentLength

run Frack::Application

HT

TP

requ

est

*a middleware is a rack application that wraps up an inner application.

Middleware Stack

use Rack::Static

use Rack::CommonLogger

use Rack::ContentLength

run Frack::Application

HT

TP

requ

est

HT

TP

resp

onse

*a middleware is a rack application that wraps up an inner application.

Middleware Stack

use Rack::Static

use Rack::CommonLogger

use Rack::ContentLength

run Frack::Application

HT

TP

requ

est

HT

TP

resp

onse

module Rack class ContentLength def initialize(app) @app = app end! def call(env) status, headers, body = @app.call(env) # [...] # headers['Content-Length'] = length.to_s # [...] [status, headers, body] end endend

*a middleware is a rack application that wraps up an inner application.

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

$LOAD_PATH << '.'!require 'lib/frack'require 'app/controllers/users_controller'require 'app/models/user'!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLength!run Frack::Application

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

$LOAD_PATH << '.'!require 'lib/frack'require 'app/controllers/users_controller'require 'app/models/user'!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLength!run Frack::Applicationuse Frack::Router

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

$LOAD_PATH << File.expand_path(File.dirname(__FILE__))!require 'rack'require 'tilt'!module Frack! autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller'end

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

$LOAD_PATH << File.expand_path(File.dirname(__FILE__))!require 'rack'require 'tilt'!module Frack! autoload :Application, 'frack/application' autoload :BaseController, 'frack/base_controller'end

autoload :Router, 'frack/router'

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

module Frack class Router attr_reader :app! def initialize(app) @app = app end! def call(env) app.call(env) end endend

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

app.call(env)

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

ROUTES = {'/' =>

}

app.call(env)

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

ROUTES = {'/' =>

}

app.call(env)

{ 'controller' => 'users', 'action' => 'index' },

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

if (mapping = ROUTES[env['PATH_INFO']])

ROUTES = {'/' =>

}

app.call(env)

{ 'controller' => 'users', 'action' => 'index' },

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

if (mapping = ROUTES[env['PATH_INFO']])env.merge!(mapping)

ROUTES = {'/' =>

}

app.call(env)

{ 'controller' => 'users', 'action' => 'index' },

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

if (mapping = ROUTES[env['PATH_INFO']])env.merge!(mapping)

elseRack::Response.new('Not found', 404)

end

ROUTES = {'/' =>

}

app.call(env)

{ 'controller' => 'users', 'action' => 'index' },

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end endend

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

if (mapping = ROUTES[env['PATH_INFO']])env.merge!(mapping)

elseRack::Response.new('Not found', 404)

end

ROUTES = {'/' =>

}

app.call(env)

'users#index'

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend

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

if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = { '/' => }

app.call(env)

'users#index'

mapping)

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend

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

if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = { '/' => }

app.call(env)

'users#index'

def controller_action(mapping)

mapping)

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend

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

if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = { '/' => }

app.call(env)

'users#index'

def controller_action(mapping)

controller_action( )mapping)

module Frack class Router attr_reader :app!!!!! def initialize(app) @app = app end! def call(env) !!!!! end!!!! endend

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

if (mapping = ROUTES[env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = { '/' => }

app.call(env)

'users#index'

def controller_action(mapping)Hash[ %w(controller action).zip mapping.split('#') ]

end

controller_action( )mapping)

module Frack class Application class << self!! !! !!!!!!!!!

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

if env['PATH_INFO'] == '/'

elseRack::Response.new('Not found', 404)

end

UsersController.new.index)Rack::Response.new(

end endend

def call(env)

end

module Frack class Application class << self!! !! !!!!!!!!!

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

UsersController.new.index)Rack::Response.new(

end endend

def call(env)

end

module Frack class Application class << self!! !! !!!!!!!!!

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

Rack::Response.new(

end endend

def call(env)

end

module Frack class Application class << self!! !! !!!!!!!!!

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

*dispatch)Rack::Response.new(

end endend

def call(env)

end

module Frack class Application class << self!! !! !!!!!!!!!

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

*dispatch)Rack::Response.new(

end endend

def call(env)

attr_accessor :env

self.env = env

end

module Frack class Application class << self!! !! !!!!!!!!!

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

*dispatch)Rack::Response.new(

end endend

def call(env)

attr_accessor :env

self.env = env

end

def dispatchcontroller.new.public_send(env['action'])

end

module Frack class Application class << self!! !! !!!!!!!!!

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

*dispatch)Rack::Response.new(

end endend

def call(env)

attr_accessor :env

self.env = env

end

def dispatchcontroller.new.public_send(env['action'])

end

def controller

module Frack class Application class << self!! !! !!!!!!!!!

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

*dispatch)Rack::Response.new(

end endend

def call(env)

attr_accessor :env

self.env = env

end

def dispatchcontroller.new.public_send(env['action'])

end

def controllerObject.const_get(env['controller'].capitalize + 'Controller')

end

What if the router could take a block?

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

$LOAD_PATH << '.'!require 'lib/frack'require 'app/controllers/users_controller'require 'app/models/user'!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLength!!!!

use Frack::Routerrun Frack::Application

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

$LOAD_PATH << '.'!require 'lib/frack'require 'app/controllers/users_controller'require 'app/models/user'!use Rack::Static, root: 'public', urls: ['/images', '/js', '/css']use Rack::CommonLoggeruse Rack::ContentLength!!!!

use Frack::Router domatch '/' => 'users#index'

end

run Frack::Application

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = {'/' =>

}

app.call(env)

'users#index'

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

def initialize(app) @app = app

endend

ROUTES

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

ROUTES = {'/' =>

}

app.call(env)

'users#index'

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

def initialize(app) @app = app

endend

ROUTES

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

routes

def initialize(app) @app = app

endend

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

routes

def initialize(app) @app = app

endend

, &block)

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

@routes = {}

routes

def initialize(app) @app = app

endend

, &block)

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

@routes = {}instance_eval(&block) if block_given?

routes

def initialize(app) @app = app

endend

, &block)

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

@routes = {}instance_eval(&block) if block_given?

routes

def match(route)

def initialize(app) @app = app

endend

, &block)

module Frack class Router attr_reader :app!!!!!!! end! def call(env) !!!!! end!!!!!!!!!

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

if (mapping = [env['PATH_INFO']]) env.merge!( else Rack::Response.new('Not found', 404) end

app.call(env)

def controller_action(mapping) Hash[ %w(controller action).zip mapping.split('#') ] end

controller_action( )mapping)

, :routes

@routes = {}instance_eval(&block) if block_given?

routes

def match(route)self.routes.merge!(route)

end

def initialize(app) @app = app

endend

, &block)

in ~ 50-100 LOCMVC

I haven't shown you all of it

Challenges for the curious ones: !• params!• redirect_to!• partial rendering!• implicit call to render!• routing with placeholders!• routing with specific http verbs!• error handling!• session management!• flash messages!• persistence!• security stuff and protection!• different mime types!• url helper!• better class loading / autoloading!• asset management

Rebuilding Rails features, is a great opportunity to learn how they work.

yes, you should definitely do this at home

but maybe not in production

love the Rails core team for their amazing work

2014.RailsCamp.de

Marco Schaden | @donschado | 23.08.2014RedFrog Conf

kthxbye

Marco Schaden | @donschado | 23.08.2014RedFrog Conf

Marco @DonSchado - 17 Std.rackup -r rack/lobster -b 'run Rack::Lobster.new'

Backup

Appendix: Rack in the wild

http

://gu

ides

.ruby

onra

ils.o

rg/ra

ils_o

n_ra

ck.ht

ml

\m/ActionController ::Metal

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

*returns a valid Rack application for the Rails router to dispatch to

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

OMG WHY?

*returns a valid Rack application for the Rails router to dispatch to

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

• maybe to extract lightweight micro services

OMG WHY?

*returns a valid Rack application for the Rails router to dispatch to

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

• maybe to extract lightweight micro services • to improve the performance of any API endpoint

OMG WHY?

*returns a valid Rack application for the Rails router to dispatch to

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

• maybe to extract lightweight micro services • to improve the performance of any API endpoint• because all benefits of rails are "just a few" includes away

OMG WHY?

*returns a valid Rack application for the Rails router to dispatch to

http://api.rubyonrails.org/classes/ActionController/Metal.html

class HelloController < ActionController::Metal def index self.response_body = "Hello World!" endend

get 'hello', to: HelloController.action(:index)

• maybe to extract lightweight micro services • to improve the performance of any API endpoint• because all benefits of rails are "just a few" includes away

OMG WHY?

*returns a valid Rack application for the Rails router to dispatch to

class HelloController < ActionController::Metal include AbstractController::Rendering include ActionView::Layouts append_view_path "#{Rails.root}/app/views"! def index render "hello/index" end! # Ensure ActiveSupport::Notifications events are fired include ActionController::Instrumentationend

Backup Backup

http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html

"every possible rack server on every possible Ruby, every possible web framework"

Spoiler Alert!

"The fastest framework is Rack. !Plain old Rack with no framework at all."

Spoiler Alert!

"The fastest framework is Rack. !Plain old Rack with no framework at all."

Ruby 2.1 + Thin + Rack can hit 6301 req/sec

Spoiler Alert!

"The fastest framework is Rack. !Plain old Rack with no framework at all."

Ruby 2.1 + Thin + Rack can hit 6301 req/sec=> Sinatra only manages !! ! 2505 req/sec.

Spoiler Alert!

"The fastest framework is Rack. !Plain old Rack with no framework at all."

Ruby 2.1 + Thin + Rack can hit 6301 req/sec=> Sinatra only manages !! ! 2505 req/sec.=> Rails only does ! ! ! ! 1455 req/sec

Spoiler Alert!

"The fastest framework is Rack. !Plain old Rack with no framework at all."

Ruby 2.1 + Thin + Rack can hit 6301 req/sec=> Sinatra only manages !! ! 2505 req/sec.=> Rails only does ! ! ! ! 1455 req/sec

"So, by simply using those frameworks on top of Rack, you give up over 60% of your maximum possible throughput."

Spoiler Alert!

Spoiler spoiler Alert!

"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"

Spoiler spoiler Alert!

"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"

the fastest:

Spoiler spoiler Alert!

+

"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"

the fastest:

Spoiler spoiler Alert!

On a plain old Rack app it did 10.159 req/sec.

+

"Standard Ruby + Thin/Unicorn + Rails !is about the slowest possible combination"

the fastest:

*I think these benchmarks are a little bit unfair, !when you compare a full rails stack vs. a rack one-liner.!

But I think the main message is valid:!Do you need the full stack for every request?

Logging

Sessions

Cookies

Security

Caching

Error Handling

Routing

# hello_world.rbrequire 'rack'!!!!!!!!

app = Rack::Builder.new do !!!end

$ ruby hello_world.rb

# config.rurun ->(env) { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }

$ rackup

map '/' do! end

Rack::Handler::WEBrick.run app, :Port => 9292

run ->(env) { [200, {'Content-Type' => 'text/html'}, ['Hello World!']] }

use Rack::CommonLogger

$ ruby -r rack -e 'Rack::Handler::Thin.run lambda { |env| [200, {}, ["ok"]] }'

$ rackup -b 'run proc { [200, {}, [Time.now.to_s]] }'

for the curious:

that’s all

top related