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 +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/README.md +49 -0
- data/Rakefile +1 -0
- data/benchmark/Gemfile +5 -0
- data/benchmark/Gemfile.proxy +4 -0
- data/benchmark/Gemfile.proxy.lock +100 -0
- data/benchmark/benchmark.sh +16 -0
- data/bin/rhinestone +7 -0
- data/lib/rhinestone/app.rb +13 -0
- data/lib/rhinestone/cache.rb +29 -0
- data/lib/rhinestone/filesystem_cache_backend.rb +29 -0
- data/lib/rhinestone/header_filter.rb +16 -0
- data/lib/rhinestone/http_client.rb +15 -0
- data/lib/rhinestone/in_memory_cache_backend.rb +17 -0
- data/lib/rhinestone/injector.rb +18 -0
- data/lib/rhinestone/later.rb +7 -0
- data/lib/rhinestone/response.rb +3 -0
- data/lib/rhinestone/server.rb +25 -0
- data/lib/rhinestone/version.rb +3 -0
- data/lib/rhinestone.rb +28 -0
- data/rhinestone.gemspec +34 -0
- data/spec/cassettes/Rhinestone_HttpClient/returns_a_Rhinestone_Response.yml +166 -0
- data/spec/cassettes/Rhinestone_integration/caches_the_requests.yml +329 -0
- data/spec/cassettes/Rhinestone_integration/proxies_requests_to_rubygems_org.yml +166 -0
- data/spec/rhinestone/cache_spec.rb +25 -0
- data/spec/rhinestone/filesystem_cache_backend_spec.rb +10 -0
- data/spec/rhinestone/header_filter_spec.rb +29 -0
- data/spec/rhinestone/http_client_spec.rb +21 -0
- data/spec/rhinestone/in_memory_cache_backend_spec.rb +7 -0
- data/spec/rhinestone/integration_spec.rb +29 -0
- data/spec/rhinestone/server_spec.rb +60 -0
- data/spec/spec_helper.rb +26 -0
- metadata +199 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@rhinestone
|
data/Gemfile
ADDED
data/Guardfile
ADDED
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,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,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,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,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,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
|
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
|
data/rhinestone.gemspec
ADDED
@@ -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=\"✓\" /></div>\n <input id=\"query\" name=\"query\"
|
71
|
+
type=\"text\" value=\"Search gems…\" />\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
|