almodovar 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -4
- data/lib/almodovar.rb +15 -181
- data/lib/almodovar/digest_auth.rb +4 -0
- data/lib/almodovar/http_accessor.rb +26 -0
- data/lib/almodovar/resource.rb +56 -0
- data/lib/almodovar/resource_collection.rb +31 -0
- data/lib/almodovar/resource_presenter.rb +110 -0
- data/lib/almodovar/resource_presenter/collection.rb +24 -0
- data/lib/almodovar/resource_presenter/link.rb +103 -0
- data/lib/almodovar/single_resource.rb +79 -0
- data/lib/almodovar/to_xml.rb +21 -0
- metadata +47 -91
- data/lib/to_xml.rb +0 -24
- data/vendor/resourceful-0.5.3-patched/MIT-LICENSE +0 -21
- data/vendor/resourceful-0.5.3-patched/Manifest +0 -29
- data/vendor/resourceful-0.5.3-patched/README.markdown +0 -84
- data/vendor/resourceful-0.5.3-patched/Rakefile +0 -71
- data/vendor/resourceful-0.5.3-patched/lib/resourceful.rb +0 -18
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/authentication_manager.rb +0 -108
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/cache_manager.rb +0 -240
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/exceptions.rb +0 -34
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/header.rb +0 -126
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/http_accessor.rb +0 -98
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/memcache_cache_manager.rb +0 -75
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/net_http_adapter.rb +0 -70
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/options_interpreter.rb +0 -78
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/request.rb +0 -230
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/resource.rb +0 -165
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/response.rb +0 -221
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/stubbed_resource_proxy.rb +0 -47
- data/vendor/resourceful-0.5.3-patched/lib/resourceful/util.rb +0 -6
- data/vendor/resourceful-0.5.3-patched/resourceful.gemspec +0 -48
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/authorization_spec.rb +0 -16
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/caching_spec.rb +0 -192
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/header_spec.rb +0 -24
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/redirecting_spec.rb +0 -12
- data/vendor/resourceful-0.5.3-patched/spec/acceptance/resource_spec.rb +0 -84
- data/vendor/resourceful-0.5.3-patched/spec/acceptance_shared_specs.rb +0 -44
- data/vendor/resourceful-0.5.3-patched/spec/old_acceptance_specs.rb +0 -378
- data/vendor/resourceful-0.5.3-patched/spec/simple_sinatra_server.rb +0 -74
- data/vendor/resourceful-0.5.3-patched/spec/simple_sinatra_server_spec.rb +0 -98
- data/vendor/resourceful-0.5.3-patched/spec/spec.opts +0 -3
- data/vendor/resourceful-0.5.3-patched/spec/spec_helper.rb +0 -28
@@ -1,34 +0,0 @@
|
|
1
|
-
|
2
|
-
module Resourceful
|
3
|
-
|
4
|
-
# This exception used to indicate that the request did not succeed.
|
5
|
-
# The HTTP response is included so that the appropriate actions can
|
6
|
-
# be taken based on the details of that response
|
7
|
-
class UnsuccessfulHttpRequestError < Exception
|
8
|
-
attr_reader :http_response, :http_request
|
9
|
-
|
10
|
-
# Initialize new error from the HTTP request and response attributes.
|
11
|
-
def initialize(http_request, http_response)
|
12
|
-
super("#{http_request.method} request to <#{http_request.uri}> failed with code #{http_response.code}")
|
13
|
-
@http_request = http_request
|
14
|
-
@http_response = http_response
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class MalformedServerResponse < UnsuccessfulHttpRequestError
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
# Exception indicating that the server used a content coding scheme
|
23
|
-
# that Resourceful is unable to handle.
|
24
|
-
class UnsupportedContentCoding < Exception
|
25
|
-
end
|
26
|
-
|
27
|
-
# Raised when a body is supplied, but not a content-type header
|
28
|
-
class MissingContentType < ArgumentError
|
29
|
-
def initialize
|
30
|
-
super("A Content-Type must be specified when an entity-body is supplied.")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
# A case-normalizing Hash, adjusting on [] and []=.
|
2
|
-
# Shamelessly swiped from Rack
|
3
|
-
module Resourceful
|
4
|
-
class Header < Hash
|
5
|
-
def initialize(hash={})
|
6
|
-
hash.each { |k, v| self[k] = v }
|
7
|
-
end
|
8
|
-
|
9
|
-
def to_hash
|
10
|
-
{}.replace(self)
|
11
|
-
end
|
12
|
-
|
13
|
-
def [](k)
|
14
|
-
super capitalize(k)
|
15
|
-
end
|
16
|
-
|
17
|
-
def []=(k, v)
|
18
|
-
super capitalize(k), v
|
19
|
-
end
|
20
|
-
|
21
|
-
def has_key?(k)
|
22
|
-
super capitalize(k)
|
23
|
-
end
|
24
|
-
|
25
|
-
def capitalize(k)
|
26
|
-
k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-')
|
27
|
-
end
|
28
|
-
|
29
|
-
def each_field(&blk)
|
30
|
-
to_hash.each { |k,v|
|
31
|
-
blk.call capitalize(k), v
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
HEADERS = %w[
|
36
|
-
Accept
|
37
|
-
Accept-Charset
|
38
|
-
Accept-Encoding
|
39
|
-
Accept-Language
|
40
|
-
Accept-Ranges
|
41
|
-
Age
|
42
|
-
Allow
|
43
|
-
Authorization
|
44
|
-
Cache-Control
|
45
|
-
Connection
|
46
|
-
Content-Encoding
|
47
|
-
Content-Language
|
48
|
-
Content-Length
|
49
|
-
Content-Location
|
50
|
-
Content-MD5
|
51
|
-
Content-Range
|
52
|
-
Content-Type
|
53
|
-
Date
|
54
|
-
ETag
|
55
|
-
Expect
|
56
|
-
Expires
|
57
|
-
From
|
58
|
-
Host
|
59
|
-
If-Match
|
60
|
-
If-Modified-Since
|
61
|
-
If-None-Match
|
62
|
-
If-Range
|
63
|
-
If-Unmodified-Since
|
64
|
-
Keep-Alive
|
65
|
-
Last-Modified
|
66
|
-
Location
|
67
|
-
Max-Forwards
|
68
|
-
Pragma
|
69
|
-
Proxy-Authenticate
|
70
|
-
Proxy-Authorization
|
71
|
-
Range
|
72
|
-
Referer
|
73
|
-
Retry-After
|
74
|
-
Server
|
75
|
-
TE
|
76
|
-
Trailer
|
77
|
-
Transfer-Encoding
|
78
|
-
Upgrade
|
79
|
-
User-Agent
|
80
|
-
Vary
|
81
|
-
Via
|
82
|
-
Warning
|
83
|
-
WWW-Authenticate
|
84
|
-
]
|
85
|
-
|
86
|
-
HEADERS.each do |header|
|
87
|
-
const = header.upcase.gsub('-', '_')
|
88
|
-
meth = header.downcase.gsub('-', '_')
|
89
|
-
|
90
|
-
class_eval <<-RUBY, __FILE__, __LINE__
|
91
|
-
#{const} = "#{header}".freeze # ACCEPT = "accept".freeze
|
92
|
-
|
93
|
-
def #{meth} # def accept
|
94
|
-
self[#{const}] # self[ACCEPT]
|
95
|
-
end # end
|
96
|
-
|
97
|
-
def #{meth}=(str) # def accept=(str)
|
98
|
-
self[#{const}] = str # self[ACCEPT] = str
|
99
|
-
end # end
|
100
|
-
RUBY
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
HOP_BY_HOP_HEADERS = [
|
105
|
-
CONNECTION,
|
106
|
-
KEEP_ALIVE,
|
107
|
-
PROXY_AUTHENTICATE,
|
108
|
-
PROXY_AUTHORIZATION,
|
109
|
-
TE,
|
110
|
-
TRAILER,
|
111
|
-
TRANSFER_ENCODING,
|
112
|
-
UPGRADE
|
113
|
-
].freeze
|
114
|
-
|
115
|
-
NON_MODIFIABLE_HEADERS = [
|
116
|
-
CONTENT_LOCATION,
|
117
|
-
CONTENT_MD5,
|
118
|
-
ETAG,
|
119
|
-
LAST_MODIFIED,
|
120
|
-
EXPIRES
|
121
|
-
].freeze
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
|
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
|
-
require 'resourceful/options_interpreter'
|
4
|
-
require 'resourceful/authentication_manager'
|
5
|
-
require 'resourceful/cache_manager'
|
6
|
-
require 'resourceful/resource'
|
7
|
-
require 'resourceful/stubbed_resource_proxy'
|
8
|
-
|
9
|
-
module Resourceful
|
10
|
-
# This is an imitation Logger used when no real logger is
|
11
|
-
# registered. This allows most of the code to assume that there
|
12
|
-
# is always a logger available, which significantly improved the
|
13
|
-
# readability of the logging related code.
|
14
|
-
class BitBucketLogger
|
15
|
-
def warn(*args); end
|
16
|
-
def info(*args); end
|
17
|
-
def debug(*args); end
|
18
|
-
end
|
19
|
-
|
20
|
-
# This is the simplest logger. It just writes everything to STDOUT.
|
21
|
-
class StdOutLogger
|
22
|
-
def warn(*args); puts args; end
|
23
|
-
def info(*args); puts args; end
|
24
|
-
def debug(*args); puts args; end
|
25
|
-
end
|
26
|
-
|
27
|
-
# This class provides a simple interface to the functionality
|
28
|
-
# provided by the Resourceful library. Conceptually this object
|
29
|
-
# acts a collection of all the resources available via HTTP.
|
30
|
-
class HttpAccessor
|
31
|
-
|
32
|
-
# A logger object to which messages about the activities of this
|
33
|
-
# object will be written. This should be an object that responds
|
34
|
-
# to +#info(message)+ and +#debug(message)+.
|
35
|
-
#
|
36
|
-
# Errors will not be logged. Instead an exception will be raised
|
37
|
-
# and the application code should log it if appropriate.
|
38
|
-
attr_accessor :logger, :cache_manager
|
39
|
-
|
40
|
-
attr_reader :auth_manager
|
41
|
-
attr_reader :user_agent_tokens
|
42
|
-
|
43
|
-
INIT_OPTIONS = OptionsInterpreter.new do
|
44
|
-
option(:logger, :default => Resourceful::BitBucketLogger.new)
|
45
|
-
option(:user_agent, :default => []) {|ua| [ua].flatten}
|
46
|
-
option(:cache_manager, :default => NullCacheManager.new)
|
47
|
-
option(:authenticator)
|
48
|
-
option(:authenticators, :default => [])
|
49
|
-
end
|
50
|
-
|
51
|
-
# Initializes a new HttpAccessor. Valid options:
|
52
|
-
#
|
53
|
-
# +:logger+:: A Logger object that the new HTTP accessor should
|
54
|
-
# send log messages
|
55
|
-
#
|
56
|
-
# +:user_agent+:: One or more additional user agent tokens to
|
57
|
-
# added to the user agent string.
|
58
|
-
#
|
59
|
-
# +:cache_manager+:: The cache manager this accessor should use.
|
60
|
-
#
|
61
|
-
# +:authenticator+:: Add a single authenticator for this accessor.
|
62
|
-
#
|
63
|
-
# +:authenticators+:: Enumerable of the authenticators for this
|
64
|
-
# accessor.
|
65
|
-
def initialize(options = {})
|
66
|
-
@user_agent_tokens = [RESOURCEFUL_USER_AGENT_TOKEN]
|
67
|
-
|
68
|
-
INIT_OPTIONS.interpret(options) do |opts|
|
69
|
-
@user_agent_tokens.push(*opts[:user_agent].reverse)
|
70
|
-
self.logger = opts[:logger]
|
71
|
-
@auth_manager = AuthenticationManager.new()
|
72
|
-
@cache_manager = opts[:cache_manager]
|
73
|
-
|
74
|
-
add_authenticator(opts[:authenticator]) if opts[:authenticator]
|
75
|
-
opts[:authenticators].each { |a| add_authenticator(a) }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns the string that identifies this HTTP accessor. If you
|
80
|
-
# want to add a token to the user agent string simply add the new
|
81
|
-
# token to the end of +#user_agent_tokens+.
|
82
|
-
def user_agent_string
|
83
|
-
user_agent_tokens.reverse.join(' ')
|
84
|
-
end
|
85
|
-
|
86
|
-
# Returns a resource object representing the resource indicated
|
87
|
-
# by the specified URI. A resource object will be created if necessary.
|
88
|
-
def resource(uri, opts = {})
|
89
|
-
resource = Resource.new(self, uri, opts)
|
90
|
-
end
|
91
|
-
alias [] resource
|
92
|
-
|
93
|
-
# Adds an Authenticator to the set used by the accessor.
|
94
|
-
def add_authenticator(an_authenticator)
|
95
|
-
auth_manager.add_auth_handler(an_authenticator)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require "resourceful/cache_manager"
|
2
|
-
|
3
|
-
require 'memcache'
|
4
|
-
|
5
|
-
module Resourceful
|
6
|
-
class MemcacheCacheManager < AbstractCacheManager
|
7
|
-
|
8
|
-
# Create a new Memcached backed cache manager
|
9
|
-
#
|
10
|
-
# @param [*String] memcache_servers
|
11
|
-
# list of all Memcached servers this cache manager should use.
|
12
|
-
def initialize(*memcache_servers)
|
13
|
-
@memcache = MemCache.new(memcache_servers, :multithread => true)
|
14
|
-
end
|
15
|
-
|
16
|
-
# Finds a previously cached response to the provided request. The
|
17
|
-
# response returned may be stale.
|
18
|
-
#
|
19
|
-
# @param [Resourceful::Request] request
|
20
|
-
# The request for which we are looking for a response.
|
21
|
-
#
|
22
|
-
# @return [Resourceful::Response, nil]
|
23
|
-
# A (possibly stale) response for the request provided or nil if
|
24
|
-
# no matching response is found.
|
25
|
-
def lookup(request)
|
26
|
-
resp = cache_entries_for(request)[request]
|
27
|
-
return if resp.nil?
|
28
|
-
|
29
|
-
resp.authoritative = false
|
30
|
-
|
31
|
-
resp
|
32
|
-
end
|
33
|
-
|
34
|
-
# Store a response in the cache.
|
35
|
-
#
|
36
|
-
# This method is smart enough to not store responses that cannot be
|
37
|
-
# cached (Vary: * or Cache-Control: no-cache, private, ...)
|
38
|
-
#
|
39
|
-
# @param [Resourceful::Request] request
|
40
|
-
# The request used to obtain the response. This is needed so the
|
41
|
-
# values from the response's Vary header can be stored.
|
42
|
-
# @param [Resourceful::Response] response
|
43
|
-
# The response to be stored.
|
44
|
-
def store(request, response)
|
45
|
-
return unless response.cachable?
|
46
|
-
|
47
|
-
entries = cache_entries_for(request)
|
48
|
-
entries[request] = response
|
49
|
-
|
50
|
-
@memcache[request.to_mc_key] = entries
|
51
|
-
end
|
52
|
-
|
53
|
-
# Invalidates a all cached entries for a uri.
|
54
|
-
#
|
55
|
-
# This is used, for example, to invalidate the cache for a resource
|
56
|
-
# that gets POSTed to.
|
57
|
-
#
|
58
|
-
# @param [String] uri
|
59
|
-
# The uri of the resource to be invalidated
|
60
|
-
def invalidate(uri)
|
61
|
-
@memcache.delete(uri_hash(uri))
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
##
|
68
|
-
# The memcache proxy.
|
69
|
-
attr_reader :memcache
|
70
|
-
|
71
|
-
def cache_entries_for(a_request)
|
72
|
-
@memcache.get(uri_hash(a_request.uri)) || Resourceful::CacheEntryCollection.new
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'net/https'
|
3
|
-
require 'addressable/uri'
|
4
|
-
|
5
|
-
require 'pathname'
|
6
|
-
require 'resourceful/header'
|
7
|
-
|
8
|
-
module Addressable
|
9
|
-
class URI
|
10
|
-
def absolute_path
|
11
|
-
absolute_path = ""
|
12
|
-
absolute_path << self.path.to_s
|
13
|
-
absolute_path << "?#{self.query}" if self.query != nil
|
14
|
-
absolute_path << "##{self.fragment}" if self.fragment != nil
|
15
|
-
return absolute_path
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module Resourceful
|
21
|
-
|
22
|
-
class NetHttpAdapter
|
23
|
-
# Make an HTTP request using the standard library net/http.
|
24
|
-
#
|
25
|
-
# Will use a proxy defined in the http_proxy environment variable, if set.
|
26
|
-
def self.make_request(method, uri, body = nil, header = nil)
|
27
|
-
uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
|
28
|
-
|
29
|
-
req = net_http_request_class(method).new(uri.absolute_path)
|
30
|
-
header.each_field { |k,v| req[k] = v } if header
|
31
|
-
https = ("https" == uri.scheme)
|
32
|
-
conn = Net::HTTP.Proxy(*proxy_details).new(uri.host, uri.port || (https ? 443 : 80))
|
33
|
-
conn.use_ssl = https
|
34
|
-
begin
|
35
|
-
conn.start
|
36
|
-
res = conn.request(req, body)
|
37
|
-
ensure
|
38
|
-
conn.finish if conn.started?
|
39
|
-
end
|
40
|
-
|
41
|
-
[ Integer(res.code),
|
42
|
-
Resourceful::Header.new(res.header.to_hash),
|
43
|
-
res.body
|
44
|
-
]
|
45
|
-
ensure
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
# Parse proxy details from http_proxy environment variable
|
52
|
-
def self.proxy_details
|
53
|
-
proxy = Addressable::URI.parse(ENV["http_proxy"])
|
54
|
-
[proxy.host, proxy.port, proxy.user, proxy.password] if proxy
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.net_http_request_class(method)
|
58
|
-
case method
|
59
|
-
when :get then Net::HTTP::Get
|
60
|
-
when :head then Net::HTTP::Head
|
61
|
-
when :post then Net::HTTP::Post
|
62
|
-
when :put then Net::HTTP::Put
|
63
|
-
when :delete then Net::HTTP::Delete
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Resourceful
|
4
|
-
# Class that supports a declarative way to pick apart an options
|
5
|
-
# hash.
|
6
|
-
#
|
7
|
-
# OptionsInterpreter.new do
|
8
|
-
# option(:accept) { |accept| [accept].flatten.map{|m| m.to_str} }
|
9
|
-
# option(:http_header_fields, :default => {})
|
10
|
-
# end.interpret(:accept => 'this/that')
|
11
|
-
# # => {:accept => ['this/that'], :http_header_fields => { } }
|
12
|
-
#
|
13
|
-
# The returned hash contains :accept with the pass accept option
|
14
|
-
# value transformed into an array and :http_header_fields with its
|
15
|
-
# default value.
|
16
|
-
#
|
17
|
-
# OptionsInterpreter.new do
|
18
|
-
# option(:max_redirects)
|
19
|
-
# end.interpret(:foo => 1, :bar => 2)
|
20
|
-
# # Raises ArgumentError: Unrecognized options: foo, bar
|
21
|
-
#
|
22
|
-
# If options are passed that are not defined an exception is raised.
|
23
|
-
#
|
24
|
-
class OptionsInterpreter
|
25
|
-
def self.interpret(options_hash, &block)
|
26
|
-
interpreter = self.new(options_hash)
|
27
|
-
interpreter.instance_eval(&block)
|
28
|
-
|
29
|
-
interpreter.interpret
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(&block)
|
33
|
-
@handlers = Hash.new
|
34
|
-
|
35
|
-
instance_eval(&block) if block_given?
|
36
|
-
end
|
37
|
-
|
38
|
-
def interpret(options_hash, &block)
|
39
|
-
unless (unrecognized_options = (options_hash.keys - supported_options)).empty?
|
40
|
-
raise ArgumentError, "Unrecognized options: #{unrecognized_options.join(", ")}"
|
41
|
-
end
|
42
|
-
|
43
|
-
options = Hash.new
|
44
|
-
handlers.each do |opt_name, a_handler|
|
45
|
-
opt_val = a_handler.call(options_hash)
|
46
|
-
options[opt_name] = opt_val if opt_val
|
47
|
-
end
|
48
|
-
|
49
|
-
yield(options) if block_given?
|
50
|
-
|
51
|
-
options
|
52
|
-
end
|
53
|
-
|
54
|
-
def option(name, opts = {}, &block)
|
55
|
-
|
56
|
-
passed_value_fetcher = if opts[:default]
|
57
|
-
default_value = opts[:default]
|
58
|
-
lambda{|options_hash| options_hash[name] || default_value}
|
59
|
-
else
|
60
|
-
lambda{|options_hash| options_hash[name]}
|
61
|
-
end
|
62
|
-
|
63
|
-
handlers[name] = if block_given?
|
64
|
-
lambda{|options_hash| (val = passed_value_fetcher.call(options_hash)) ? block.call(val) : nil}
|
65
|
-
else
|
66
|
-
passed_value_fetcher
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def supported_options
|
71
|
-
handlers.keys
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
attr_reader :handlers
|
77
|
-
end
|
78
|
-
end
|