rhinestone 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .cache
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.3@rhinestone
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rhinestone.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
7
+ end
8
+
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Rhinestone
2
+
3
+ Has it ever bothered you how long `bundle install` command takes to run?
4
+
5
+ It has bothered me, so I wrote Rhinestone: a simple proxy caches both the gems and the gem metadata.
6
+ It updates the cache *after* returning the response, so you get data that might be a little stale, but you get it very quickly.
7
+ You should deploy it somewhere in your local network (so that more people use the same cache).
8
+
9
+ # Installation
10
+
11
+ Just install it from RubyGems:
12
+
13
+ gem install rhinestone
14
+
15
+ # Running
16
+
17
+ It's as simple as running:
18
+
19
+ rhinestone
20
+
21
+ Rhinestone uses Goliath underneath, so there are more switches you can use:
22
+
23
+ $ rhinestone --help
24
+
25
+ Usage: <server> [options]
26
+
27
+ Server options:
28
+ -e, --environment NAME Set the execution environment (prod, dev or test) (default: development)
29
+ -a, --address HOST Bind to HOST address (default: 0.0.0.0)
30
+ -p, --port PORT Use PORT (default: 9000)
31
+ -S, --socket FILE Bind to unix domain socket
32
+
33
+ Daemon options:
34
+ -u, --user USER Run as specified user
35
+ -c, --config FILE Config file (default: ./config/<server>.rb)
36
+ -d, --daemonize Run daemonized in the background (default: false)
37
+ -l, --log FILE Log to file (default: off)
38
+ -s, --stdout Log to stdout (default: false)
39
+ -P, --pid FILE Pid file (default: off)
40
+
41
+ SSL options:
42
+ --ssl Enables SSL (default: off)
43
+ --ssl-key FILE Path to private key
44
+ --ssl-cert FILE Path to certificate
45
+ --ssl-verify Enables SSL certificate verification
46
+
47
+ Common options:
48
+ -v, --verbose Enable verbose logging (default: false)
49
+ -h, --help Display help message
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/benchmark/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+ source "http://127.0.0.1:1234"
3
+
4
+ gem "rails"
5
+ gem "rspec-rails"
@@ -0,0 +1,4 @@
1
+ source "http://127.0.0.1:1234"
2
+
3
+ gem "rails"
4
+ gem "rspec-rails"
@@ -0,0 +1,100 @@
1
+ GEM
2
+ remote: http://127.0.0.1:1234/
3
+ specs:
4
+ actionmailer (3.2.2)
5
+ actionpack (= 3.2.2)
6
+ mail (~> 2.4.0)
7
+ actionpack (3.2.2)
8
+ activemodel (= 3.2.2)
9
+ activesupport (= 3.2.2)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.1)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.2)
18
+ activesupport (= 3.2.2)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.2)
21
+ activemodel (= 3.2.2)
22
+ activesupport (= 3.2.2)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.2)
26
+ activemodel (= 3.2.2)
27
+ activesupport (= 3.2.2)
28
+ activesupport (3.2.2)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ arel (3.0.2)
32
+ builder (3.0.0)
33
+ diff-lcs (1.1.3)
34
+ erubis (2.7.0)
35
+ hike (1.2.1)
36
+ i18n (0.6.0)
37
+ journey (1.0.3)
38
+ json (1.6.5)
39
+ mail (2.4.4)
40
+ i18n (>= 0.4.0)
41
+ mime-types (~> 1.16)
42
+ treetop (~> 1.4.8)
43
+ mime-types (1.18)
44
+ multi_json (1.1.0)
45
+ polyglot (0.3.3)
46
+ rack (1.4.1)
47
+ rack-cache (1.2)
48
+ rack (>= 0.4)
49
+ rack-ssl (1.3.2)
50
+ rack
51
+ rack-test (0.6.1)
52
+ rack (>= 1.0)
53
+ rails (3.2.2)
54
+ actionmailer (= 3.2.2)
55
+ actionpack (= 3.2.2)
56
+ activerecord (= 3.2.2)
57
+ activeresource (= 3.2.2)
58
+ activesupport (= 3.2.2)
59
+ bundler (~> 1.0)
60
+ railties (= 3.2.2)
61
+ railties (3.2.2)
62
+ actionpack (= 3.2.2)
63
+ activesupport (= 3.2.2)
64
+ rack-ssl (~> 1.3.2)
65
+ rake (>= 0.8.7)
66
+ rdoc (~> 3.4)
67
+ thor (~> 0.14.6)
68
+ rake (0.9.2.2)
69
+ rdoc (3.12)
70
+ json (~> 1.4)
71
+ rspec (2.9.0)
72
+ rspec-core (~> 2.9.0)
73
+ rspec-expectations (~> 2.9.0)
74
+ rspec-mocks (~> 2.9.0)
75
+ rspec-core (2.9.0)
76
+ rspec-expectations (2.9.0)
77
+ diff-lcs (~> 1.1.3)
78
+ rspec-mocks (2.9.0)
79
+ rspec-rails (2.9.0)
80
+ actionpack (>= 3.0)
81
+ activesupport (>= 3.0)
82
+ railties (>= 3.0)
83
+ rspec (~> 2.9.0)
84
+ sprockets (2.1.2)
85
+ hike (~> 1.2)
86
+ rack (~> 1.0)
87
+ tilt (~> 1.1, != 1.3.0)
88
+ thor (0.14.6)
89
+ tilt (1.3.3)
90
+ treetop (1.4.10)
91
+ polyglot
92
+ polyglot (>= 0.3.1)
93
+ tzinfo (0.3.32)
94
+
95
+ PLATFORMS
96
+ ruby
97
+
98
+ DEPENDENCIES
99
+ rails
100
+ rspec-rails
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+
3
+ echo "without cache"
4
+ rvm 1.9.3 gemset create rhinestone-benchmark
5
+ time rvm 1.9.3@rhinestone-benchmark exec bundle install
6
+ rvm --force gemset delete rhinestone-benchmark
7
+
8
+ echo "with cache"
9
+ rvm 1.9.3 gemset create rhinestone-benchmark
10
+ time rvm 1.9.3@rhinestone-benchmark exec bundle install
11
+ rvm --force gemset delete rhinestone-benchmark
12
+
13
+ echo "no rubygems"
14
+ rvm 1.9.3 gemset create rhinestone-benchmark
15
+ time rvm 1.9.3@rhinestone-benchmark exec bundle install --gemfile=Gemfile.proxy
16
+ rvm --force gemset delete rhinestone-benchmark
data/bin/rhinestone ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push File.expand_path("../../lib", __FILE__)
4
+
5
+ require 'rhinestone'
6
+
7
+ Rhinestone.run!
@@ -0,0 +1,13 @@
1
+ module Rhinestone
2
+ class App < Goliath::API
3
+ def initialize
4
+ @server = Rhinestone.server
5
+ end
6
+
7
+ def response(env)
8
+ response = @server.get("#{env['REQUEST_PATH']}?#{env['QUERY_STRING']}")
9
+
10
+ [response.status, response.headers, response.body]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module Rhinestone
2
+ class Cache
3
+ takes :cache_backend
4
+
5
+ class KeyNotFound < RuntimeError; end
6
+
7
+ def set(url, response)
8
+ cache_backend.set("status:#{url}", response.status.to_s)
9
+ cache_backend.set("headers:#{url}", response.headers.to_yaml)
10
+ cache_backend.set("body:#{url}", response.body)
11
+ end
12
+
13
+ def get(url)
14
+ status = get!("status:#{url}").to_i
15
+ headers = YAML.load(get!("headers:#{url}"))
16
+ body = get!("body:#{url}")
17
+ return Rhinestone::Response.new(status, headers, body)
18
+ rescue KeyNotFound
19
+ return nil
20
+ end
21
+
22
+ private
23
+
24
+ def get!(key)
25
+ cache_backend.get(key) or raise KeyNotFound
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'fileutils'
2
+ require 'digest/sha2'
3
+
4
+ module Rhinestone
5
+ class FilesystemCacheBackend
6
+ takes :base_directory
7
+
8
+ def get(key)
9
+ File.read(file_name(key)) rescue nil
10
+ end
11
+
12
+ def set(key, value)
13
+ file = file_name(key)
14
+ FileUtils.mkdir_p(File.dirname(file))
15
+ File.open(file, "w") do |f|
16
+ f.write value
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def file_name(key)
23
+ sha = Digest::SHA2.hexdigest(key)
24
+ parts = sha.gsub(/.{16}/){|s| s+'|'}.split('|')
25
+ return File.expand_path(File.join(*parts), base_directory)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ module Rhinestone
2
+ class HeaderFilter
3
+ takes :important_headers
4
+
5
+ def filter(headers)
6
+ filtered = {}
7
+
8
+ important_headers.each do |name|
9
+ value = headers[name]
10
+ filtered[name] = value if value
11
+ end
12
+
13
+ filtered
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require 'em-synchrony/em-http'
2
+
3
+ module Rhinestone
4
+ class HttpClient
5
+ takes :hostname, :header_filter
6
+
7
+ def get(path)
8
+ response = EM::HttpRequest.new("http://#{hostname}#{path}").get(:redirects => 5)
9
+ headers = response.response_header
10
+ return Rhinestone::Response.new(headers.status,
11
+ header_filter.filter(headers),
12
+ response.response)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Rhinestone
2
+ class InMemoryCacheBackend
3
+ attr_reader :data
4
+
5
+ def initialize
6
+ @data = {}
7
+ end
8
+
9
+ def set(key, value)
10
+ data[key] = value
11
+ end
12
+
13
+ def get(key)
14
+ data[key]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Rhinestone
2
+ class Injector
3
+ include Dependor::AutoInject
4
+ look_in_modules Rhinestone
5
+
6
+ def cache_backend
7
+ @cache_backend ||= FilesystemCacheBackend.new(".cache")
8
+ end
9
+
10
+ def hostname
11
+ "rubygems.org"
12
+ end
13
+
14
+ def important_headers
15
+ %w{Content-Type Cache-Control ETag Set-Cookie}
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Rhinestone
2
+ class Later
3
+ def run(&block)
4
+ EM.next_tick{ Fiber.new(&block).resume }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Rhinestone
2
+ Response = Struct.new(:status, :headers, :body)
3
+ end
@@ -0,0 +1,25 @@
1
+ module Rhinestone
2
+ class Server
3
+ takes :http_client, :cache, :later
4
+
5
+ def get(path)
6
+ response = cache.get(path)
7
+
8
+ unless response
9
+ response = fetch_response(path)
10
+ else
11
+ later.run{ fetch_response(path) }
12
+ end
13
+
14
+ return response
15
+ end
16
+
17
+ private
18
+
19
+ def fetch_response(path)
20
+ response = http_client.get(path)
21
+ cache.set(path, response)
22
+ response
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Rhinestone
2
+ VERSION = "0.0.1"
3
+ end
data/lib/rhinestone.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'dependor'
2
+ require 'dependor/shorty'
3
+
4
+ require 'goliath'
5
+ require 'yaml'
6
+
7
+ module Rhinestone
8
+ autoload :App, 'rhinestone/app'
9
+ autoload :Cache, 'rhinestone/cache'
10
+ autoload :FilesystemCacheBackend, 'rhinestone/filesystem_cache_backend'
11
+ autoload :HeaderFilter, 'rhinestone/header_filter'
12
+ autoload :Injector, 'rhinestone/injector'
13
+ autoload :InMemoryCacheBackend, 'rhinestone/in_memory_cache_backend'
14
+ autoload :HttpClient, 'rhinestone/http_client'
15
+ autoload :Later, 'rhinestone/later'
16
+ autoload :Response, 'rhinestone/response'
17
+ autoload :Server, 'rhinestone/server'
18
+ autoload :VERSION, 'rhinestone/version'
19
+
20
+ def self.server
21
+ Injector.new.server
22
+ end
23
+
24
+ def self.run!
25
+ Goliath::Application.app_class = 'Rhinestone::App'
26
+ Goliath::Application.run!
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rhinestone/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rhinestone"
7
+ s.version = Rhinestone::VERSION
8
+ s.authors = ["Adam Pohorecki"]
9
+ s.email = ["adam@pohorecki.pl"]
10
+ s.homepage = "http://github.com/psyho/rhinestone"
11
+ s.summary = %q{Proxy to rubygems}
12
+ s.description = %q{Proxy to rubygems that returns the latest cached version of the requested url and updates the cache in the background}
13
+
14
+ s.rubyforge_project = "rhinestone"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'dependor'
22
+ s.add_runtime_dependency 'goliath'
23
+ s.add_runtime_dependency 'em-http-request'
24
+
25
+ s.add_development_dependency 'rake'
26
+
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'vcr'
29
+ s.add_development_dependency 'webmock'
30
+
31
+ s.add_development_dependency 'guard'
32
+ s.add_development_dependency 'guard-rspec'
33
+ s.add_development_dependency 'libnotify'
34
+ end
@@ -0,0 +1,166 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://rubygems.org/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers: {}
10
+ response:
11
+ status:
12
+ code: 200
13
+ message: OK
14
+ headers:
15
+ Date:
16
+ - Fri, 16 Mar 2012 11:39:48 GMT
17
+ Server:
18
+ - Apache/2.2.3 (Red Hat) mod_ssl/2.2.3 OpenSSL/0.9.8e-fips-rhel5 Phusion_Passenger/3.0.11
19
+ X-Powered-By:
20
+ - Phusion Passenger (mod_rails/mod_rack) 3.0.11
21
+ Etag:
22
+ - ! '"e727c435d70d9b1b896fc0be277f8855"'
23
+ Cache-Control:
24
+ - max-age=0, private, must-revalidate
25
+ X-Ua-Compatible:
26
+ - IE=Edge,chrome=1
27
+ X-Runtime:
28
+ - '0.850949'
29
+ Set-Cookie:
30
+ - _rubygems_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFRiIlZDJjYzA3ZWM5NTExNWQ3ZmQ0YjFlYTFmMjYxMTQ4YjBJIhBfY3NyZl90b2tlbgY7AEZJIjF0ekRYTllLY0c1cHhOVmsxcHZ2K3lrNmpyUkVNTGtMRk9NQkpiWHh3dkFjPQY7AEY%3D--5c1881112da15303960e1b8cbef881b12006e326;
31
+ path=/; HttpOnly
32
+ Status:
33
+ - '200'
34
+ Vary:
35
+ - Accept-Encoding
36
+ Content-Length:
37
+ - '9629'
38
+ Connection:
39
+ - close
40
+ Content-Type:
41
+ - text/html; charset=utf-8
42
+ body:
43
+ encoding: US-ASCII
44
+ string: ! "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta http-equiv=\"Content-Type\"
45
+ content=\"text/html; charset=utf-8\">\n <link rel=\"apple-touch-icon\"
46
+ href=\"/touch-icon-iphone.png\" />\n <link rel=\"apple-touch-icon\" sizes=\"72x72\"
47
+ href=\"/touch-icon-ipad.png\" />\n <link rel=\"apple-touch-icon\" sizes=\"114x114\"
48
+ href=\"/touch-icon-iphone4.png\" />\n <link rel=\"fluid-icon\" href=\"/fluid-icon.png\"/>\n
49
+ \ <link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"RubyGems.org\"
50
+ href=\"/opensearch.xml\">\n <link rel=\"shortcut icon\" href=\"/favicon.ico\"
51
+ type=\"image/x-icon\">\n <link href=\"/stylesheets/all.css?1331498529\"
52
+ media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n <!--[if IE 7]>\n
53
+ \ <link href=\"/stylesheets/ie7.css?1331498529\" media=\"screen\" rel=\"stylesheet\"
54
+ type=\"text/css\" />\n <![endif]-->\n \n<link href=\"http://feeds.feedburner.com/gemcutter-latest\"
55
+ rel=\"alternate\" title=\"RubyGems.org | Latest Gems\" type=\"application/atom+xml\"
56
+ />\n\n <meta name=\"csrf-param\" content=\"authenticity_token\"/>\n<meta
57
+ name=\"csrf-token\" content=\"tzDXNYKcG5pxNVk1pvv+yk6jrREMLkLFOMBJbXxwvAc=\"/>\n
58
+ \ <title>RubyGems.org | your community gem host</title>\n </head>\n <body>\n
59
+ \ <div class=\"container_12\">\n <div class=\"prefix_1 grid_4 header\">\n
60
+ \ <h1><a href=\"http://rubygems.org/\" title=\"Home\">RubyGems.org</a></h1>\n
61
+ \ </div>\n <div class=\"grid_6 suffix_1 nav\">\n <div id=\"nav-cap\">\n
62
+ \ <div id=\"nav\">\n <ul id=\"signed_out\">\n <li
63
+ id=\"all-gems\"><a href=\"http://rubygems.org/gems\">all gems</a></li>\n\n
64
+ \ <li id=\"sign-in\">\n <a href=\"https://rubygems.org/session/new\">sign
65
+ in</a>\n </li>\n\n <li id=\"sign-up\">\n <a
66
+ href=\"https://rubygems.org/users/new\">sign up</a>\n </li>\n
67
+ \ </ul>\n </div>\n </div>\n <form accept-charset=\"UTF-8\"
68
+ action=\"http://rubygems.org/search\" id=\"main-search\" method=\"get\"><div
69
+ style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\"
70
+ value=\"&#x2713;\" /></div>\n <input id=\"query\" name=\"query\"
71
+ type=\"text\" value=\"Search gems&hellip;\" />\n <input id=\"search_submit\"
72
+ type=\"submit\" value=\"Search\" />\n</form> </div>\n <div class=\"prefix_1
73
+ grid_10 suffix_1 main\">\n \n\n <div class=\"fold\">\n <div
74
+ class=\"count\">\n <strong>528,127,613 downloads</strong>\n of 35,796
75
+ gems cut since July 2009\n </div>\n <div class=\"blurb\">\n <strong>Welcome
76
+ to your community RubyGem host.</strong>\n <br />Find your gems easier,
77
+ publish them faster, and have fun doing it.\n </div>\n\n </div>\n
78
+ \ <div class=\"info clearfix\">\n <div class=\"title\">\n \n
79
+ \ </div>\n \n<div class=\"border\">\n <div class=\"background\">\n
80
+ \ <div class=\"learn\">\n <h3>learn</h3>\n <dl>\n <dt><a
81
+ href=\"http://rubygems.org/pages/download\">Install RubyGems 1.8.17</a></dt>\n
82
+ \ <dd>Ruby's premier packaging system</dd>\n <dt><a href=\"http://guides.rubygems.org/\">Browse
83
+ the Guides</a></dt>\n <dd>In depth explanations, tutorials, and references</dd>\n
84
+ \ <dt><a href=\"http://guides.rubygems.org/specification-reference/\">Gem
85
+ Specification</a></dt>\n <dd>Your gem's interface to the world</dd>\n
86
+ \ </dl>\n </div>\n <div class=\"share\">\n <h3>share</h3>\n
87
+ \ <dl>\n <dt><code>gem update --system</code></dt>\n <dd>Update
88
+ to the latest RubyGems version</dd>\n <dt><code>gem build foo.gemspec</code></dt>\n
89
+ \ <dd>Build your gem</dd>\n <dt><code>gem push foo-1.0.0.gem</code></dt>\n
90
+ \ <dd>Deploy your gem instantly</dd>\n </dl>\n </div>\n </div>\n</div>\n\n<p
91
+ class=\"pitch\">\n <strong><a href=\"http://rubygems.org/pages/about\">RubyGems.org</a></strong>
92
+ is the Ruby community's gem hosting service. <strong><a href=\"http://guides.rubygems.org/make-your-own-gem\"
93
+ anchor=\"push\">Instantly publish</a></strong> your gems and install them.
94
+ <strong><a href=\"http://guides.rubygems.org/rubygems-org-api/\">Use the API</a></strong>
95
+ to interact and find out more information about available gems. <strong><a
96
+ href=\"http://github.com/rubygems/rubygems.org\">Become a contributor</a></strong>
97
+ and enhance the site with your own changes.\n</p>\n<div class=\"leaderboards\">\n
98
+ \ <div class=\"grid_3\" id=\"new_gems\">\n <strong>New Gems</strong>\n
99
+ \ <ol>\n <li>\n <a href=\"/gems/appyantra_admin\" title=\"Rails
100
+ 3 engine for managing an app's assets, users, pages, blog, SEO and Social
101
+ Media Integration \">appyantra_admin (0.0.1)</a>\n </li>\n <li>\n
102
+ \ <a href=\"/gems/artieller\" title=\"Converts CSS files from left-to-right
103
+ to right-to-left\">artieller (0.0.2)</a>\n </li>\n <li>\n <a
104
+ href=\"/gems/fluent-plugin-file-alternative\" title=\"alternative implementation
105
+ of out_file, with various configurations\">fluent-plugin-file-alternative
106
+ (0.1.0)</a>\n </li>\n <li>\n <a href=\"/gems/middleware\"
107
+ title=\"Generalized implementation of the middleware abstraction for Ruby.\">middleware
108
+ (0.1.0)</a>\n </li>\n <li>\n <a href=\"/gems/failsafe\"
109
+ title=\"Tiny little library for silently handling errors so they don't interrupt
110
+ program flow.\">failsafe (0.1.0)</a>\n </li>\n </ol>\n </div>\n
111
+ \ <div class=\"grid_3\" id=\"most_downloaded\">\n <strong>Most Downloaded
112
+ Today</strong>\n <ol>\n <li>\n <a href=\"/gems/mime-types\"
113
+ title=\"This library allows for the identification of a file's likely MIME
114
+ content\ntype. This is release ...\">mime-types-1.17.2 (7,837)</a>\n </li>\n
115
+ \ <li>\n <a href=\"/gems/json\" title=\"This is a JSON
116
+ implementation as a Ruby extension in C.\">json-1.6.5 (7,532)</a>\n </li>\n
117
+ \ <li>\n <a href=\"/gems/rake\" title=\"Rake is a Make-like
118
+ program implemented in Ruby. Tasks and dependencies arespecified in standard
119
+ ...\">rake-0.9.2.2 (7,330)</a>\n </li>\n <li>\n <a
120
+ href=\"/gems/thor\" title=\"A scripting framework that replaces rake, sake
121
+ and rubigen\">thor-0.14.6 (6,853)</a>\n </li>\n <li>\n <a
122
+ href=\"/gems/treetop\" title=\"A Ruby-based text parsing and interpretation
123
+ DSL\">treetop-1.4.10 (6,584)</a>\n </li>\n </ol>\n </div>\n
124
+ \ <div class=\"grid_3\" id=\"just_updated\">\n <strong>Just Updated</strong>\n
125
+ \ <ol>\n <li>\n <a href=\"/gems/dynarex\" title=\"dynarex\">dynarex
126
+ (1.1.9)</a>\n </li>\n <li>\n <a href=\"/gems/ajax_pagination\"
127
+ title=\"Loads page content into AJAX sections with AJAX links, handling the
128
+ details for you, load content...\">ajax_pagination (0.6.2)</a>\n </li>\n
129
+ \ <li>\n <a href=\"/gems/diffbench\" title=\"Diffbench is gem
130
+ designed to benchmark the performance patches. It can run specified benchmark
131
+ fi...\">diffbench (0.0.2)</a>\n </li>\n <li>\n <a href=\"/gems/elibri_onix\"
132
+ title=\"EDItEUR ONIX format subset implementation used in Elibri publication
133
+ system\">elibri_onix (0.1.12)</a>\n </li>\n <li>\n <a
134
+ href=\"/gems/anmo\" title=\"This rubygem does not have a description or summary.\">anmo
135
+ (0.0.3)</a>\n </li>\n </ol>\n </div>\n</div>\n\n </div>\n
136
+ \ </div>\n <div class=\"prefix_1 grid_10 suffix_1 footer\">\n <ul
137
+ class=\"major\">\n <li><a href=\"http://help.rubygems.org\">Help</a></li>\n
138
+ \ <li><a href=\"http://guides.rubygems.org\">Guides</a></li>\n <li><a
139
+ href=\"http://blog.rubygems.org\">Blog</a></li>\n <li><a href=\"http://guides.rubygems.org/contributing/\">Contribute</a></li>\n
140
+ \ </ul>\n <ul class=\"minor\">\n <li><a href=\"http://m.rubygems.org\">Mobile</a></li>\n
141
+ \ <li><a href=\"http://status.rubygems.org\">Status</a></li>\n <li><a
142
+ href=\"http://uptime.rubygems.org\">Uptime</a></li>\n <li><a href=\"http://github.com/rubygems/rubygems.org\">Code</a></li>\n
143
+ \ <li><a href=\"http://groups.google.com/group/gemcutter\">Discuss</a></li>\n
144
+ \ <li><a href=\"http://rubygems.org/stats\">Stats</a></li>\n <li><a
145
+ href=\"http://rubygems.org/pages/about\">About</a></li>\n </ul>\n <ul
146
+ class=\"sponsors\">\n <li><a href=\"http://rubycentral.org\" id=\"rubycentral\"
147
+ title=\"Hosted by Ruby Central\">hosted by <img alt=\"Rubycentral\" src=\"/images/rubycentral.png?1331498529\"
148
+ /></a></li>\n <li><a href=\"http://thoughtbot.com\" id=\"thoughtbot\"
149
+ title=\"Design by Thoughtbot\">design by <img alt=\"Thoughtbot\" src=\"/images/thoughtbot.png?1331498529\"
150
+ /></a></li>\n <li><a href=\"http://dnsimple.com\" id=\"dnsimple\"
151
+ title=\"Resolved with DNSimple\">resolved with <img alt=\"Dnsimple\" src=\"/images/dnsimple.png?1331498529\"
152
+ /></a></li>\n <li><a href=\"http://newrelic.com\" id=\"newrelic\"
153
+ title=\"Optimized by NewRelic\">optimized by <img alt=\"Newrelic\" src=\"/images/newrelic.png?1331498529\"
154
+ /></a></li>\n <li><a href=\"http://gaug.es\" id=\"gauges\" title=\"Tracking
155
+ by Gauges\">tracking by <img alt=\"Gauges\" src=\"/images/gauges.png?1331498529\"
156
+ /></a></li>\n </ul>\n </div>\n </div>\n <script src=\"/javascripts/all.js?1331498529\"
157
+ type=\"text/javascript\"></script>\n \n <script type=\"text/javascript\">\n
158
+ \ var _gauges = _gauges || [];\n (function() {\n var t =
159
+ document.createElement('script');\n t.type = 'text/javascript';\n
160
+ \ t.async = true;\n t.id = 'gauges-tracker';\n t.setAttribute('data-site-id',
161
+ '4eab0ac8613f5d1583000005');\n t.src = '//secure.gaug.es/track.js';\n
162
+ \ var s = document.getElementsByTagName('script')[0];\n s.parentNode.insertBefore(t,
163
+ s);\n })();\n </script>\n </body>\n</html>\n"
164
+ http_version:
165
+ recorded_at: Fri, 16 Mar 2012 11:39:49 GMT
166
+ recorded_with: VCR 2.0.0