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

The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 

Recently uploaded (20)

The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 

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