Skip to content

Instantly share code, notes, and snippets.

@ismasan
Created October 14, 2009 18:54
Show Gist options
  • Save ismasan/210314 to your computer and use it in GitHub Desktop.
Save ismasan/210314 to your computer and use it in GitHub Desktop.
# USAGE ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# require 'rack/versioner'
# V1 = Proc.new do |env|
# body = "Hello world from V1"
# [200, {"Content-Type" => "text/html", "Content-Length" => body.size.to_s}, [body]]
# end
#
# V2 = Proc.new do |env|
# body = "Hello world from V2"
# [200, {"Content-Type" => "text/html", "Content-Length" => body.size.to_s}, [body]]
# end
#
# api = Rack::Versioner.build(:namespace => '/api', :author => 'Ismael Celis') do |m|
# m.version 'v1', V1
# m.version 'v2', V2
# m.current 'v1'
# end
#
# run api
#
# This gives you
# /api/v1
# /api/v2
# /api/current => same as v1
#
module Rack
module Versioner
def self.build(options = {}, &block)
namespace = options.fetch(:namespace, '/api')
author = options[:author]
builder = Rack::Builder.new
versioner = Rack::Versioner::Map.new
yield versioner
versioner.versions.each do |num, app|
builder.map "#{namespace}/#{num}" do
use Headers, :version => num, :author => author
run app
end
end
# default
builder.map "#{namespace}/current" do
use Headers, :version => versioner.current_version, :author => author
run versioner.current_app
end
builder
end
class Headers
def initialize(app, opts = {})
@app = app
@version = opts[:version]
@author = opts[:author]
end
def call(env)
status, headers, body = @app.call(env)
body = [] if env['REQUEST_METHOD'] == 'HEAD'
headers["X-API-Version"] = @version.to_s if @version
headers["X-API-Author"] = @author.to_s if @author
[status, headers, body]
end
end
class Map
attr_reader :versions
def initialize
@versions = {}
@current = nil
end
def version(num, app)
@versions[num] = app
self
end
def current(num)
@current = num
self
end
def current_version
@versions[@current] ? @current : @versions.keys.last
end
def current_app
@versions[current_version]
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment