wrest 4.0.0-universal-java-18
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.
- checksums.yaml +7 -0
- data/CHANGELOG +169 -0
- data/LICENCE +7 -0
- data/README.md +436 -0
- data/bin/wrest +4 -0
- data/bin/wrest_shell.rb +23 -0
- data/lib/wrest/async_request/event_machine_backend.rb +32 -0
- data/lib/wrest/async_request/thread_backend.rb +34 -0
- data/lib/wrest/async_request/thread_pool.rb +29 -0
- data/lib/wrest/async_request.rb +51 -0
- data/lib/wrest/cache_proxy.rb +119 -0
- data/lib/wrest/caching/memcached.rb +37 -0
- data/lib/wrest/caching/redis.rb +38 -0
- data/lib/wrest/caching.rb +57 -0
- data/lib/wrest/callback.rb +70 -0
- data/lib/wrest/components/container/alias_accessors.rb +70 -0
- data/lib/wrest/components/container/typecaster.rb +178 -0
- data/lib/wrest/components/container.rb +204 -0
- data/lib/wrest/components/mutators/base.rb +65 -0
- data/lib/wrest/components/mutators/camel_to_snake_case.rb +26 -0
- data/lib/wrest/components/mutators/xml_type_caster.rb +56 -0
- data/lib/wrest/components/mutators.rb +42 -0
- data/lib/wrest/components/translators/content_types.rb +25 -0
- data/lib/wrest/components/translators/json.rb +36 -0
- data/lib/wrest/components/translators/txt.rb +35 -0
- data/lib/wrest/components/translators/xml/conversions.rb +56 -0
- data/lib/wrest/components/translators/xml.rb +77 -0
- data/lib/wrest/components/translators.rb +30 -0
- data/lib/wrest/components.rb +22 -0
- data/lib/wrest/core_ext/hash/conversions.rb +45 -0
- data/lib/wrest/core_ext/hash.rb +7 -0
- data/lib/wrest/core_ext/string/conversions.rb +38 -0
- data/lib/wrest/core_ext/string.rb +7 -0
- data/lib/wrest/exceptions.rb +38 -0
- data/lib/wrest/hash_with_case_insensitive_access.rb +52 -0
- data/lib/wrest/hash_with_indifferent_access.rb +442 -0
- data/lib/wrest/http_codes.rb +83 -0
- data/lib/wrest/http_shared/headers.rb +345 -0
- data/lib/wrest/http_shared/standard_headers.rb +22 -0
- data/lib/wrest/http_shared/standard_tokens.rb +21 -0
- data/lib/wrest/http_shared.rb +25 -0
- data/lib/wrest/multipart.rb +84 -0
- data/lib/wrest/native/connection_factory.rb +28 -0
- data/lib/wrest/native/delete.rb +27 -0
- data/lib/wrest/native/get.rb +83 -0
- data/lib/wrest/native/options.rb +27 -0
- data/lib/wrest/native/patch.rb +27 -0
- data/lib/wrest/native/post.rb +27 -0
- data/lib/wrest/native/post_multipart.rb +36 -0
- data/lib/wrest/native/put.rb +27 -0
- data/lib/wrest/native/put_multipart.rb +36 -0
- data/lib/wrest/native/redirection.rb +39 -0
- data/lib/wrest/native/request.rb +161 -0
- data/lib/wrest/native/response.rb +278 -0
- data/lib/wrest/native/session.rb +66 -0
- data/lib/wrest/native.rb +36 -0
- data/lib/wrest/test/request_patches.rb +12 -0
- data/lib/wrest/test.rb +3 -0
- data/lib/wrest/uri/builders.rb +48 -0
- data/lib/wrest/uri.rb +312 -0
- data/lib/wrest/uri_template.rb +63 -0
- data/lib/wrest/utils.rb +129 -0
- data/lib/wrest/version.rb +14 -0
- data/lib/wrest.rb +77 -0
- data/lib/wrest_no_ext.rb +7 -0
- metadata +286 -0
data/lib/wrest/uri.rb
ADDED
@@ -0,0 +1,312 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2009 Sidu Ponnappa
|
4
|
+
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
9
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
11
|
+
|
12
|
+
module Wrest # :nodoc:
|
13
|
+
# Wrest::Uri provides a simple api for
|
14
|
+
# REST calls. String#to_uri is a convenience
|
15
|
+
# method to build a Wrest::Uri from a string url.
|
16
|
+
# Note that a Wrest::Uri is immutable.
|
17
|
+
#
|
18
|
+
# Basic HTTP Authentication is supported.
|
19
|
+
# Example:
|
20
|
+
# "http://kaiwren:fupuppies@coathangers.com/portal/1".to_uri
|
21
|
+
# "http://coathangers.com/portal/1".to_uri(:username => 'kaiwren', :password => 'fupuppies')
|
22
|
+
#
|
23
|
+
# The second form is preferred as it can handle passwords with special characters like ^ and @
|
24
|
+
#
|
25
|
+
# You can find examples that use real APIs (like delicious) under the wrest/examples directory.
|
26
|
+
class Uri
|
27
|
+
attr_reader :uri, :username, :password, :uri_string, :uri_path, :query, :default_headers
|
28
|
+
|
29
|
+
# Valid tuples for the options are:
|
30
|
+
# :asynchronous_backend => Can currently be set to either Wrest::AsyncRequest::EventMachineBackend.new
|
31
|
+
# or Wrest::AsyncRequest::ThreadBackend.new. Easier to do using Uri#using_em and
|
32
|
+
# Uri#using_threads.
|
33
|
+
# :callback => Accepts a hash where the keys are response codes or ranges of response codes and
|
34
|
+
# the values are the corresponding blocks that will be invoked should the response
|
35
|
+
# code match the key.
|
36
|
+
# :default_headers => Accepts a hash containing a set of default request headers with which the headers
|
37
|
+
# passed to Uri#get, Uri#post etc. are merged. Incoming headers will override the
|
38
|
+
# defaults if there are any clashes. Use this to set cookies or use OAuth2 Authorize
|
39
|
+
# headers. When extending or cloning a Uri, passing in a new set of default_headers
|
40
|
+
# will result in the old set being overridden.
|
41
|
+
# :username, :password => HTTP authentication. Passing nil for either username or password will skip it.
|
42
|
+
# See Wrest::Native::Request for other available options and their default values.
|
43
|
+
def initialize(uri_string, options = {})
|
44
|
+
@options = options.clone
|
45
|
+
setup_uri_state!(uri_string)
|
46
|
+
setup_request_config!
|
47
|
+
end
|
48
|
+
|
49
|
+
# Builds a Wrest::UriTemplate by extending the current URI
|
50
|
+
# with the pattern passed to it.
|
51
|
+
def to_template(pattern)
|
52
|
+
template_pattern = URI.join(uri_string, pattern).to_s
|
53
|
+
UriTemplate.new(template_pattern, @options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Build a new Wrest::Uri by appending _path_ to
|
57
|
+
# the current uri. If the original Wrest::Uri
|
58
|
+
# has a username and password, that will be
|
59
|
+
# copied to the new Wrest::Uri as well.
|
60
|
+
#
|
61
|
+
# Example:
|
62
|
+
# uri = "https://localhost:3000/v1".to_uri
|
63
|
+
# uri['/oogas/1'].get
|
64
|
+
#
|
65
|
+
# To change the username and password on the new
|
66
|
+
# instance, simply pass them as an options map.
|
67
|
+
#
|
68
|
+
# Example:
|
69
|
+
# uri = "https://localhost:3000/v1".to_uri(:username => 'foo', :password => 'bar')
|
70
|
+
# uri['/oogas/1', {:username => 'meh', :password => 'baz'}].get
|
71
|
+
def [](path, options = nil)
|
72
|
+
Uri.new(uri + File.join(uri_path, path), options || @options)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Clones a Uri, building a new instance with exactly the same uri string.
|
76
|
+
# You can however change the Uri options or add new ones.
|
77
|
+
def clone(opts = {})
|
78
|
+
merged_options = @options.merge(opts)
|
79
|
+
merged_options[:default_headers] = opts[:default_headers] ? @default_headers.merge(opts[:default_headers]) : {}
|
80
|
+
Uri.new(@uri_string, merged_options)
|
81
|
+
end
|
82
|
+
|
83
|
+
def eql?(other)
|
84
|
+
self == other
|
85
|
+
end
|
86
|
+
|
87
|
+
def ==(other)
|
88
|
+
return false if other.class != self.class
|
89
|
+
|
90
|
+
other.uri == uri && username == other.username && password == other.password
|
91
|
+
end
|
92
|
+
|
93
|
+
def hash
|
94
|
+
[@uri, @username, @password].hash
|
95
|
+
end
|
96
|
+
|
97
|
+
# This produces exactly the same string as the Wrest::Uri was constructed with.
|
98
|
+
# If the orignial URI contained a HTTP username and password, that too will
|
99
|
+
# show up, so be careful if using this for logging.
|
100
|
+
def to_s
|
101
|
+
uri_string
|
102
|
+
end
|
103
|
+
|
104
|
+
# :nodoc:
|
105
|
+
def build_get(parameters = {}, headers = {}, &block)
|
106
|
+
Http::Get.new(self, parameters, default_headers.merge(headers),
|
107
|
+
block ? @options.merge(callback_block: block) : @options)
|
108
|
+
end
|
109
|
+
|
110
|
+
# :nodoc:
|
111
|
+
def build_put(body = '', headers = {}, parameters = {}, &block)
|
112
|
+
Http::Put.new(self, body.to_s, default_headers.merge(headers), parameters,
|
113
|
+
block ? @options.merge(callback_block: block) : @options)
|
114
|
+
end
|
115
|
+
|
116
|
+
# :nodoc:
|
117
|
+
def build_patch(body = '', headers = {}, parameters = {}, &block)
|
118
|
+
Http::Patch.new(self, body.to_s, default_headers.merge(headers), parameters,
|
119
|
+
block ? @options.merge(callback_block: block) : @options)
|
120
|
+
end
|
121
|
+
|
122
|
+
# :nodoc:
|
123
|
+
def build_post(body = '', headers = {}, parameters = {}, &block)
|
124
|
+
Http::Post.new(self, body.to_s, default_headers.merge(headers), parameters,
|
125
|
+
block ? @options.merge(callback_block: block) : @options)
|
126
|
+
end
|
127
|
+
|
128
|
+
# :nodoc:
|
129
|
+
def build_post_form(parameters = {}, headers = {}, &block)
|
130
|
+
headers = default_headers.merge(headers).merge(Wrest::H::ContentType => Wrest::T::FormEncoded)
|
131
|
+
body = Utils.hash_to_param(parameters)
|
132
|
+
Http::Post.new(self, body, headers, {}, block ? @options.merge(callback_block: block) : @options)
|
133
|
+
end
|
134
|
+
|
135
|
+
# :nodoc:
|
136
|
+
def build_delete(parameters = {}, headers = {}, &block)
|
137
|
+
Http::Delete.new(self, parameters, default_headers.merge(headers),
|
138
|
+
block ? @options.merge(callback_block: block) : @options)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Make a GET request to this URI. This is a convenience API
|
142
|
+
# that creates a Wrest::Native::Get, executes it and returns a Wrest::Native::Response.
|
143
|
+
#
|
144
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
145
|
+
def get(parameters = {}, headers = {}, &block)
|
146
|
+
build_get(parameters, headers, &block).invoke
|
147
|
+
end
|
148
|
+
|
149
|
+
# Make a GET request to this URI. This is a convenience API
|
150
|
+
# that creates a Wrest::Native::Get.
|
151
|
+
#
|
152
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
153
|
+
#
|
154
|
+
# Note: get_async does not return a response and the response should be accessed through callbacks.
|
155
|
+
# This implementation of asynchronous get is currently in alpha. Hence, it should not be used in production.
|
156
|
+
def get_async(parameters = {}, headers = {}, &block)
|
157
|
+
@asynchronous_backend.execute(build_get(parameters, headers, &block))
|
158
|
+
end
|
159
|
+
|
160
|
+
# Make a PUT request to this URI. This is a convenience API
|
161
|
+
# that creates a Wrest::Native::Put, executes it and returns a Wrest::Native::Response.
|
162
|
+
#
|
163
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
164
|
+
def put(body = '', headers = {}, parameters = {}, &block)
|
165
|
+
build_put(body, headers, parameters, &block).invoke
|
166
|
+
end
|
167
|
+
|
168
|
+
# Make a PUT request to this URI. This is a convenience API
|
169
|
+
# that creates a Wrest::Native::Put.
|
170
|
+
#
|
171
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
172
|
+
#
|
173
|
+
# Note: put_async does not return a response and the response should be accessed through callbacks.
|
174
|
+
# This implementation of asynchronous put is currently in alpha. Hence, it should not be used in production.
|
175
|
+
def put_async(body = '', headers = {}, parameters = {}, &block)
|
176
|
+
@asynchronous_backend.execute(build_put(body, headers, parameters, &block))
|
177
|
+
end
|
178
|
+
|
179
|
+
# Make a PATCH request to this URI. This is a convenience API
|
180
|
+
# that creates a Wrest::Native::Patch, executes it and returns a Wrest::Native::Response.
|
181
|
+
#
|
182
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
183
|
+
def patch(body = '', headers = {}, parameters = {}, &block)
|
184
|
+
build_patch(body, headers, parameters, &block).invoke
|
185
|
+
end
|
186
|
+
|
187
|
+
# Make a PATCH request to this URI. This is a convenience API
|
188
|
+
# that creates a Wrest::Native::Patch.
|
189
|
+
#
|
190
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
191
|
+
#
|
192
|
+
# Note: patch_async does not return a response and the response should be accessed through callbacks.
|
193
|
+
def patch_async(body = '', headers = {}, parameters = {}, &block)
|
194
|
+
@asynchronous_backend.execute(build_patch(body, headers, parameters, &block))
|
195
|
+
end
|
196
|
+
|
197
|
+
# Makes a POST request to this URI. This is a convenience API
|
198
|
+
# that creates a Wrest::Native::Post, executes it and returns a Wrest::Native::Response.
|
199
|
+
#
|
200
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
201
|
+
def post(body = '', headers = {}, parameters = {}, &block)
|
202
|
+
build_post(body, headers, parameters, &block).invoke
|
203
|
+
end
|
204
|
+
|
205
|
+
# Makes a POST request to this URI. This is a convenience API
|
206
|
+
# that creates a Wrest::Native::Post.
|
207
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
208
|
+
#
|
209
|
+
# Note: post_async does not return a response and the response should be accessed through callbacks.
|
210
|
+
# This implementation of asynchronous post is currently in alpha. Hence, it should not be used in production.
|
211
|
+
def post_async(body = '', headers = {}, parameters = {}, &block)
|
212
|
+
@asynchronous_backend.execute(build_post(body, headers, parameters, &block))
|
213
|
+
end
|
214
|
+
|
215
|
+
# Makes a POST request to this URI. This is a convenience API
|
216
|
+
# that mimics a form being posted; some allegly RESTful APIs like FCBK require
|
217
|
+
# this.
|
218
|
+
#
|
219
|
+
# Form encoding involves munging the parameters into a string and placing them
|
220
|
+
# in the body, as well as setting the Content-Type header to
|
221
|
+
# application/x-www-form-urlencoded
|
222
|
+
def post_form(parameters = {}, headers = {}, &block)
|
223
|
+
build_post_form(parameters, headers, &block).invoke
|
224
|
+
end
|
225
|
+
|
226
|
+
# Makes a POST request to this URI. This is a convenience API
|
227
|
+
# that mimics a form being posted; some allegly RESTful APIs like FCBK require
|
228
|
+
# this.
|
229
|
+
#
|
230
|
+
# Form encoding involves munging the parameters into a string and placing them
|
231
|
+
# in the body, as well as setting the Content-Type header to
|
232
|
+
# application/x-www-form-urlencoded
|
233
|
+
#
|
234
|
+
# Note: post_form_async does not return a response and the response should be accessed through callbacks.
|
235
|
+
# This implementation of asynchronous post_form is currently in alpha. Hence, it should not be used in production.
|
236
|
+
def post_form_async(parameters = {}, headers = {}, &block)
|
237
|
+
@asynchronous_backend.execute(build_post_form(parameters, headers, &block))
|
238
|
+
end
|
239
|
+
|
240
|
+
# Makes a DELETE request to this URI. This is a convenience API
|
241
|
+
# that creates a Wrest::Native::Delete, executes it and returns a Wrest::Native::Response.
|
242
|
+
#
|
243
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
244
|
+
def delete(parameters = {}, headers = {}, &block)
|
245
|
+
build_delete(parameters, headers, &block).invoke
|
246
|
+
end
|
247
|
+
|
248
|
+
# Makes a DELETE request to this URI. This is a convenience API
|
249
|
+
# that creates a Wrest::Native::Delete.
|
250
|
+
#
|
251
|
+
# Remember to escape all parameter strings if necessary, using URI.escape
|
252
|
+
#
|
253
|
+
# Note: delete_async does not return a response and the response should be accessed through callbacks.
|
254
|
+
# This implementation of asynchronous delete is currently in alpha. Hence, it should not be used in production.
|
255
|
+
def delete_async(parameters = {}, headers = {}, &block)
|
256
|
+
@asynchronous_backend.execute(build_delete(parameters, headers, &block))
|
257
|
+
end
|
258
|
+
|
259
|
+
# Makes an OPTIONS request to this URI. This is a convenience API
|
260
|
+
# that creates a Wrest::Native::Options, executes it and returns the Wrest::Native::Response.
|
261
|
+
def options
|
262
|
+
Http::Options.new(self, @options).invoke
|
263
|
+
end
|
264
|
+
|
265
|
+
def https?
|
266
|
+
@uri.is_a?(URI::HTTPS)
|
267
|
+
end
|
268
|
+
|
269
|
+
# Provides the full path of a request.
|
270
|
+
# For example, for
|
271
|
+
# http://localhost:3000/demons/1/chi?sort=true
|
272
|
+
# this would return
|
273
|
+
# /demons/1/chi?sort=true
|
274
|
+
def full_path
|
275
|
+
uri.request_uri
|
276
|
+
end
|
277
|
+
|
278
|
+
def protocol
|
279
|
+
uri.scheme
|
280
|
+
end
|
281
|
+
|
282
|
+
def host
|
283
|
+
uri.host
|
284
|
+
end
|
285
|
+
|
286
|
+
def port
|
287
|
+
uri.port
|
288
|
+
end
|
289
|
+
|
290
|
+
include Http::ConnectionFactory
|
291
|
+
include Uri::Builders
|
292
|
+
|
293
|
+
private
|
294
|
+
|
295
|
+
def setup_request_config!
|
296
|
+
@username = (@options[:username] ||= @uri.user)
|
297
|
+
@password = (@options[:password] ||= @uri.password)
|
298
|
+
@asynchronous_backend = @options[:asynchronous_backend] || Wrest::AsyncRequest.default_backend
|
299
|
+
@options[:callback] = Callback.new(@options[:callback]) if @options[:callback]
|
300
|
+
@default_headers = @options[:default_headers] || {}
|
301
|
+
end
|
302
|
+
|
303
|
+
def setup_uri_state!(uri_string)
|
304
|
+
@uri_string = uri_string.to_s
|
305
|
+
@uri = URI.parse(@uri_string)
|
306
|
+
uri_scheme = URI.split(@uri_string)
|
307
|
+
@uri_path = uri_scheme[-4].split('?').first || ''
|
308
|
+
@uri_path = (@uri_path.empty? ? '/' : @uri_path)
|
309
|
+
@query = uri_scheme[-2] || ''
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2009 Sidu Ponnappa
|
4
|
+
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
9
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
11
|
+
|
12
|
+
module Wrest
|
13
|
+
class UriTemplate
|
14
|
+
attr_reader :uri_pattern
|
15
|
+
|
16
|
+
def initialize(uri_pattern, options = {})
|
17
|
+
@uri_pattern = uri_pattern.clone
|
18
|
+
@options = options.clone
|
19
|
+
end
|
20
|
+
|
21
|
+
# Builds a new Wrest::Uri from this uri template
|
22
|
+
# by replacing the keys in the options that match with
|
23
|
+
# the corressponding values.
|
24
|
+
#
|
25
|
+
# Example:
|
26
|
+
# template = UriTemplate.new("http://coathangers.com/:resource/:id.:format")
|
27
|
+
# template.to_uri(:resource => 'shen_coins', :id => 5, :format => :json)
|
28
|
+
# => #<Wrest::Uri:0x1225514 @uri=#<URI::HTTP:0x9127d8 URL:http://localhost:3000/shen_coins/5.json>>
|
29
|
+
#
|
30
|
+
# This feature can also be used to handle HTTP authentication where the username
|
31
|
+
# and password needs changing at runtime. However, this approach _will_ fail if
|
32
|
+
# the password contains characters like ^ and @.
|
33
|
+
#
|
34
|
+
# Note that beacuse because both HTTP Auth and UriTemplate
|
35
|
+
# use ':' as a delimiter, the pattern does look slightly weird, but it still works.
|
36
|
+
# Example:
|
37
|
+
# template = UriTemplate.new("http://:username::password@coathangers.com/:resource/:id.:format")
|
38
|
+
# template.to_uri(
|
39
|
+
# :user => 'kaiwren',
|
40
|
+
# :password => 'fupuppies',
|
41
|
+
# :resource => 'portal',
|
42
|
+
# :id => '1'
|
43
|
+
# )
|
44
|
+
# => #<Wrest::Uri:0x18e0bec @uri=#<URI::HTTP:0x18e09a8 URL:http://kaiwren:fupuppies@coathangers.com/portal/1>>
|
45
|
+
def to_uri(options = {})
|
46
|
+
merged_options = @options.merge(options)
|
47
|
+
Wrest::Uri.new(merged_options.inject(uri_pattern.clone) do |uri_string, tuple|
|
48
|
+
key, value = tuple
|
49
|
+
uri_string.gsub(":#{key}", value.to_s)
|
50
|
+
end, @options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](path)
|
54
|
+
UriTemplate.new(File.join(uri_pattern, path))
|
55
|
+
end
|
56
|
+
|
57
|
+
def ==(other)
|
58
|
+
return false if other.class != self.class
|
59
|
+
|
60
|
+
other.uri_pattern == uri_pattern
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/wrest/utils.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wrest
|
4
|
+
module Utils
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# https://github.com/rails/rails/commit/2a371368c91789a4d689d6a84eb20b238c37678a
|
8
|
+
# A string is blank if it's empty or contains whitespaces only:
|
9
|
+
#
|
10
|
+
# "".blank? # => true
|
11
|
+
# " ".blank? # => true
|
12
|
+
# " ".blank? # => true
|
13
|
+
# " something here ".blank? # => false
|
14
|
+
#
|
15
|
+
def string_blank?(string)
|
16
|
+
string !~ /[^[:space:]]/
|
17
|
+
end
|
18
|
+
|
19
|
+
# https://github.com/rails/rails/commit/69b550fc88f0e155ab997476e576142a2dbec324
|
20
|
+
# Tries to find a constant with the name specified in the argument string.
|
21
|
+
#
|
22
|
+
# constantize('Module') # => Module
|
23
|
+
# constantize('Foo::Bar') # => Foo::Bar
|
24
|
+
#
|
25
|
+
# The name is assumed to be the one of a top-level constant, no matter
|
26
|
+
# whether it starts with "::" or not. No lexical context is taken into
|
27
|
+
# account:
|
28
|
+
#
|
29
|
+
# C = 'outside'
|
30
|
+
# module M
|
31
|
+
# C = 'inside'
|
32
|
+
# C # => 'inside'
|
33
|
+
# constantize('C') # => 'outside', same as ::C
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# NameError is raised when the name is not in CamelCase or the constant is
|
37
|
+
# unknown.
|
38
|
+
def string_constantize(camel_cased_word)
|
39
|
+
Object.const_get(camel_cased_word)
|
40
|
+
end
|
41
|
+
|
42
|
+
# https://github.com/rails/rails/commit/69b550fc88f0e155ab997476e576142a2dbec324
|
43
|
+
# Removes the module part from the expression in the string.
|
44
|
+
#
|
45
|
+
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
|
46
|
+
# demodulize('Inflections') # => "Inflections"
|
47
|
+
# demodulize('::Inflections') # => "Inflections"
|
48
|
+
# demodulize('') # => ""
|
49
|
+
#
|
50
|
+
def string_demodulize(path)
|
51
|
+
path = path.to_s
|
52
|
+
if (i = path.rindex('::'))
|
53
|
+
path[(i + 2)..]
|
54
|
+
else
|
55
|
+
path
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# https://github.com/rails/rails/commit/69b550fc88f0e155ab997476e576142a2dbec324
|
60
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
61
|
+
#
|
62
|
+
# Changes '::' to '/' to convert namespaces to paths.
|
63
|
+
#
|
64
|
+
# underscore('ActiveModel') # => "active_model"
|
65
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
66
|
+
#
|
67
|
+
# As a rule of thumb you can think of +underscore+ as the inverse of
|
68
|
+
# #camelize, though there are cases where that does not hold:
|
69
|
+
#
|
70
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
71
|
+
def string_underscore(camel_cased_word)
|
72
|
+
return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
|
73
|
+
|
74
|
+
word = camel_cased_word.to_s.gsub('::', '/')
|
75
|
+
word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { (Regexp.last_match(1) || Regexp.last_match(2)) << '_' }
|
76
|
+
word.tr!('-', '_')
|
77
|
+
word.downcase!
|
78
|
+
word
|
79
|
+
end
|
80
|
+
|
81
|
+
# https://github.com/rails/rails/commit/a0d7247d1509762283c61182ad82c2eed8d54757
|
82
|
+
# Returns a string representation of the receiver suitable for use as a URL
|
83
|
+
# query string:
|
84
|
+
#
|
85
|
+
# {:name => 'David', :nationality => 'Danish'}.to_param
|
86
|
+
# # => "name=David&nationality=Danish"
|
87
|
+
#
|
88
|
+
# The string pairs "key=value" that conform the query string
|
89
|
+
# are sorted lexicographically in ascending order.
|
90
|
+
#
|
91
|
+
def hash_to_param(hash)
|
92
|
+
hash.collect do |key, value|
|
93
|
+
object_to_query(key, value)
|
94
|
+
end.sort * '&'
|
95
|
+
end
|
96
|
+
|
97
|
+
# https://github.com/rails/rails/commit/52b71c01fd3c8a87152f55129a8cb3234190734a
|
98
|
+
#
|
99
|
+
# Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
|
100
|
+
# param name.
|
101
|
+
def object_to_query(key, object)
|
102
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(object.to_s)}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# https://github.com/rails/rails/commit/18707ab17fa492eb25ad2e8f9818a320dc20b823
|
106
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
107
|
+
# For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
|
108
|
+
#
|
109
|
+
# This simplifies
|
110
|
+
#
|
111
|
+
# !address || address.empty?
|
112
|
+
#
|
113
|
+
# to
|
114
|
+
#
|
115
|
+
# address.blank?
|
116
|
+
#
|
117
|
+
# @return [true, false]
|
118
|
+
def object_blank?(object)
|
119
|
+
object.respond_to?(:empty?) ? !!object.empty? : !object
|
120
|
+
end
|
121
|
+
|
122
|
+
# https://github.com/rails/rails/commit/6372d23616b13c62c7a12efa89f958b334dd66ae
|
123
|
+
# Converts self to an integer number of seconds since the Unix epoch.
|
124
|
+
def datetime_to_i(datetime)
|
125
|
+
seconds_per_day = 86_400
|
126
|
+
((datetime - ::DateTime.civil(1970)) * seconds_per_day).to_i
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2009-2011 Sidu Ponnappa
|
4
|
+
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
9
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
11
|
+
|
12
|
+
module Wrest
|
13
|
+
VERSION = '4.0.0'
|
14
|
+
end
|
data/lib/wrest.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2009 Sidu Ponnappa
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
8
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
10
|
+
|
11
|
+
require 'net/http'
|
12
|
+
require 'net/https'
|
13
|
+
require 'forwardable'
|
14
|
+
require 'date'
|
15
|
+
require 'cgi'
|
16
|
+
require 'base64'
|
17
|
+
require 'logger'
|
18
|
+
require 'benchmark'
|
19
|
+
require 'concurrent'
|
20
|
+
require 'nokogiri'
|
21
|
+
require 'json'
|
22
|
+
|
23
|
+
module Wrest
|
24
|
+
Root = File.dirname(__FILE__)
|
25
|
+
|
26
|
+
$LOAD_PATH.unshift Root
|
27
|
+
|
28
|
+
def self.logger=(logger)
|
29
|
+
@logger = logger
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.logger
|
33
|
+
@logger
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.enable_evented_requests!
|
37
|
+
require 'wrest/event_machine_backend'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Switch Wrest to using Net::HTTP.
|
41
|
+
def self.use_native!
|
42
|
+
old_verbose = $VERBOSE
|
43
|
+
$VERBOSE = nil
|
44
|
+
Wrest.const_set('Http', Wrest::Native)
|
45
|
+
ensure
|
46
|
+
$VERBOSE = old_verbose
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Wrest.logger = Logger.new($stdout)
|
51
|
+
Wrest.logger.level = Logger::DEBUG
|
52
|
+
|
53
|
+
require 'wrest/utils'
|
54
|
+
require 'wrest/core_ext/string'
|
55
|
+
require 'wrest/hash_with_indifferent_access'
|
56
|
+
require 'wrest/hash_with_case_insensitive_access'
|
57
|
+
|
58
|
+
# Load Wrest Core
|
59
|
+
require 'wrest/version'
|
60
|
+
require 'wrest/cache_proxy'
|
61
|
+
require 'wrest/http_shared'
|
62
|
+
require 'wrest/http_codes'
|
63
|
+
require 'wrest/callback'
|
64
|
+
require 'wrest/native'
|
65
|
+
|
66
|
+
require 'wrest/async_request/thread_pool'
|
67
|
+
require 'wrest/async_request/thread_backend'
|
68
|
+
require 'wrest/async_request'
|
69
|
+
|
70
|
+
require 'wrest/caching'
|
71
|
+
|
72
|
+
# Load Wrest Wrappers
|
73
|
+
require 'wrest/uri/builders'
|
74
|
+
require 'wrest/uri'
|
75
|
+
require 'wrest/uri_template'
|
76
|
+
require 'wrest/exceptions'
|
77
|
+
require 'wrest/components'
|