webbed 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +15 -0
- data/LICENSE +20 -0
- data/README.md +0 -0
- data/Rakefile +18 -0
- data/lib/webbed/generic_message.rb +30 -0
- data/lib/webbed/headers.rb +79 -0
- data/lib/webbed/http_version.rb +55 -0
- data/lib/webbed/method.rb +64 -0
- data/lib/webbed/request.rb +44 -0
- data/lib/webbed/response.rb +42 -0
- data/lib/webbed/status_code.rb +102 -0
- data/lib/webbed/version.rb +3 -0
- data/lib/webbed.rb +9 -0
- metadata +109 -0
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
gem 'webbed', :path => File.expand_path("..", __FILE__)
|
4
|
+
gem 'addressable', '~> 2.1'
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'rake'
|
8
|
+
end
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
gem 'rspec', '~> 1.3', :require => 'spec'
|
12
|
+
gem 'bourne'
|
13
|
+
gem 'heckle'
|
14
|
+
gem 'ruby2ruby', '1.2.2'
|
15
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Alexander Kern and Artcentric Networks LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup :default, :development, :test
|
3
|
+
|
4
|
+
require 'webbed'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
Spec::Rake::SpecTask.new do |t|
|
8
|
+
t.libs << 'lib'
|
9
|
+
end
|
10
|
+
|
11
|
+
gemspec = eval(File.read('webbed.gemspec'))
|
12
|
+
|
13
|
+
task :build => "#{gemspec.full_name}.gem"
|
14
|
+
|
15
|
+
file "#{gemspec.full_name}.gem" => gemspec.files + ['webbed.gemspec'] do
|
16
|
+
system 'gem build webbed.gemspec'
|
17
|
+
system "gem install webbed-#{Webbed::VERSION}.gem"
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Webbed
|
2
|
+
module GenericMessage
|
3
|
+
|
4
|
+
attr_reader :http_version
|
5
|
+
attr_accessor :entity_body
|
6
|
+
|
7
|
+
# This is purely for test/spec purposes.
|
8
|
+
def initialize
|
9
|
+
self.http_version = 'HTTP/1.1'
|
10
|
+
self.entity_body = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
# Must be overridden!
|
14
|
+
def start_line
|
15
|
+
"Invalid Start Line\r\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def http_version=(http_version)
|
19
|
+
@http_version = Webbed::HTTPVersion.new(http_version)
|
20
|
+
end
|
21
|
+
|
22
|
+
def headers
|
23
|
+
@headers ||= Webbed::Headers.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"#{start_line}#{headers.to_s}\r\n#{entity_body}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Webbed
|
2
|
+
# This class is stolen directly from Rack.
|
3
|
+
class Headers < Hash
|
4
|
+
def self.new(hash={})
|
5
|
+
Headers === hash ? hash : super(hash)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(hash={})
|
9
|
+
super()
|
10
|
+
@names = {}
|
11
|
+
hash.each { |k, v| self[k] = v }
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
super do |k, v|
|
16
|
+
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
inject({}) do |hash, (k,v)|
|
22
|
+
if v.respond_to? :to_ary
|
23
|
+
hash[k] = v.to_ary.join("\n")
|
24
|
+
else
|
25
|
+
hash[k] = v
|
26
|
+
end
|
27
|
+
hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](k)
|
32
|
+
super(@names[k]) if @names[k]
|
33
|
+
super(@names[k.downcase])
|
34
|
+
end
|
35
|
+
|
36
|
+
def []=(k, v)
|
37
|
+
delete k
|
38
|
+
@names[k] = @names[k.downcase] = k
|
39
|
+
super k, v
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete(k)
|
43
|
+
canonical = k.downcase
|
44
|
+
result = super @names.delete(canonical)
|
45
|
+
@names.delete_if { |name,| name.downcase == canonical }
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
def include?(k)
|
50
|
+
@names.include?(k) || @names.include?(k.downcase)
|
51
|
+
end
|
52
|
+
|
53
|
+
alias_method :has_key?, :include?
|
54
|
+
alias_method :member?, :include?
|
55
|
+
alias_method :key?, :include?
|
56
|
+
|
57
|
+
def merge!(other)
|
58
|
+
other.each { |k, v| self[k] = v }
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def merge(other)
|
63
|
+
hash = dup
|
64
|
+
hash.merge! other
|
65
|
+
end
|
66
|
+
|
67
|
+
def replace(other)
|
68
|
+
clear
|
69
|
+
other.each { |k, v| self[k] = v }
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s
|
74
|
+
map do |field_name, field_content|
|
75
|
+
"#{field_name}: #{field_content}\r\n"
|
76
|
+
end.join
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Webbed
|
2
|
+
class HTTPVersion
|
3
|
+
|
4
|
+
include Comparable
|
5
|
+
REGEX = /^HTTP\/(\d+\.\d+)$/
|
6
|
+
|
7
|
+
def self.new(http_version, dup = false)
|
8
|
+
unless dup
|
9
|
+
if ['HTTP/1.1', 1.1].include? http_version
|
10
|
+
return ONE_POINT_ONE
|
11
|
+
end
|
12
|
+
|
13
|
+
if ['HTTP/1.0', 1.0].include? http_version
|
14
|
+
return ONE_POINT_OH
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
super(http_version)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(http_version)
|
22
|
+
@http_version = to_f(http_version)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"HTTP/#{to_f}"
|
27
|
+
end
|
28
|
+
alias :inspect :to_s
|
29
|
+
|
30
|
+
# This feels like a hack. Oh well.
|
31
|
+
def to_f(http_version = @http_version)
|
32
|
+
if http_version.respond_to? :match
|
33
|
+
REGEX.match(http_version)[1].to_f
|
34
|
+
else
|
35
|
+
http_version.to_f
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def <=>(other_version)
|
40
|
+
to_f <=> to_f(other_version)
|
41
|
+
end
|
42
|
+
|
43
|
+
def major
|
44
|
+
to_f.floor
|
45
|
+
end
|
46
|
+
|
47
|
+
# TODO: Fix this ugly hack! :x
|
48
|
+
def minor
|
49
|
+
(to_f - to_f.floor).to_s[2..-1].to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
ONE_POINT_ONE = HTTPVersion.new(1.1, true)
|
53
|
+
ONE_POINT_OH = HTTPVersion.new(1.0, true)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Webbed
|
2
|
+
class Method
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
alias :to_s :name
|
6
|
+
alias :inspect :name
|
7
|
+
|
8
|
+
DEFAULTS = {
|
9
|
+
:safe => false,
|
10
|
+
:idempotent => false,
|
11
|
+
:entities => [:request, :response]
|
12
|
+
}
|
13
|
+
|
14
|
+
def self.new(name, options = {})
|
15
|
+
if const_defined? name
|
16
|
+
const_get(name)
|
17
|
+
else
|
18
|
+
super(name, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(name, options = {})
|
23
|
+
options = DEFAULTS.merge options
|
24
|
+
@name = name
|
25
|
+
@safe = options[:safe]
|
26
|
+
@idempotent = options[:safe] || options[:idempotent]
|
27
|
+
@has_request_entity = options[:entities].include? :request
|
28
|
+
@has_response_entity = options[:entities].include? :response
|
29
|
+
end
|
30
|
+
|
31
|
+
def safe?
|
32
|
+
@safe
|
33
|
+
end
|
34
|
+
|
35
|
+
def idempotent?
|
36
|
+
@idempotent
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_request_entity?
|
40
|
+
@has_request_entity
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_response_entity?
|
44
|
+
@has_response_entity
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(other_method)
|
48
|
+
name == other_method.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
# Common methods used and their settings. Most are defined in RFC 2616 with
|
52
|
+
# the exception of PATCH which is defined in RFC 5789. These are for caching
|
53
|
+
# purposes, so that new objects don't need to be created on each request.
|
54
|
+
OPTIONS = new 'OPTIONS', :safe => true, :idempotent => true, :entities => [:response]
|
55
|
+
GET = new 'GET', :safe => true, :idempotent => true, :entities => [:response]
|
56
|
+
HEAD = new 'HEAD', :safe => true, :idempotent => true, :entities => []
|
57
|
+
POST = new 'POST', :safe => false, :idempotent => false, :entities => [:request, :response]
|
58
|
+
PUT = new 'PUT', :safe => false, :idempotent => true, :entities => [:request, :response]
|
59
|
+
DELETE = new 'DELETE', :safe => false, :idempotent => true, :entities => [:response]
|
60
|
+
TRACE = new 'TRACE', :safe => true, :idempotent => true, :entities => [:response]
|
61
|
+
CONNECT = new 'CONNECT', :safe => false, :idempotent => false, :entities => [:request, :response]
|
62
|
+
PATCH = new 'PATCH', :safe => false, :idempotent => false, :entities => [:request, :response]
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
module Webbed
|
4
|
+
class Request
|
5
|
+
|
6
|
+
include Webbed::GenericMessage
|
7
|
+
attr_reader :request_uri
|
8
|
+
DEFAULTS = {
|
9
|
+
:method => 'GET',
|
10
|
+
:request_uri => '*',
|
11
|
+
:http_version => 'HTTP/1.1',
|
12
|
+
:headers => {},
|
13
|
+
:entity_body => ''
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize(request_hash = {})
|
17
|
+
request_hash = DEFAULTS.merge(request_hash)
|
18
|
+
|
19
|
+
self.method = request_hash[:method]
|
20
|
+
self.request_uri = request_hash[:request_uri]
|
21
|
+
self.http_version = request_hash[:http_version]
|
22
|
+
self.headers.merge!(request_hash[:headers])
|
23
|
+
self.entity_body = request_hash[:entity_body]
|
24
|
+
end
|
25
|
+
|
26
|
+
def method(*args)
|
27
|
+
return super(*args) unless args.empty?
|
28
|
+
@method
|
29
|
+
end
|
30
|
+
|
31
|
+
def method=(method)
|
32
|
+
@method = Webbed::Method.new(method)
|
33
|
+
end
|
34
|
+
|
35
|
+
def request_uri=(uri)
|
36
|
+
@request_uri = Addressable::URI.parse(uri)
|
37
|
+
end
|
38
|
+
|
39
|
+
def request_line
|
40
|
+
"#{method} #{request_uri} #{http_version}\r\n"
|
41
|
+
end
|
42
|
+
alias :start_line :request_line
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Webbed
|
2
|
+
class Response
|
3
|
+
|
4
|
+
include Webbed::GenericMessage
|
5
|
+
attr_reader :status_code
|
6
|
+
attr_writer :reason_phrase
|
7
|
+
DEFAULTS = {
|
8
|
+
:http_version => 'HTTP/1.1',
|
9
|
+
:status_code => 200,
|
10
|
+
:reason_phrase => nil,
|
11
|
+
:headers => {},
|
12
|
+
:entity_body => ''
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(response_hash = {})
|
16
|
+
response_hash = DEFAULTS.merge(response_hash)
|
17
|
+
|
18
|
+
self.http_version = response_hash[:http_version]
|
19
|
+
self.status_code = response_hash[:status_code]
|
20
|
+
self.reason_phrase = response_hash[:reason_phrase]
|
21
|
+
self.headers.merge!(response_hash[:headers])
|
22
|
+
self.entity_body = response_hash[:entity_body]
|
23
|
+
end
|
24
|
+
|
25
|
+
def reason_phrase
|
26
|
+
@reason_phrase || default_reason_phrase
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_reason_phrase
|
30
|
+
@status_code.default_reason_phrase
|
31
|
+
end
|
32
|
+
|
33
|
+
def status_code=(status_code)
|
34
|
+
@status_code = Webbed::StatusCode.new(status_code)
|
35
|
+
end
|
36
|
+
|
37
|
+
def status_line
|
38
|
+
"#{http_version} #{status_code} #{reason_phrase}\r\n"
|
39
|
+
end
|
40
|
+
alias :start_line :status_line
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Webbed
|
2
|
+
class StatusCode
|
3
|
+
|
4
|
+
include Comparable
|
5
|
+
attr_reader :status_code, :default_reason_phrase
|
6
|
+
CACHED = {}
|
7
|
+
|
8
|
+
UNKNOWN_REASON_PHRASE = 'Unknown Status Code'
|
9
|
+
REASON_PHRASES = {
|
10
|
+
100 => 'Continue',
|
11
|
+
101 => 'Switching Protocols',
|
12
|
+
200 => 'OK',
|
13
|
+
201 => 'Created',
|
14
|
+
202 => 'Accepted',
|
15
|
+
203 => 'Non-Authoritative Information',
|
16
|
+
204 => 'No Content',
|
17
|
+
205 => 'Reset Content',
|
18
|
+
206 => 'Partial Content',
|
19
|
+
300 => 'Multiple Choices',
|
20
|
+
301 => 'Moved Permanently',
|
21
|
+
302 => 'Found',
|
22
|
+
303 => 'See Other',
|
23
|
+
304 => 'Not Modified',
|
24
|
+
305 => 'Use Proxy',
|
25
|
+
307 => 'Temporary Redirect',
|
26
|
+
400 => 'Bad Request',
|
27
|
+
401 => 'Unauthorized',
|
28
|
+
402 => 'Payment Required',
|
29
|
+
403 => 'Forbidden',
|
30
|
+
404 => 'Not Found',
|
31
|
+
405 => 'Method Not Allowed',
|
32
|
+
406 => 'Not Acceptable',
|
33
|
+
407 => 'Proxy Authentication Required',
|
34
|
+
408 => 'Request Time-out',
|
35
|
+
409 => 'Conflict',
|
36
|
+
410 => 'Gone',
|
37
|
+
411 => 'Length Required',
|
38
|
+
412 => 'Precondition Failed',
|
39
|
+
413 => 'Request Entity Too Large',
|
40
|
+
414 => 'Request-URI Too Large',
|
41
|
+
415 => 'Unsupported Media Type',
|
42
|
+
416 => 'Requested range not satisfiable',
|
43
|
+
417 => 'Expectation Failed',
|
44
|
+
500 => 'Internal Server Error',
|
45
|
+
501 => 'Not Implemented',
|
46
|
+
502 => 'Bad Gateway',
|
47
|
+
503 => 'Service Unavailable',
|
48
|
+
504 => 'Gateway Time-out',
|
49
|
+
505 => 'HTTP Version not supported'
|
50
|
+
}
|
51
|
+
|
52
|
+
def self.new(status_code)
|
53
|
+
CACHED[status_code] ||= super(status_code)
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(status_code)
|
57
|
+
status_code = status_code.to_i
|
58
|
+
@status_code = status_code
|
59
|
+
@default_reason_phrase = REASON_PHRASES[status_code] || UNKNOWN_REASON_PHRASE
|
60
|
+
end
|
61
|
+
|
62
|
+
def <=>(other_status_code)
|
63
|
+
status_code <=> other_status_code.to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_i
|
67
|
+
status_code
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
'%03d' % status_code
|
72
|
+
end
|
73
|
+
|
74
|
+
def informational?
|
75
|
+
(100...200).include? status_code
|
76
|
+
end
|
77
|
+
|
78
|
+
def success?
|
79
|
+
(200...300).include? status_code
|
80
|
+
end
|
81
|
+
|
82
|
+
def redirection?
|
83
|
+
(300...400).include? status_code
|
84
|
+
end
|
85
|
+
|
86
|
+
def client_error?
|
87
|
+
(400...500).include? status_code
|
88
|
+
end
|
89
|
+
|
90
|
+
def server_error?
|
91
|
+
(500...600).include? status_code
|
92
|
+
end
|
93
|
+
|
94
|
+
def unknown?
|
95
|
+
!(100...600).include? status_code
|
96
|
+
end
|
97
|
+
|
98
|
+
def error?
|
99
|
+
(400...600).include? status_code
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/webbed.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
module Webbed
|
2
|
+
autoload :Headers, 'webbed/headers'
|
3
|
+
autoload :HTTPVersion, 'webbed/http_version'
|
4
|
+
autoload :GenericMessage, 'webbed/generic_message'
|
5
|
+
autoload :Method, 'webbed/method'
|
6
|
+
autoload :StatusCode, 'webbed/status_code'
|
7
|
+
autoload :Request, 'webbed/request'
|
8
|
+
autoload :Response, 'webbed/response'
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webbed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alexander Kern
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-27 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 1
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 1
|
31
|
+
version: "2.1"
|
32
|
+
requirement: *id001
|
33
|
+
name: addressable
|
34
|
+
prerelease: false
|
35
|
+
type: :runtime
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
requirement: *id002
|
47
|
+
name: rake
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
description: Consistent library of manipulating HTTP messages.
|
51
|
+
email: alex@kernul.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- lib/webbed/generic_message.rb
|
60
|
+
- lib/webbed/headers.rb
|
61
|
+
- lib/webbed/http_version.rb
|
62
|
+
- lib/webbed/method.rb
|
63
|
+
- lib/webbed/request.rb
|
64
|
+
- lib/webbed/response.rb
|
65
|
+
- lib/webbed/status_code.rb
|
66
|
+
- lib/webbed/version.rb
|
67
|
+
- lib/webbed.rb
|
68
|
+
- LICENSE
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- Gemfile
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/CapnKernul/webbed
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 57
|
87
|
+
segments:
|
88
|
+
- 1
|
89
|
+
- 8
|
90
|
+
- 7
|
91
|
+
version: 1.8.7
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project: webbed
|
104
|
+
rubygems_version: 1.3.7
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Take control of HTTP.
|
108
|
+
test_files: []
|
109
|
+
|