SlideShare a Scribd company logo
1 of 82
Download to read offline
And the Greatest of These Is...
           Rack Support
            Ben Scofield – Viget Labs




Saturday, July 25, 2009
Saturday, July 25, 2009
Application Templates
Saturday, July 25, 2009
Nested Attribute Assignment
  flickr: angelrays


Saturday, July 25, 2009
ActiveRecord::Base#touch
  flickr: jjjohn


Saturday, July 25, 2009
DB Seeding
  flickr: richardthomas78


Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Rack


Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
def call(env)
       [
          status, # 200
          headers, # {"Content-Type" => "text/html"}
          body     # ["<html>...</html>"]
       ]
      end




Saturday, July 25, 2009
Saturday, July 25, 2009
request
                          application
                           response
Saturday, July 25, 2009
request
                             middleware

                          application
                             middleware

                           response
Saturday, July 25, 2009
Saturday, July 25, 2009
Rack::Profiler
  flickr: oberazzi


Saturday, July 25, 2009
Rack::MailExceptions
  flickr: warmnfuzzy


Saturday, July 25, 2009
Rack::Cache
  flickr: timpatterson


Saturday, July 25, 2009
rack::cascade

 Rack::Cascade
  flickr: _at


Saturday, July 25, 2009
Rack in Rails


Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
> rake middleware
      use Rack::Lock
      use ActionDispatch::ShowExceptions, [true]
      use ActionDispatch::Callbacks, [true]
      use ActionDispatch::Rescue, [#<Method: ...>]
      use ActionDispatch::Session::CookieStore, [{...}]
      use ActionDispatch::ParamsParser
      use Rack::MethodOverride
      use Rack::Head
      use ActiveRecord::ConnectionAdapters::ConnectionManagement
      use ActiveRecord::QueryCache
      run ActionController::Dispatcher.new




Saturday, July 25, 2009
> rake middleware
      use Rack::Lock
      use ActionDispatch::ShowExceptions, [true]
      use ActionDispatch::Callbacks, [true]
      use ActionDispatch::Rescue, [#<Method: ...>]
      use ActionDispatch::Session::CookieStore, [{...}]
      use ActionDispatch::ParamsParser
      use Rack::MethodOverride
      use Rack::Head
      use ActiveRecord::ConnectionAdapters::ConnectionManagement
      use ActiveRecord::QueryCache
      run ActionController::Dispatcher.new




Saturday, July 25, 2009
app = Rack::Builder.new {
        use Rails::Rack::LogTailer unless options[:detach]
        use Rails::Rack::Debugger if options[:debugger]

        map "/" do
          use Rails::Rack::Static
          run ActionController::Dispatcher.new
        end
      }.to_app




Saturday, July 25, 2009
Rails::Initializer.run do |config|
        config.middleware.insert_before Rack::Head, Ben::Asplode
        config.middleware.swap          Rack::Lock, Ben::Lock
        config.middleware.use            Rack::MailExceptions
      end




Saturday, July 25, 2009
# in config/initializers/middlewares.rb
      Rails::Initializer.run do |config|
        config.middleware.insert_before Rack::Head, Ben::Asplode
      ActionController::Dispatcher.middleware.insert_before 'Rack::Head', Appender
        config.middleware.swap          Rack::Lock, Ben::Lock
      ActionController::Dispatcher.middleware.delete 'Rack::Lock'
        config.middleware.use            Rack::MailExceptions
      ActionController::Dispatcher.middleware.use Prepender
      end




Saturday, July 25, 2009
Metal
  flickr: lrargerich


Saturday, July 25, 2009
http://www.kiwibean.com/



Saturday, July 25, 2009
Saturday, July 25, 2009
PLEASE testing metalBY
                             EXPAND:
                                     STAND
                          THIS IS ONLY A TEST


Saturday, July 25, 2009
Saturday, July 25, 2009
METAL
                           Sinatra

Saturday, July 25, 2009
Cool Tricks


Saturday, July 25, 2009
Rack::Bug
  flickr: catdancing


Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
requires
                          </body>
Saturday, July 25, 2009
Progressive Caching
Saturday, July 25, 2009
Progressive Caching
Saturday, July 25, 2009
Progressive Caching
Saturday, July 25, 2009
Saturday, July 25, 2009
class SessionsController < ApplicationController
        def create
          # ...
          session[:personalize] = {
            :logged_in => true,
            :quicklist => current_user.quicklist.episode_ids,
            :subscriptions => current_user.subscription_ids
          }
        end
      end




Saturday, July 25, 2009
class ChannelsController < ApplicationController
        caches_page :show

        def show
          @channel = Channel.find(params[:id])
        end
      end




Saturday, July 25, 2009
$(document).ready(function() {
        $.getJSON('/personalize', function(data) {

              // identify quicklisted episodes
              $.each(data['quicklist'], function() {
                $('#episode_'+this).addClass('listed');
              });

              // switch navigation
              if (data['logged_in']) {
                $('#logged_in_nav').show();
              }

          // etc.
        });
      });




Saturday, July 25, 2009
class Personalizer
        def self.call(env)
          if env["PATH_INFO"] =~ /^/personalize/
            [
               200,
              {"Content-Type" => "application/javascript"},
              env['rack.session'][:personalize].to_json
            ]
          else
            [404, {"Content-Type" => "text/html"}, ["Not Found"]]
          end
        end
      end




Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
class PullList
        def self.call(env)
          if env["PATH_INFO"] =~ /^/pulls/
            [
               200,
              {"Content-Type" => "application/javascript"},
              [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]]
          else
            [404, {"Content-Type" => "text/html"}, ["Not Found"]]
          end
        end
      end




             standard     0.617




       progressive        0.039 0.096




Saturday, July 25, 2009
class PullList
        def self.call(env)
          if env["PATH_INFO"] =~ /^/pulls/
            [
               200,
              {"Content-Type" => "application/javascript"},
              [env['rack.session'][:pulls].to_json]
            ]
          else
            [404, {"Content-Type" => "text/html"}, ["Not Found"]]
          end
        end
      end




             standard     0.617



       progressive        0.039 0.096



  progressive v2          0.043 0.023




Saturday, July 25, 2009
DIY


Saturday, July 25, 2009
request
                             middleware

                          application
                             middleware

                           response
Saturday, July 25, 2009
Rack::Embiggener
Saturday, July 25, 2009
Saturday, July 25, 2009
class Embiggener < Test::Unit::TestCase
        def test_embiggener_should_embiggen_known_url
          body = ["Hello! I'm at http://bit.ly/31IqMl"]
          assert_equal ["Hello! I'm at http://cnn.com"],
                         Rack:: Embiggener.embiggen_urls(body)
        end

          def test_embiggener_should_embiggen_multiple_urls
            body = [
              "Hello! I'm at http://bit.ly/31IqMl",
              "And I'm at http://bit.ly/31IqMl"
            ]

          assert_equal [
            "Hello! I'm at http://cnn.com",
            "And I'm at http://cnn.com"
          ], Rack::Embiggener.embiggen_urls(body)
        end
      end




Saturday, July 25, 2009
module Rack
        class Embiggener
          def self.embiggen_urls(original_body, login, key)
            new_body = []
            original_body.each { |line|
              bits = line.scan(/(http://bit.ly/(.{6}))/)

                          new_body << bits.uniq.inject(line) do |body, bit|
                            original_bit, hash = *bit
                            new_url = embiggened_url(hash, login, key)

                            body.gsub(original_bit, new_url) if new_url
                          end
                }
                new_body
              end

          # ...
        end
      end




Saturday, July 25, 2009
module Rack
        class Embiggener
          # ...

              def self.embiggened_url(hash, login, key)
                url = [
                  "http://api.bit.ly/expand?version=2.0.1",
                  "shortUrl=http://bit.ly/#{hash}", "login=#{login}", "apiKey=#{key}"
                ].join('&')
                response = JSON.parse(Net::HTTP.get_response(URI.parse(url)))

                if response['statusCode'] = 'OK'
                  embiggened_url = response['results'][hash]['longUrl']
                end
              end

          # ...
        end
      end




Saturday, July 25, 2009
module Rack
        class Embiggener
           # ...

              attr_accessor :api_login, :api_key

              def initialize(app, api_login, api_key)
                @app = app
                @api_login = api_login
                @api_key = api_key
              end

          def call(env)
            status, headers, body = @app.call(env)
            headers.delete('Content-Length')
            response = Rack::Response.new(
              Rack::Embiggener.embiggen_urls(body, api_login, api_hash),
              status,
              headers
            )
            response.finish
            return response.to_a
          end
        end
      end




Saturday, July 25, 2009
module Rack
        class Embiggener
          def self.embiggen_urls(original_body, login, key)
            new_body = []
            original_body.each { |line|
              bits = line.scan(/bit:(w+?)/)

                          new_body << bits.uniq.inject(line) do |body, bit|
                            hash = bit.first
                            original_bit = "bit:#{hash}"
                            new_url = embiggened_url(hash, login, key)

                            body.gsub(original_bit, new_url) if new_url
                          end
                   }
                   new_body

              end

          # ...
        end
      end




Saturday, July 25, 2009
module Rack
        class Embiggener
          # ...

              def self.embiggened_url(hash, login, key)
                url = [
                  "http://api.bit.ly/expand?version=2.0.1",
                  "hash=#{hash}", "login=#{login}", "apiKey=#{key}"
                ].join('&')
                response = JSON.parse(Net::HTTP.get_response(URI.parse(url)))

                if response['statusCode'] = 'OK'
                  embiggened_url = response['results'][hash]['longUrl']
                end
              end

          # ...
        end
      end




Saturday, July 25, 2009
WARNING       exception handling



Saturday, July 25, 2009
formerly:


            WARNING       exception handling



Saturday, July 25, 2009
Rack::Hoptoad*
  * unofficial; thoughtbot is not responsible for this middleware; do not taunt rack::hoptoad; pregnant women should consult their doctors before using rack::hoptoad


Saturday, July 25, 2009
Saturday, July 25, 2009
> rake middleware
      use Rack::Lock
      use ActionDispatch::ShowExceptions, [true]
      use ActionDispatch::Callbacks, [true]
      use ActionDispatch::Rescue, [#<Method: ...>]
      use ActionDispatch::Session::CookieStore, [{...}]
      use ActionDispatch::ParamsParser
      use Rack::MethodOverride
      use Rack::Head
      use ActiveRecord::ConnectionAdapters::ConnectionManagement
      use ActiveRecord::QueryCache
      run ActionController::Dispatcher.new




Saturday, July 25, 2009
ActionController::Dispatcher.middleware.delete ActionDispatch::ShowExceptions
      ActionController::Dispatcher.middleware.delete ActionDispatch::Rescue

      ActionController::Dispatcher.middleware.use   'Rack::Hoptoad', 'my-api-key'
      ActionController::Dispatcher.middleware.use   'Rack::ShowExceptions'




Saturday, July 25, 2009
module Rack
        class Hoptoad
          def initialize(app, api_key)
            @app = app
            @api_key = api_key
          end

              def call(env)
                @app.call(env)
              rescue => exception
                notify_hoptoad(exception, env)
                raise exception
              end

          # ...
        end
      end




Saturday, July 25, 2009
module Rack
        class Hoptoad
          def notify_hoptoad(exception, env)
            headers = {
              'Content-type' => 'application/x-yaml',
              'Accept' => 'text/xml, application/xml'
            }
            url = URI.parse("http://hoptoadapp.com/notices")

                   http = Net::HTTP.new(url.host, url.port)

                   data = {
                     :api_key         =>   @api_key,
                     :error_message   =>   "#{exception.class}: #{exception}",
                     :backtrace       =>   exception.backtrace,
                     :request         =>   {},
                     :session         =>   env['rack.session'],
                     :environment     =>   env
                   }

                   response = http.post(
                     url.path,
                     stringify_keys(:notice => data).to_yaml,
                     headers
                   )

            if response != Net::HTTPSuccess
              # Hoptoad post failed
            end
          end
        end
      end

Saturday, July 25, 2009
Saturday, July 25, 2009
Intangibles


Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Saturday, July 25, 2009
Thank You
         ben scofield - @bscofield - http://www.viget.com/extend - http://www.speakerrate.com/bscofield
Saturday, July 25, 2009

More Related Content

What's hot

Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)andrewnacin
 
jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creationbenalman
 
An introduction to Ember.js
An introduction to Ember.jsAn introduction to Ember.js
An introduction to Ember.jscodeofficer
 
JRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the CloudJRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the CloudHiro Asari
 
The DOM is a Mess @ Yahoo
The DOM is a Mess @ YahooThe DOM is a Mess @ Yahoo
The DOM is a Mess @ Yahoojeresig
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty HammerBen Scofield
 
And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...Codemotion
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkBen Scofield
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionPaul Irish
 
Writing Redis in Python with asyncio
Writing Redis in Python with asyncioWriting Redis in Python with asyncio
Writing Redis in Python with asyncioJames Saryerwinnie
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Kris Wallsmith
 
Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2nottings
 
SEMAC 2011 - Apresentando Ruby e Ruby on Rails
SEMAC 2011 - Apresentando Ruby e Ruby on RailsSEMAC 2011 - Apresentando Ruby e Ruby on Rails
SEMAC 2011 - Apresentando Ruby e Ruby on RailsFabio Akita
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developersAndrew Eddie
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010ikailan
 

What's hot (19)

Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creation
 
An introduction to Ember.js
An introduction to Ember.jsAn introduction to Ember.js
An introduction to Ember.js
 
JRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the CloudJRuby, Ruby, Rails and You on the Cloud
JRuby, Ruby, Rails and You on the Cloud
 
The DOM is a Mess @ Yahoo
The DOM is a Mess @ YahooThe DOM is a Mess @ Yahoo
The DOM is a Mess @ Yahoo
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty Hammer
 
And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & Compression
 
Symfony 2
Symfony 2Symfony 2
Symfony 2
 
Writing Redis in Python with asyncio
Writing Redis in Python with asyncioWriting Redis in Python with asyncio
Writing Redis in Python with asyncio
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)
 
Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2
 
SEMAC 2011 - Apresentando Ruby e Ruby on Rails
SEMAC 2011 - Apresentando Ruby e Ruby on RailsSEMAC 2011 - Apresentando Ruby e Ruby on Rails
SEMAC 2011 - Apresentando Ruby e Ruby on Rails
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developers
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010
 

Similar to And the Greatest of These Is ... Space

How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Rails For Kids 2009
Rails For Kids 2009Rails For Kids 2009
Rails For Kids 2009Fabio Akita
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy Kendall
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
StirTrek 2018 - Rapid API Development with Sails
StirTrek 2018 - Rapid API Development with SailsStirTrek 2018 - Rapid API Development with Sails
StirTrek 2018 - Rapid API Development with SailsJustin James
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2Kacper Gunia
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜崇之 清水
 
QConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebQConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebFabio Akita
 
Ruby: Beyond the Basics
Ruby: Beyond the BasicsRuby: Beyond the Basics
Ruby: Beyond the BasicsMichael Koby
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTPMustafa TURAN
 
#NewMeetup Performance
#NewMeetup Performance#NewMeetup Performance
#NewMeetup PerformanceJustin Cataldo
 
Beyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance JavascriptBeyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance Javascriptaglemann
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
SilverStripe CMS JavaScript Refactoring
SilverStripe CMS JavaScript RefactoringSilverStripe CMS JavaScript Refactoring
SilverStripe CMS JavaScript RefactoringIngo Schommer
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkJeremy Kendall
 

Similar to And the Greatest of These Is ... Space (20)

How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Rails For Kids 2009
Rails For Kids 2009Rails For Kids 2009
Rails For Kids 2009
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
StirTrek 2018 - Rapid API Development with Sails
StirTrek 2018 - Rapid API Development with SailsStirTrek 2018 - Rapid API Development with Sails
StirTrek 2018 - Rapid API Development with Sails
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
Elegant APIs
Elegant APIsElegant APIs
Elegant APIs
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
QConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebQConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações Web
 
Ruby: Beyond the Basics
Ruby: Beyond the BasicsRuby: Beyond the Basics
Ruby: Beyond the Basics
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
#NewMeetup Performance
#NewMeetup Performance#NewMeetup Performance
#NewMeetup Performance
 
Beyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance JavascriptBeyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance Javascript
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
SilverStripe CMS JavaScript Refactoring
SilverStripe CMS JavaScript RefactoringSilverStripe CMS JavaScript Refactoring
SilverStripe CMS JavaScript Refactoring
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 

More from Ben Scofield

How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsBen Scofield
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUGBen Scofield
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to ArmsBen Scofield
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and MasteryBen Scofield
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or MediocrityBen Scofield
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation AtlantaBen Scofield
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding MasteryBen Scofield
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the WebBen Scofield
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQLBen Scofield
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010Ben Scofield
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)Ben Scofield
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardBen Scofield
 
The Future of Data
The Future of DataThe Future of Data
The Future of DataBen Scofield
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardBen Scofield
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative DatabasesBen Scofield
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the WebBen Scofield
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the EarthBen Scofield
 
"Comics" Is Hard: Domain Modeling Challenges
"Comics" Is Hard: Domain Modeling Challenges"Comics" Is Hard: Domain Modeling Challenges
"Comics" Is Hard: Domain Modeling ChallengesBen Scofield
 

More from Ben Scofield (20)

How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 Steps
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
Thinking Small
Thinking SmallThinking Small
Thinking Small
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to Arms
 
Ship It
Ship ItShip It
Ship It
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and Mastery
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or Mediocrity
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation Atlanta
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding Mastery
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the Web
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQL
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is Hard
 
The Future of Data
The Future of DataThe Future of Data
The Future of Data
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is Hard
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the Web
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the Earth
 
"Comics" Is Hard: Domain Modeling Challenges
"Comics" Is Hard: Domain Modeling Challenges"Comics" Is Hard: Domain Modeling Challenges
"Comics" Is Hard: Domain Modeling Challenges
 

Recently uploaded

My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 

Recently uploaded (20)

My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 

And the Greatest of These Is ... Space

  • 1. And the Greatest of These Is... Rack Support Ben Scofield – Viget Labs Saturday, July 25, 2009
  • 4. Nested Attribute Assignment flickr: angelrays Saturday, July 25, 2009
  • 5. ActiveRecord::Base#touch flickr: jjjohn Saturday, July 25, 2009
  • 6. DB Seeding flickr: richardthomas78 Saturday, July 25, 2009
  • 12. def call(env) [ status, # 200 headers, # {"Content-Type" => "text/html"} body # ["<html>...</html>"] ] end Saturday, July 25, 2009
  • 14. request application response Saturday, July 25, 2009
  • 15. request middleware application middleware response Saturday, July 25, 2009
  • 17. Rack::Profiler flickr: oberazzi Saturday, July 25, 2009
  • 18. Rack::MailExceptions flickr: warmnfuzzy Saturday, July 25, 2009
  • 19. Rack::Cache flickr: timpatterson Saturday, July 25, 2009
  • 20. rack::cascade Rack::Cascade flickr: _at Saturday, July 25, 2009
  • 21. Rack in Rails Saturday, July 25, 2009
  • 25. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [true] use ActionDispatch::Rescue, [#<Method: ...>] use ActionDispatch::Session::CookieStore, [{...}] use ActionDispatch::ParamsParser use Rack::MethodOverride use Rack::Head use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache run ActionController::Dispatcher.new Saturday, July 25, 2009
  • 26. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [true] use ActionDispatch::Rescue, [#<Method: ...>] use ActionDispatch::Session::CookieStore, [{...}] use ActionDispatch::ParamsParser use Rack::MethodOverride use Rack::Head use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache run ActionController::Dispatcher.new Saturday, July 25, 2009
  • 27. app = Rack::Builder.new { use Rails::Rack::LogTailer unless options[:detach] use Rails::Rack::Debugger if options[:debugger] map "/" do use Rails::Rack::Static run ActionController::Dispatcher.new end }.to_app Saturday, July 25, 2009
  • 28. Rails::Initializer.run do |config| config.middleware.insert_before Rack::Head, Ben::Asplode config.middleware.swap Rack::Lock, Ben::Lock config.middleware.use Rack::MailExceptions end Saturday, July 25, 2009
  • 29. # in config/initializers/middlewares.rb Rails::Initializer.run do |config| config.middleware.insert_before Rack::Head, Ben::Asplode ActionController::Dispatcher.middleware.insert_before 'Rack::Head', Appender config.middleware.swap Rack::Lock, Ben::Lock ActionController::Dispatcher.middleware.delete 'Rack::Lock' config.middleware.use Rack::MailExceptions ActionController::Dispatcher.middleware.use Prepender end Saturday, July 25, 2009
  • 30. Metal flickr: lrargerich Saturday, July 25, 2009
  • 33. PLEASE testing metalBY EXPAND: STAND THIS IS ONLY A TEST Saturday, July 25, 2009
  • 35. METAL Sinatra Saturday, July 25, 2009
  • 37. Rack::Bug flickr: catdancing Saturday, July 25, 2009
  • 42. requires </body> Saturday, July 25, 2009
  • 47. class SessionsController < ApplicationController def create # ... session[:personalize] = { :logged_in => true, :quicklist => current_user.quicklist.episode_ids, :subscriptions => current_user.subscription_ids } end end Saturday, July 25, 2009
  • 48. class ChannelsController < ApplicationController caches_page :show def show @channel = Channel.find(params[:id]) end end Saturday, July 25, 2009
  • 49. $(document).ready(function() { $.getJSON('/personalize', function(data) { // identify quicklisted episodes $.each(data['quicklist'], function() { $('#episode_'+this).addClass('listed'); }); // switch navigation if (data['logged_in']) { $('#logged_in_nav').show(); } // etc. }); }); Saturday, July 25, 2009
  • 50. class Personalizer def self.call(env) if env["PATH_INFO"] =~ /^/personalize/ [ 200, {"Content-Type" => "application/javascript"}, env['rack.session'][:personalize].to_json ] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end Saturday, July 25, 2009
  • 55. class PullList def self.call(env) if env["PATH_INFO"] =~ /^/pulls/ [ 200, {"Content-Type" => "application/javascript"}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end standard 0.617 progressive 0.039 0.096 Saturday, July 25, 2009
  • 56. class PullList def self.call(env) if env["PATH_INFO"] =~ /^/pulls/ [ 200, {"Content-Type" => "application/javascript"}, [env['rack.session'][:pulls].to_json] ] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end standard 0.617 progressive 0.039 0.096 progressive v2 0.043 0.023 Saturday, July 25, 2009
  • 58. request middleware application middleware response Saturday, July 25, 2009
  • 61. class Embiggener < Test::Unit::TestCase def test_embiggener_should_embiggen_known_url body = ["Hello! I'm at http://bit.ly/31IqMl"] assert_equal ["Hello! I'm at http://cnn.com"], Rack:: Embiggener.embiggen_urls(body) end def test_embiggener_should_embiggen_multiple_urls body = [ "Hello! I'm at http://bit.ly/31IqMl", "And I'm at http://bit.ly/31IqMl" ] assert_equal [ "Hello! I'm at http://cnn.com", "And I'm at http://cnn.com" ], Rack::Embiggener.embiggen_urls(body) end end Saturday, July 25, 2009
  • 62. module Rack class Embiggener def self.embiggen_urls(original_body, login, key) new_body = [] original_body.each { |line| bits = line.scan(/(http://bit.ly/(.{6}))/) new_body << bits.uniq.inject(line) do |body, bit| original_bit, hash = *bit new_url = embiggened_url(hash, login, key) body.gsub(original_bit, new_url) if new_url end } new_body end # ... end end Saturday, July 25, 2009
  • 63. module Rack class Embiggener # ... def self.embiggened_url(hash, login, key) url = [ "http://api.bit.ly/expand?version=2.0.1", "shortUrl=http://bit.ly/#{hash}", "login=#{login}", "apiKey=#{key}" ].join('&') response = JSON.parse(Net::HTTP.get_response(URI.parse(url))) if response['statusCode'] = 'OK' embiggened_url = response['results'][hash]['longUrl'] end end # ... end end Saturday, July 25, 2009
  • 64. module Rack class Embiggener # ... attr_accessor :api_login, :api_key def initialize(app, api_login, api_key) @app = app @api_login = api_login @api_key = api_key end def call(env) status, headers, body = @app.call(env) headers.delete('Content-Length') response = Rack::Response.new( Rack::Embiggener.embiggen_urls(body, api_login, api_hash), status, headers ) response.finish return response.to_a end end end Saturday, July 25, 2009
  • 65. module Rack class Embiggener def self.embiggen_urls(original_body, login, key) new_body = [] original_body.each { |line| bits = line.scan(/bit:(w+?)/) new_body << bits.uniq.inject(line) do |body, bit| hash = bit.first original_bit = "bit:#{hash}" new_url = embiggened_url(hash, login, key) body.gsub(original_bit, new_url) if new_url end } new_body end # ... end end Saturday, July 25, 2009
  • 66. module Rack class Embiggener # ... def self.embiggened_url(hash, login, key) url = [ "http://api.bit.ly/expand?version=2.0.1", "hash=#{hash}", "login=#{login}", "apiKey=#{key}" ].join('&') response = JSON.parse(Net::HTTP.get_response(URI.parse(url))) if response['statusCode'] = 'OK' embiggened_url = response['results'][hash]['longUrl'] end end # ... end end Saturday, July 25, 2009
  • 67. WARNING exception handling Saturday, July 25, 2009
  • 68. formerly: WARNING exception handling Saturday, July 25, 2009
  • 69. Rack::Hoptoad* * unofficial; thoughtbot is not responsible for this middleware; do not taunt rack::hoptoad; pregnant women should consult their doctors before using rack::hoptoad Saturday, July 25, 2009
  • 71. > rake middleware use Rack::Lock use ActionDispatch::ShowExceptions, [true] use ActionDispatch::Callbacks, [true] use ActionDispatch::Rescue, [#<Method: ...>] use ActionDispatch::Session::CookieStore, [{...}] use ActionDispatch::ParamsParser use Rack::MethodOverride use Rack::Head use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache run ActionController::Dispatcher.new Saturday, July 25, 2009
  • 72. ActionController::Dispatcher.middleware.delete ActionDispatch::ShowExceptions ActionController::Dispatcher.middleware.delete ActionDispatch::Rescue ActionController::Dispatcher.middleware.use 'Rack::Hoptoad', 'my-api-key' ActionController::Dispatcher.middleware.use 'Rack::ShowExceptions' Saturday, July 25, 2009
  • 73. module Rack class Hoptoad def initialize(app, api_key) @app = app @api_key = api_key end def call(env) @app.call(env) rescue => exception notify_hoptoad(exception, env) raise exception end # ... end end Saturday, July 25, 2009
  • 74. module Rack class Hoptoad def notify_hoptoad(exception, env) headers = { 'Content-type' => 'application/x-yaml', 'Accept' => 'text/xml, application/xml' } url = URI.parse("http://hoptoadapp.com/notices") http = Net::HTTP.new(url.host, url.port) data = { :api_key => @api_key, :error_message => "#{exception.class}: #{exception}", :backtrace => exception.backtrace, :request => {}, :session => env['rack.session'], :environment => env } response = http.post( url.path, stringify_keys(:notice => data).to_yaml, headers ) if response != Net::HTTPSuccess # Hoptoad post failed end end end end Saturday, July 25, 2009
  • 82. Thank You ben scofield - @bscofield - http://www.viget.com/extend - http://www.speakerrate.com/bscofield Saturday, July 25, 2009