pezra-resourceful 0.6.0 → 0.7.0
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/History.txt +16 -0
- data/Manifest +27 -26
- data/Rakefile +1 -1
- data/lib/resourceful.rb +2 -1
- data/lib/resourceful/header.rb +154 -67
- data/lib/resourceful/http_accessor.rb +12 -13
- data/lib/resourceful/response.rb +8 -11
- data/resourceful.gemspec +10 -6
- data/spec/caching_spec.rb +1 -1
- data/spec/resourceful/header_spec.rb +148 -3
- data/spec/resourceful/http_accessor_spec.rb +56 -0
- data/spec/resourceful/response_spec.rb +51 -0
- data/spec/spec_helper.rb +4 -2
- metadata +51 -41
- data/lib/resourceful/options_interpretation.rb +0 -72
data/History.txt
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
Version 0.7.0
|
2
|
+
=============
|
3
|
+
* Multiple values in a single header field are treated the same as repeated header fields. (Peter Williams)
|
4
|
+
|
5
|
+
Compatibility issues
|
6
|
+
--------------------
|
7
|
+
|
8
|
+
* The semantics of the Resourceful::Header API have changed slightly.
|
9
|
+
Previously multiple values in a single header field
|
10
|
+
(e.g. `Accept: application/xml, application/json`) where treated
|
11
|
+
differently from multiple values occurring in multiple fields (e.g
|
12
|
+
`Accept: application/xml\n\rAccept: application/json`). This lead
|
13
|
+
to some unfortunate complexity when interacting with multi-valued
|
14
|
+
fields.
|
15
|
+
|
16
|
+
|
1
17
|
Version 0.6.0
|
2
18
|
=============
|
3
19
|
|
data/Manifest
CHANGED
@@ -1,39 +1,40 @@
|
|
1
|
-
|
2
|
-
lib/resourceful/net_http_adapter.rb
|
3
|
-
lib/resourceful/options_interpretation.rb
|
4
|
-
lib/resourceful/stubbed_resource_proxy.rb
|
5
|
-
lib/resourceful/urlencoded_form_data.rb
|
6
|
-
lib/resourceful/header.rb
|
7
|
-
lib/resourceful/memcache_cache_manager.rb
|
8
|
-
lib/resourceful/response.rb
|
9
|
-
lib/resourceful/util.rb
|
1
|
+
History.txt
|
10
2
|
lib/resourceful/abstract_form_data.rb
|
3
|
+
lib/resourceful/authentication_manager.rb
|
11
4
|
lib/resourceful/cache_manager.rb
|
12
|
-
lib/resourceful/request.rb
|
13
|
-
lib/resourceful/resource.rb
|
14
5
|
lib/resourceful/exceptions.rb
|
15
|
-
lib/resourceful/
|
6
|
+
lib/resourceful/header.rb
|
16
7
|
lib/resourceful/http_accessor.rb
|
17
|
-
lib/resourceful/
|
18
|
-
|
19
|
-
resourceful.
|
20
|
-
|
8
|
+
lib/resourceful/memcache_cache_manager.rb
|
9
|
+
lib/resourceful/multipart_form_data.rb
|
10
|
+
lib/resourceful/net_http_adapter.rb
|
11
|
+
lib/resourceful/request.rb
|
12
|
+
lib/resourceful/resource.rb
|
13
|
+
lib/resourceful/response.rb
|
14
|
+
lib/resourceful/stubbed_resource_proxy.rb
|
15
|
+
lib/resourceful/urlencoded_form_data.rb
|
16
|
+
lib/resourceful/util.rb
|
17
|
+
lib/resourceful.rb
|
18
|
+
Manifest
|
21
19
|
MIT-LICENSE
|
22
20
|
Rakefile
|
23
|
-
|
24
|
-
|
25
|
-
spec/old_acceptance_specs.rb
|
26
|
-
spec/acceptance_shared_specs.rb
|
27
|
-
spec/spec_helper.rb
|
28
|
-
spec/simple_sinatra_server.rb
|
21
|
+
README.markdown
|
22
|
+
resourceful.gemspec
|
29
23
|
spec/acceptance/authorization_spec.rb
|
30
|
-
spec/acceptance/header_spec.rb
|
31
|
-
spec/acceptance/resource_spec.rb
|
32
24
|
spec/acceptance/caching_spec.rb
|
25
|
+
spec/acceptance/header_spec.rb
|
33
26
|
spec/acceptance/redirecting_spec.rb
|
34
|
-
spec/
|
27
|
+
spec/acceptance/resource_spec.rb
|
28
|
+
spec/acceptance_shared_specs.rb
|
29
|
+
spec/caching_spec.rb
|
30
|
+
spec/old_acceptance_specs.rb
|
35
31
|
spec/resourceful/header_spec.rb
|
32
|
+
spec/resourceful/http_accessor_spec.rb
|
33
|
+
spec/resourceful/multipart_form_data_spec.rb
|
36
34
|
spec/resourceful/resource_spec.rb
|
35
|
+
spec/resourceful/response_spec.rb
|
37
36
|
spec/resourceful/urlencoded_form_data_spec.rb
|
38
|
-
spec/
|
37
|
+
spec/simple_sinatra_server.rb
|
38
|
+
spec/simple_sinatra_server_spec.rb
|
39
39
|
spec/spec.opts
|
40
|
+
spec/spec_helper.rb
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
p.email = "psadauskas@gmail.com"
|
13
13
|
|
14
14
|
p.ignore_pattern = ["pkg/*", "tmp/*"]
|
15
|
-
p.dependencies = [['addressable', '>= 2.1.0'], 'httpauth']
|
15
|
+
p.dependencies = [['addressable', '>= 2.1.0'], 'httpauth', ['options', '>= 2.2.0']]
|
16
16
|
p.development_dependencies = ['thin', 'yard', 'sinatra', 'rspec']
|
17
17
|
p.retain_gemspec = true
|
18
18
|
end
|
data/lib/resourceful.rb
CHANGED
@@ -13,10 +13,11 @@ require 'resourceful/http_accessor'
|
|
13
13
|
module Resourceful
|
14
14
|
autoload :MultipartFormData, 'resourceful/multipart_form_data'
|
15
15
|
autoload :UrlencodedFormData, 'resourceful/urlencoded_form_data'
|
16
|
+
autoload :StubbedResourceProxy, 'resourceful/stubbed_resource_proxy'
|
16
17
|
end
|
17
18
|
|
18
19
|
# Resourceful is a library that provides a high level HTTP interface.
|
19
20
|
module Resourceful
|
20
|
-
VERSION = "0.
|
21
|
+
VERSION = "0.7.0"
|
21
22
|
RESOURCEFUL_USER_AGENT_TOKEN = "Resourceful/#{VERSION}(Ruby/#{RUBY_VERSION})"
|
22
23
|
end
|
data/lib/resourceful/header.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'options'
|
2
2
|
require 'set'
|
3
|
+
require 'facets/memoize'
|
3
4
|
|
4
5
|
# Represents the header fields of an HTTP message. To access a field
|
5
6
|
# you can use `#[]` and `#[]=`. For example, to get the content type
|
@@ -53,11 +54,25 @@ module Resourceful
|
|
53
54
|
def has_key?(k)
|
54
55
|
field_def(k).exists_in?(@raw_fields)
|
55
56
|
end
|
57
|
+
alias has_field? has_key?
|
56
58
|
|
57
59
|
def each(&blk)
|
58
60
|
@raw_fields.each(&blk)
|
59
61
|
end
|
60
|
-
|
62
|
+
|
63
|
+
# Iterates through the fields with values provided as message
|
64
|
+
# ready strings.
|
65
|
+
def each_field(&blk)
|
66
|
+
each do |k,v|
|
67
|
+
str_v = if field_def(k).multivalued?
|
68
|
+
v.join(', ')
|
69
|
+
else
|
70
|
+
v.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
yield k, str_v
|
74
|
+
end
|
75
|
+
end
|
61
76
|
|
62
77
|
def merge!(another)
|
63
78
|
another.each do |k,v|
|
@@ -78,43 +93,61 @@ module Resourceful
|
|
78
93
|
self.class.new(@raw_fields.dup)
|
79
94
|
end
|
80
95
|
|
81
|
-
|
82
96
|
# Class to handle the details of each type of field.
|
83
|
-
class
|
97
|
+
class FieldDesc
|
84
98
|
include Comparable
|
85
|
-
|
86
|
-
|
99
|
+
|
87
100
|
##
|
88
101
|
attr_reader :name
|
89
|
-
|
102
|
+
|
103
|
+
# Create a new header field descriptor.
|
104
|
+
#
|
105
|
+
# @param [String] name The canonical name of this field.
|
106
|
+
#
|
107
|
+
# @param [Hash] options hash containing extra information about
|
108
|
+
# this header fields. Valid keys are:
|
109
|
+
#
|
110
|
+
# `:multivalued`
|
111
|
+
# `:multivalue`
|
112
|
+
# `:repeatable`
|
113
|
+
# : Values of this field are comma separated list of values.
|
114
|
+
# (n#VALUE per HTTP spec.) Default: false
|
115
|
+
#
|
116
|
+
# `:hop_by_hop`
|
117
|
+
# : True if the header is a hop-by-hop header. Default: false
|
118
|
+
#
|
119
|
+
# `:modifiable`
|
120
|
+
# : False if the header should not be modified by intermediates or caches. Default: true
|
121
|
+
#
|
90
122
|
def initialize(name, options = {})
|
91
123
|
@name = name
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
124
|
+
options = Options.for(options).validate(:repeatable, :hop_by_hop, :modifiable)
|
125
|
+
|
126
|
+
@repeatable = options.getopt([:repeatable, :multivalue, :multivalued]) || false
|
127
|
+
@hop_by_hop = options.getopt(:hop_by_hop) || false
|
128
|
+
@modifiable = options.getopt(:modifiable, true)
|
97
129
|
end
|
98
|
-
|
130
|
+
|
99
131
|
def repeatable?
|
100
132
|
@repeatable
|
101
133
|
end
|
102
|
-
|
134
|
+
alias multivalued? repeatable?
|
135
|
+
|
103
136
|
def hop_by_hop?
|
104
137
|
@hop_by_hop
|
105
138
|
end
|
106
|
-
|
139
|
+
|
107
140
|
def modifiable?
|
108
141
|
@modifiable
|
109
142
|
end
|
110
|
-
|
143
|
+
|
111
144
|
def get_from(raw_fields_hash)
|
112
145
|
raw_fields_hash[name]
|
113
146
|
end
|
114
|
-
|
147
|
+
|
115
148
|
def set_to(value, raw_fields_hash)
|
116
|
-
raw_fields_hash[name] = if
|
117
|
-
Array(value)
|
149
|
+
raw_fields_hash[name] = if multivalued?
|
150
|
+
Array(value).map{|v| v.split(/,\s*/)}.flatten
|
118
151
|
elsif value.kind_of?(Array)
|
119
152
|
raise ArgumentError, "#{name} field may only have one value" if value.size > 1
|
120
153
|
value.first
|
@@ -122,86 +155,140 @@ module Resourceful
|
|
122
155
|
value
|
123
156
|
end
|
124
157
|
end
|
125
|
-
|
158
|
+
|
126
159
|
def exists_in?(raw_fields_hash)
|
127
160
|
raw_fields_hash.has_key?(name)
|
128
161
|
end
|
129
|
-
|
162
|
+
|
130
163
|
def <=>(another)
|
131
164
|
name <=> another.name
|
132
165
|
end
|
133
|
-
|
166
|
+
|
134
167
|
def ==(another)
|
135
|
-
name_pattern === another.
|
168
|
+
name_pattern === another.to_s
|
136
169
|
end
|
137
170
|
alias eql? ==
|
138
|
-
|
171
|
+
|
139
172
|
def ===(another)
|
140
|
-
if another.kind_of?(
|
173
|
+
if another.kind_of?(FieldDesc)
|
141
174
|
self == another
|
142
175
|
else
|
143
176
|
name_pattern === another
|
144
177
|
end
|
145
178
|
end
|
146
|
-
|
179
|
+
|
147
180
|
def name_pattern
|
148
|
-
Regexp.new('^' + name.gsub('-', '[_-]') + '$', Regexp::IGNORECASE)
|
181
|
+
@name_pattern ||= Regexp.new('^' + name.gsub('-', '[_-]') + '$', Regexp::IGNORECASE)
|
149
182
|
end
|
150
|
-
|
183
|
+
|
151
184
|
def methodized_name
|
152
|
-
name.downcase.gsub('-', '_')
|
185
|
+
@methodized_name ||= name.downcase.gsub('-', '_')
|
153
186
|
end
|
154
|
-
|
187
|
+
|
188
|
+
def constantized_name
|
189
|
+
@constantized_name ||= name.upcase.gsub('-', '_')
|
190
|
+
end
|
191
|
+
|
155
192
|
alias to_s name
|
156
|
-
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
193
|
+
|
194
|
+
def accessor_module
|
195
|
+
@accessor_module ||= begin
|
196
|
+
Module.new.tap{|m| m.module_eval(<<-RUBY)}
|
197
|
+
#{constantized_name} = '#{name}'
|
198
|
+
|
199
|
+
def #{methodized_name} # def accept
|
200
|
+
self[#{constantized_name}] # self[ACCEPT]
|
201
|
+
end # end
|
202
|
+
|
203
|
+
def #{methodized_name}=(val) # def accept=(val)
|
204
|
+
self[#{constantized_name}] = val # self[ACCEPT] = val
|
205
|
+
end # end
|
206
|
+
RUBY
|
207
|
+
end
|
163
208
|
end
|
164
209
|
|
165
|
-
def
|
166
|
-
|
167
|
-
def #{methodized_name} # def accept
|
168
|
-
self['#{name}'] # self['Accept']
|
169
|
-
end # end
|
170
|
-
RUBY
|
210
|
+
def hash
|
211
|
+
@name.hash
|
171
212
|
end
|
172
|
-
|
173
|
-
def gen_canonical_name_const(klass)
|
174
|
-
const_name = name.upcase.gsub('-', '_')
|
175
213
|
|
176
|
-
|
214
|
+
# Yields each commonly used lookup key for this header field.
|
215
|
+
def lookup_keys(&blk)
|
216
|
+
yield name
|
217
|
+
yield name.upcase
|
218
|
+
yield name.downcase
|
219
|
+
yield methodized_name
|
220
|
+
yield methodized_name.to_sym
|
221
|
+
yield constantized_name
|
222
|
+
yield constantized_name.to_sym
|
177
223
|
end
|
178
|
-
end
|
179
|
-
|
180
|
-
@@
|
181
|
-
|
224
|
+
end # FieldDesc
|
225
|
+
|
226
|
+
@@known_fields = Set.new
|
227
|
+
@@known_fields_lookup = Hash.new
|
228
|
+
|
229
|
+
# Declares a common header field. Header fields do not have to be
|
230
|
+
# defined this way but accessing them is easier, safer and faster
|
231
|
+
# if you do. Declaring a field does the following things:
|
232
|
+
#
|
233
|
+
# * defines accessor methods (e.g. `#content_type` and
|
234
|
+
# `#content_type=`) on `Header`
|
235
|
+
#
|
236
|
+
# * defines constant that can be used to reference there field
|
237
|
+
# name (e.g. `some_header[Header::CONTENT_TYPE]`)
|
238
|
+
#
|
239
|
+
# * includes the field in the appropriate *_fields groups (e.g. `Header.non_modifiable_fields`)
|
240
|
+
#
|
241
|
+
# * provides improved multiple value parsing
|
242
|
+
#
|
243
|
+
# Create a new header field descriptor.
|
244
|
+
#
|
245
|
+
# @param [String] name The canonical name of this field.
|
246
|
+
#
|
247
|
+
# @param [Hash] options hash containing extra information about
|
248
|
+
# this header fields. Valid keys are:
|
249
|
+
#
|
250
|
+
# `:multivalued`
|
251
|
+
# `:multivalue`
|
252
|
+
# `:repeatable`
|
253
|
+
# : Values of this field are comma separated list of values.
|
254
|
+
# (n#VALUE per HTTP spec.) Default: false
|
255
|
+
#
|
256
|
+
# `:hop_by_hop`
|
257
|
+
# : True if the header is a hop-by-hop header. Default: false
|
258
|
+
#
|
259
|
+
# `:modifiable`
|
260
|
+
# : False if the header should not be modified by intermediates or caches. Default: true
|
261
|
+
#
|
182
262
|
def self.header_field(name, options = {})
|
183
|
-
hfd =
|
184
|
-
|
185
|
-
@@
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
hfd.gen_canonical_name_const(self)
|
190
|
-
end
|
263
|
+
hfd = FieldDesc.new(name, options)
|
264
|
+
|
265
|
+
@@known_fields << hfd
|
266
|
+
hfd.lookup_keys do |a_key|
|
267
|
+
@@known_fields_lookup[a_key] = hfd
|
268
|
+
end
|
191
269
|
|
192
|
-
|
193
|
-
@@header_field_defs.select{|hfd| hfd.hop_by_hop?}
|
270
|
+
include(hfd.accessor_module)
|
194
271
|
end
|
195
|
-
|
196
|
-
def self.
|
197
|
-
@@
|
272
|
+
|
273
|
+
def self.hop_by_hop_fields
|
274
|
+
@@known_fields.select{|hfd| hfd.hop_by_hop?}
|
198
275
|
end
|
199
276
|
|
200
|
-
def
|
201
|
-
@@
|
202
|
-
HeaderFieldDef.new(name.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-'), :repeatable => true)
|
277
|
+
def self.non_modifiable_fields
|
278
|
+
@@known_fields.reject{|hfd| hfd.modifiable?}
|
203
279
|
end
|
204
280
|
|
281
|
+
protected
|
282
|
+
|
283
|
+
# ---
|
284
|
+
#
|
285
|
+
# We have to fall back on a slow iteration to find the header
|
286
|
+
# field some times because field names are
|
287
|
+
def field_def(name)
|
288
|
+
@@known_fields_lookup[name] || # the fast way
|
289
|
+
@@known_fields.find{|hfd| hfd === name} || # the slow way
|
290
|
+
FieldDesc.new(name.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-'), :repeatable => true) # make up as we go
|
291
|
+
end
|
205
292
|
|
206
293
|
header_field('Accept', :repeatable => true)
|
207
294
|
header_field('Accept-Charset', :repeatable => true)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
|
3
|
-
require 'resourceful/options_interpretation'
|
4
3
|
require 'resourceful/authentication_manager'
|
5
4
|
require 'resourceful/cache_manager'
|
6
5
|
require 'resourceful/resource'
|
7
|
-
|
6
|
+
|
7
|
+
require 'options'
|
8
8
|
|
9
9
|
module Resourceful
|
10
10
|
# This is an imitation Logger used when no real logger is
|
@@ -28,8 +28,6 @@ module Resourceful
|
|
28
28
|
# provided by the Resourceful library. Conceptually this object
|
29
29
|
# acts a collection of all the resources available via HTTP.
|
30
30
|
class HttpAccessor
|
31
|
-
include OptionsInterpretation
|
32
|
-
|
33
31
|
# A logger object to which messages about the activities of this
|
34
32
|
# object will be written. This should be an object that responds
|
35
33
|
# to +#info(message)+ and +#debug(message)+.
|
@@ -67,18 +65,19 @@ module Resourceful
|
|
67
65
|
#
|
68
66
|
#
|
69
67
|
def initialize(options = {})
|
68
|
+
options = Options.for(options).validate(:logger, :user_agent, :cache_manager, :authenticator, :authenticators, :http_adapter)
|
69
|
+
|
70
70
|
@user_agent_tokens = [RESOURCEFUL_USER_AGENT_TOKEN]
|
71
71
|
@auth_manager = AuthenticationManager.new()
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
opts.extract(:authenticators, :default => []).each { |a| add_authenticator(a) }
|
73
|
+
|
74
|
+
@user_agent_tokens.push(*Array(options.getopt(:user_agent)).flatten.reverse)
|
75
|
+
self.logger = options.getopt(:logger) || BitBucketLogger.new
|
76
|
+
@cache_manager = options.getopt(:cache_manager) || NullCacheManager.new
|
77
|
+
@http_adapter = options.getopt(:http_adapter) || NetHttpAdapter.new
|
78
|
+
|
79
|
+
Array(options.getopt([:authenticator, :authenticators])).flatten.each do |an_authenticator|
|
80
|
+
add_authenticator(an_authenticator)
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
data/lib/resourceful/response.rb
CHANGED
@@ -23,11 +23,10 @@ module Resourceful
|
|
23
23
|
#
|
24
24
|
# @return true|false
|
25
25
|
def expired?
|
26
|
-
if header
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
return true if Time.httpdate(header['Expires']) < Time.now
|
26
|
+
if header.cache_control and m_age_str = header.cache_control.find{|cc| /^max-age=/ === cc}
|
27
|
+
return current_age > m_age_str[/\d+/].to_i
|
28
|
+
elsif header.expires
|
29
|
+
return Time.httpdate(header.expires) < Time.now
|
31
30
|
end
|
32
31
|
|
33
32
|
false
|
@@ -38,10 +37,8 @@ module Resourceful
|
|
38
37
|
# @return true|false
|
39
38
|
def stale?
|
40
39
|
return true if expired?
|
41
|
-
|
42
|
-
|
43
|
-
return true if header['Cache-Control'].include?('no-cache')
|
44
|
-
end
|
40
|
+
return false unless header.has_field?(Header::CACHE_CONTROL)
|
41
|
+
return true if header.cache_control.any?{|cc| /must-revalidate|no-cache/ === cc}
|
45
42
|
|
46
43
|
false
|
47
44
|
end
|
@@ -75,8 +72,8 @@ module Resourceful
|
|
75
72
|
|
76
73
|
# Algorithm taken from RCF2616#13.2.3
|
77
74
|
def current_age
|
78
|
-
age_value = header
|
79
|
-
date_value = Time.httpdate(header
|
75
|
+
age_value = header.age.to_i
|
76
|
+
date_value = Time.httpdate(header.date)
|
80
77
|
now = Time.now
|
81
78
|
|
82
79
|
apparent_age = [0, response_time - date_value].max
|
data/resourceful.gemspec
CHANGED
@@ -2,29 +2,31 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{resourceful}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.7.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Paul Sadauskas"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-25}
|
10
10
|
s.description = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
|
11
11
|
s.email = %q{psadauskas@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["lib/resourceful
|
13
|
-
s.files = ["
|
12
|
+
s.extra_rdoc_files = ["lib/resourceful/abstract_form_data.rb", "lib/resourceful/authentication_manager.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/header.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/response.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/util.rb", "lib/resourceful.rb", "README.markdown"]
|
13
|
+
s.files = ["History.txt", "lib/resourceful/abstract_form_data.rb", "lib/resourceful/authentication_manager.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/header.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/response.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/util.rb", "lib/resourceful.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.markdown", "resourceful.gemspec", "spec/acceptance/authorization_spec.rb", "spec/acceptance/caching_spec.rb", "spec/acceptance/header_spec.rb", "spec/acceptance/redirecting_spec.rb", "spec/acceptance/resource_spec.rb", "spec/acceptance_shared_specs.rb", "spec/caching_spec.rb", "spec/old_acceptance_specs.rb", "spec/resourceful/header_spec.rb", "spec/resourceful/http_accessor_spec.rb", "spec/resourceful/multipart_form_data_spec.rb", "spec/resourceful/resource_spec.rb", "spec/resourceful/response_spec.rb", "spec/resourceful/urlencoded_form_data_spec.rb", "spec/simple_sinatra_server.rb", "spec/simple_sinatra_server_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
|
14
|
+
s.has_rdoc = true
|
14
15
|
s.homepage = %q{http://github.com/paul/resourceful}
|
15
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Resourceful", "--main", "README.markdown"]
|
16
17
|
s.require_paths = ["lib"]
|
17
18
|
s.rubyforge_project = %q{resourceful}
|
18
|
-
s.rubygems_version = %q{1.3.
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
19
20
|
s.summary = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
|
20
21
|
|
21
22
|
if s.respond_to? :specification_version then
|
22
23
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
-
s.specification_version =
|
24
|
+
s.specification_version = 2
|
24
25
|
|
25
26
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
27
|
s.add_runtime_dependency(%q<addressable>, [">= 2.1.0"])
|
27
28
|
s.add_runtime_dependency(%q<httpauth>, [">= 0"])
|
29
|
+
s.add_runtime_dependency(%q<options>, [">= 2.2.0"])
|
28
30
|
s.add_development_dependency(%q<thin>, [">= 0"])
|
29
31
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
30
32
|
s.add_development_dependency(%q<sinatra>, [">= 0"])
|
@@ -32,6 +34,7 @@ Gem::Specification.new do |s|
|
|
32
34
|
else
|
33
35
|
s.add_dependency(%q<addressable>, [">= 2.1.0"])
|
34
36
|
s.add_dependency(%q<httpauth>, [">= 0"])
|
37
|
+
s.add_dependency(%q<options>, [">= 2.2.0"])
|
35
38
|
s.add_dependency(%q<thin>, [">= 0"])
|
36
39
|
s.add_dependency(%q<yard>, [">= 0"])
|
37
40
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
@@ -40,6 +43,7 @@ Gem::Specification.new do |s|
|
|
40
43
|
else
|
41
44
|
s.add_dependency(%q<addressable>, [">= 2.1.0"])
|
42
45
|
s.add_dependency(%q<httpauth>, [">= 0"])
|
46
|
+
s.add_dependency(%q<options>, [">= 2.2.0"])
|
43
47
|
s.add_dependency(%q<thin>, [">= 0"])
|
44
48
|
s.add_dependency(%q<yard>, [">= 0"])
|
45
49
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
data/spec/caching_spec.rb
CHANGED
@@ -1,8 +1,153 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../spec_helper.rb"
|
2
2
|
|
3
|
+
module Resourceful
|
4
|
+
describe Header do
|
5
|
+
def self.should_support_header(name)
|
6
|
+
const_name = name.upcase.gsub('-', '_')
|
7
|
+
meth_name = name.downcase.gsub('-', '_')
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
9
|
+
eval <<-RUBY
|
10
|
+
it "should have constant `#{const_name}` for header `#{name}`" do
|
11
|
+
Resourceful::Header::#{const_name}.should == '#{name}'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have accessor method `#{meth_name}` for header `#{name}`" do
|
15
|
+
Resourceful::Header.new.should respond_to(:#{meth_name})
|
16
|
+
end
|
17
|
+
|
18
|
+
RUBY
|
19
|
+
end
|
20
|
+
|
21
|
+
should_support_header('Accept')
|
22
|
+
should_support_header('Accept-Charset')
|
23
|
+
should_support_header('Accept-Encoding')
|
24
|
+
should_support_header('Accept-Language')
|
25
|
+
should_support_header('Accept-Ranges')
|
26
|
+
should_support_header('Age')
|
27
|
+
should_support_header('Allow')
|
28
|
+
should_support_header('Authorization')
|
29
|
+
should_support_header('Cache-Control')
|
30
|
+
should_support_header('Connection')
|
31
|
+
should_support_header('Content-Encoding')
|
32
|
+
should_support_header('Content-Language')
|
33
|
+
should_support_header('Content-Length')
|
34
|
+
should_support_header('Content-Location')
|
35
|
+
should_support_header('Content-MD5')
|
36
|
+
should_support_header('Content-Range')
|
37
|
+
should_support_header('Content-Type')
|
38
|
+
should_support_header('Date')
|
39
|
+
should_support_header('ETag')
|
40
|
+
should_support_header('Expect')
|
41
|
+
should_support_header('Expires')
|
42
|
+
should_support_header('From')
|
43
|
+
should_support_header('Host')
|
44
|
+
should_support_header('If-Match')
|
45
|
+
should_support_header('If-Modified-Since')
|
46
|
+
should_support_header('If-None-Match')
|
47
|
+
should_support_header('If-Range')
|
48
|
+
should_support_header('If-Unmodified-Since')
|
49
|
+
should_support_header('Keep-Alive')
|
50
|
+
should_support_header('Last-Modified')
|
51
|
+
should_support_header('Location')
|
52
|
+
should_support_header('Max-Forwards')
|
53
|
+
should_support_header('Pragma')
|
54
|
+
should_support_header('Proxy-Authenticate')
|
55
|
+
should_support_header('Proxy-Authorization')
|
56
|
+
should_support_header('Range')
|
57
|
+
should_support_header('Referer')
|
58
|
+
should_support_header('Retry-After')
|
59
|
+
should_support_header('Server')
|
60
|
+
should_support_header('TE')
|
61
|
+
should_support_header('Trailer')
|
62
|
+
should_support_header('Transfer-Encoding')
|
63
|
+
should_support_header('Upgrade')
|
64
|
+
should_support_header('User-Agent')
|
65
|
+
should_support_header('Vary')
|
66
|
+
should_support_header('Via')
|
67
|
+
should_support_header('Warning')
|
68
|
+
should_support_header('WWW-Authenticate')
|
69
|
+
|
70
|
+
|
71
|
+
it "should be instantiatable w/ single valued header fields" do
|
72
|
+
Header.new('Host' => 'foo.example').
|
73
|
+
host.should eql('foo.example')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should gracefully handle repeated values for single valued header fields" do
|
77
|
+
lambda {
|
78
|
+
Header.new('Host' => ['foo.example', 'bar.example'])
|
79
|
+
}.should raise_error(ArgumentError, 'Host field may only have one value')
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should provide #each_fields to iterate through all header fields and values as strings" do
|
83
|
+
field_names = []
|
84
|
+
Header.new('Accept' => "this", :content_type => "that", 'pragma' => 'test').each_field do |fname, _|
|
85
|
+
field_names << fname
|
86
|
+
end
|
87
|
+
|
88
|
+
field_names.should include('Accept')
|
89
|
+
field_names.should include('Content-Type')
|
90
|
+
field_names.should include('Pragma')
|
91
|
+
field_names.should have(3).items
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should provide #to_hash as a way to dump the header fields" do
|
95
|
+
Header.new('Accept' => "this", :content_type => "that", 'date' => 'today').to_hash.tap do |h|
|
96
|
+
h.should have_pair('Accept', ['this'])
|
97
|
+
h.should have_pair('Content-Type', 'that')
|
98
|
+
h.should have_pair('Date', 'today')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should provide a list of hop-by-hop fields" do
|
103
|
+
Header.header_field('X-Hop-By-Hop-Header', :hop_by_hop => true)
|
104
|
+
Header.hop_by_hop_fields.should include('X-Hop-By-Hop-Header')
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should provide a list of not modified fields" do
|
108
|
+
Header.header_field('X-Dont-Modify-Me', :modifiable => false)
|
109
|
+
Header.non_modifiable_fields.should include('X-Dont-Modify-Me')
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "multi-valued fields" do
|
113
|
+
it "should be instantiatable w/ repeated multi-valued header fields" do
|
114
|
+
Header.new('Accept' => ['application/foo', 'application/bar']).
|
115
|
+
accept.should eql(['application/foo', 'application/bar'])
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should be instantiatable w/ repeated multi-valued header fields w/ multiple values" do
|
119
|
+
Header.new('Accept' => ['application/foo, application/bar', 'text/plain']).
|
120
|
+
accept.should eql(['application/foo', 'application/bar', 'text/plain'])
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be instantiatable w/ multi-valued header fields w/ multiple values" do
|
124
|
+
Header.new('Accept' => 'application/foo, application/bar').
|
125
|
+
accept.should eql(['application/foo', 'application/bar'])
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should be instantiatable w/ multi-valued header fields w/ one value" do
|
129
|
+
Header.new('Accept' => 'application/foo').
|
130
|
+
accept.should eql(['application/foo'])
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should provide values to #each_field as a comma separated string" do
|
134
|
+
Header.new('Accept' => ['this', 'that']).each_field do |fname, fval|
|
135
|
+
fval.should == 'this, that'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should provide #each as a way to iterate through fields as w/ higher level values" do
|
140
|
+
Header.new('Accept' => ['this', 'that']).each do |fname, fval|
|
141
|
+
fval.should == ['this', 'that']
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
Spec::Matchers.define :have_pair do |name, value|
|
147
|
+
match do |header_hash|
|
148
|
+
header_hash.has_key?(name)
|
149
|
+
header_hash[name] == value
|
150
|
+
end
|
151
|
+
end
|
7
152
|
end
|
8
153
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
require "resourceful/http_accessor"
|
4
|
+
|
5
|
+
module Resourceful
|
6
|
+
describe HttpAccessor do
|
7
|
+
describe "instantiation" do
|
8
|
+
it "should accept logger option" do
|
9
|
+
test_logger = stub('logger', :debug => false)
|
10
|
+
ha = HttpAccessor.new(:logger => test_logger)
|
11
|
+
ha.logger.should equal(test_logger)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should accept array user_agent option" do
|
15
|
+
ha = HttpAccessor.new(:user_agent => ['foo/3.2', 'bar/1.0'])
|
16
|
+
ha.user_agent_string.should match(/^foo\/3.2 bar\/1.0 Resourceful/)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should accept string user_agent option" do
|
20
|
+
ha = HttpAccessor.new(:user_agent => 'foo')
|
21
|
+
ha.user_agent_string.should match(/^foo Resourceful/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should accept cache_manager option" do
|
25
|
+
test_cache_manager = stub('cache_manager', :debug => false)
|
26
|
+
ha = HttpAccessor.new(:cache_manager => test_cache_manager)
|
27
|
+
ha.cache_manager.should equal(test_cache_manager)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should accept http_adapter option" do
|
31
|
+
test_http_adapter = stub('http_adapter', :debug => false)
|
32
|
+
ha = HttpAccessor.new(:http_adapter => test_http_adapter)
|
33
|
+
ha.http_adapter.should equal(test_http_adapter)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should accept authenticator option" do
|
37
|
+
test_authenticator = stub('authenticator', :debug => false)
|
38
|
+
ha = HttpAccessor.new(:authenticator => test_authenticator)
|
39
|
+
# cannot really be tested safely so we just rely on the fact that the option was accepted
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should accept authenticators option" do
|
43
|
+
test_authenticator1 = stub('authenticator1', :debug => false)
|
44
|
+
test_authenticator2 = stub('authenticator2', :debug => false)
|
45
|
+
ha = HttpAccessor.new(:authenticator => [test_authenticator1, test_authenticator2])
|
46
|
+
# cannot really be tested safely so we just rely on the fact that the option was accepted
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should reject unrecognized options" do
|
50
|
+
lambda {
|
51
|
+
HttpAccessor.new(:not_a_valid_option => "this")
|
52
|
+
}.should raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
require 'resourceful/response'
|
4
|
+
require 'resourceful/header'
|
5
|
+
|
6
|
+
module Resourceful
|
7
|
+
describe Response do
|
8
|
+
|
9
|
+
it "should know when it is expired" do
|
10
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'max-age=2', 'Date' => (Time.now - 2).httpdate), nil)
|
11
|
+
resp.request_time = Time.now
|
12
|
+
|
13
|
+
resp.expired?.should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should know when it is not expired" do
|
17
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'max-age=1', 'Date' => Time.now.httpdate), nil)
|
18
|
+
resp.request_time = Time.now
|
19
|
+
|
20
|
+
resp.expired?.should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
it "know when it is stale due to expiration" do
|
24
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'max-age=1', 'Date' => (Time.now - 2).httpdate), nil)
|
25
|
+
resp.request_time = Time.now
|
26
|
+
|
27
|
+
resp.stale?.should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "know when it is stale due to no-cache" do
|
31
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'no-cache', 'Date' => Time.now.httpdate), nil)
|
32
|
+
resp.request_time = Time.now
|
33
|
+
|
34
|
+
resp.stale?.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "know when it is stale due to must-revalidate" do
|
38
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'must-revalidate', 'Date' => Time.now.httpdate), nil)
|
39
|
+
resp.request_time = Time.now
|
40
|
+
|
41
|
+
resp.stale?.should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "know when it is not stale" do
|
45
|
+
resp = Response.new(nil, nil, Header.new('Cache-Control' => 'max-age=1', 'Date' => Time.now.httpdate), nil)
|
46
|
+
resp.request_time = Time.now
|
47
|
+
|
48
|
+
resp.stale?.should be_false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,10 +2,12 @@ require 'rubygems'
|
|
2
2
|
require 'spec'
|
3
3
|
require 'pp'
|
4
4
|
|
5
|
-
|
5
|
+
__DIR__ = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH << File.join(__DIR__, "..", "lib")
|
6
8
|
require 'resourceful'
|
7
9
|
|
8
|
-
$LOAD_PATH <<
|
10
|
+
$LOAD_PATH << __DIR__ # ./spec
|
9
11
|
|
10
12
|
# Spawn the server in another process
|
11
13
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pezra-resourceful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Sadauskas
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-25 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +32,16 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: options
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.2.0
|
44
|
+
version:
|
35
45
|
- !ruby/object:Gem::Dependency
|
36
46
|
name: thin
|
37
47
|
type: :development
|
@@ -79,65 +89,65 @@ executables: []
|
|
79
89
|
extensions: []
|
80
90
|
|
81
91
|
extra_rdoc_files:
|
82
|
-
- lib/resourceful.rb
|
83
|
-
- lib/resourceful/net_http_adapter.rb
|
84
|
-
- lib/resourceful/options_interpretation.rb
|
85
|
-
- lib/resourceful/stubbed_resource_proxy.rb
|
86
|
-
- lib/resourceful/urlencoded_form_data.rb
|
87
|
-
- lib/resourceful/header.rb
|
88
|
-
- lib/resourceful/memcache_cache_manager.rb
|
89
|
-
- lib/resourceful/response.rb
|
90
|
-
- lib/resourceful/util.rb
|
91
92
|
- lib/resourceful/abstract_form_data.rb
|
93
|
+
- lib/resourceful/authentication_manager.rb
|
92
94
|
- lib/resourceful/cache_manager.rb
|
93
|
-
- lib/resourceful/request.rb
|
94
|
-
- lib/resourceful/resource.rb
|
95
95
|
- lib/resourceful/exceptions.rb
|
96
|
-
- lib/resourceful/
|
96
|
+
- lib/resourceful/header.rb
|
97
97
|
- lib/resourceful/http_accessor.rb
|
98
|
-
- lib/resourceful/
|
99
|
-
-
|
100
|
-
files:
|
101
|
-
- lib/resourceful.rb
|
98
|
+
- lib/resourceful/memcache_cache_manager.rb
|
99
|
+
- lib/resourceful/multipart_form_data.rb
|
102
100
|
- lib/resourceful/net_http_adapter.rb
|
103
|
-
- lib/resourceful/
|
101
|
+
- lib/resourceful/request.rb
|
102
|
+
- lib/resourceful/resource.rb
|
103
|
+
- lib/resourceful/response.rb
|
104
104
|
- lib/resourceful/stubbed_resource_proxy.rb
|
105
105
|
- lib/resourceful/urlencoded_form_data.rb
|
106
|
-
- lib/resourceful/header.rb
|
107
|
-
- lib/resourceful/memcache_cache_manager.rb
|
108
|
-
- lib/resourceful/response.rb
|
109
106
|
- lib/resourceful/util.rb
|
107
|
+
- lib/resourceful.rb
|
108
|
+
- README.markdown
|
109
|
+
files:
|
110
|
+
- History.txt
|
110
111
|
- lib/resourceful/abstract_form_data.rb
|
112
|
+
- lib/resourceful/authentication_manager.rb
|
111
113
|
- lib/resourceful/cache_manager.rb
|
112
|
-
- lib/resourceful/request.rb
|
113
|
-
- lib/resourceful/resource.rb
|
114
114
|
- lib/resourceful/exceptions.rb
|
115
|
-
- lib/resourceful/
|
115
|
+
- lib/resourceful/header.rb
|
116
116
|
- lib/resourceful/http_accessor.rb
|
117
|
-
- lib/resourceful/
|
118
|
-
-
|
119
|
-
- resourceful.
|
120
|
-
-
|
117
|
+
- lib/resourceful/memcache_cache_manager.rb
|
118
|
+
- lib/resourceful/multipart_form_data.rb
|
119
|
+
- lib/resourceful/net_http_adapter.rb
|
120
|
+
- lib/resourceful/request.rb
|
121
|
+
- lib/resourceful/resource.rb
|
122
|
+
- lib/resourceful/response.rb
|
123
|
+
- lib/resourceful/stubbed_resource_proxy.rb
|
124
|
+
- lib/resourceful/urlencoded_form_data.rb
|
125
|
+
- lib/resourceful/util.rb
|
126
|
+
- lib/resourceful.rb
|
127
|
+
- Manifest
|
121
128
|
- MIT-LICENSE
|
122
129
|
- Rakefile
|
123
|
-
-
|
124
|
-
-
|
125
|
-
- spec/old_acceptance_specs.rb
|
126
|
-
- spec/acceptance_shared_specs.rb
|
127
|
-
- spec/spec_helper.rb
|
128
|
-
- spec/simple_sinatra_server.rb
|
130
|
+
- README.markdown
|
131
|
+
- resourceful.gemspec
|
129
132
|
- spec/acceptance/authorization_spec.rb
|
130
|
-
- spec/acceptance/header_spec.rb
|
131
|
-
- spec/acceptance/resource_spec.rb
|
132
133
|
- spec/acceptance/caching_spec.rb
|
134
|
+
- spec/acceptance/header_spec.rb
|
133
135
|
- spec/acceptance/redirecting_spec.rb
|
134
|
-
- spec/
|
136
|
+
- spec/acceptance/resource_spec.rb
|
137
|
+
- spec/acceptance_shared_specs.rb
|
138
|
+
- spec/caching_spec.rb
|
139
|
+
- spec/old_acceptance_specs.rb
|
135
140
|
- spec/resourceful/header_spec.rb
|
141
|
+
- spec/resourceful/http_accessor_spec.rb
|
142
|
+
- spec/resourceful/multipart_form_data_spec.rb
|
136
143
|
- spec/resourceful/resource_spec.rb
|
144
|
+
- spec/resourceful/response_spec.rb
|
137
145
|
- spec/resourceful/urlencoded_form_data_spec.rb
|
138
|
-
- spec/
|
146
|
+
- spec/simple_sinatra_server.rb
|
147
|
+
- spec/simple_sinatra_server_spec.rb
|
139
148
|
- spec/spec.opts
|
140
|
-
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
has_rdoc: true
|
141
151
|
homepage: http://github.com/paul/resourceful
|
142
152
|
licenses:
|
143
153
|
post_install_message:
|
@@ -167,7 +177,7 @@ requirements: []
|
|
167
177
|
rubyforge_project: resourceful
|
168
178
|
rubygems_version: 1.3.5
|
169
179
|
signing_key:
|
170
|
-
specification_version:
|
180
|
+
specification_version: 2
|
171
181
|
summary: An HTTP library for Ruby that takes advantage of everything HTTP has to offer.
|
172
182
|
test_files: []
|
173
183
|
|
@@ -1,72 +0,0 @@
|
|
1
|
-
module Resourceful
|
2
|
-
# Declarative way of interpreting options hashes
|
3
|
-
#
|
4
|
-
# include OptionsInterpretion
|
5
|
-
# def my_method(opts = {})
|
6
|
-
# extract_opts(opts) do |opts|
|
7
|
-
# host = opts.extract(:host)
|
8
|
-
# port = opts.extract(:port, :default => 80) {|p| Integer(p)}
|
9
|
-
# end
|
10
|
-
# end
|
11
|
-
#
|
12
|
-
module OptionsInterpretation
|
13
|
-
# Interpret an options hash
|
14
|
-
#
|
15
|
-
# @param [Hash] opts
|
16
|
-
# The options to interpret.
|
17
|
-
#
|
18
|
-
# @yield block that used to interpreter options hash
|
19
|
-
#
|
20
|
-
# @yieldparam [Resourceful::OptionsInterpretion::OptionsInterpreter] interpeter
|
21
|
-
# An interpreter that can be used to extract option information from the options hash.
|
22
|
-
def extract_opts(opts, &blk)
|
23
|
-
opts = opts.clone
|
24
|
-
yield OptionsInterpreter.new(opts)
|
25
|
-
|
26
|
-
unless opts.empty?
|
27
|
-
raise ArgumentError, "Unrecognized options: #{opts.keys.join(", ")}"
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
class OptionsInterpreter
|
33
|
-
def initialize(options_hash)
|
34
|
-
@options_hash = options_hash
|
35
|
-
end
|
36
|
-
|
37
|
-
# Extract a particular option.
|
38
|
-
#
|
39
|
-
# @param [String] name
|
40
|
-
# Name of option to extract
|
41
|
-
# @param [Hash] interpreter_opts
|
42
|
-
# ':default'
|
43
|
-
# :: The default value, or an object that responds to #call
|
44
|
-
# with the default value.
|
45
|
-
# ':required'
|
46
|
-
# :: Boolean indicating if this option is required. Default:
|
47
|
-
# false if a default is provided; otherwise true.
|
48
|
-
def extract(name, interpreter_opts = {}, &blk)
|
49
|
-
option_required = !interpreter_opts.has_key?(:default)
|
50
|
-
option_required = interpreter_opts[:required] if interpreter_opts.has_key?(:required)
|
51
|
-
|
52
|
-
raise ArgumentError, "Required option #{name} not provided" if option_required && !@options_hash.has_key?(name)
|
53
|
-
# We have the option we need
|
54
|
-
|
55
|
-
orig_val = @options_hash.delete(name)
|
56
|
-
|
57
|
-
if block_given?
|
58
|
-
yield orig_val
|
59
|
-
|
60
|
-
elsif orig_val
|
61
|
-
orig_val
|
62
|
-
|
63
|
-
elsif interpreter_opts[:default] && interpreter_opts[:default].respond_to?(:call)
|
64
|
-
interpreter_opts[:default].call()
|
65
|
-
|
66
|
-
elsif interpreter_opts[:default]
|
67
|
-
interpreter_opts[:default]
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|