hurley 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70bb285608ba9cef1503ea1acf003fbdc48c0648
4
+ data.tar.gz: 0b9e00c2e5880c432c41865ed996cffdb9174d46
5
+ SHA512:
6
+ metadata.gz: a9d694cf97f96c3099171fa5479b6c2ad5e3037ec02fa53776945a1b1166e45084e13508c660d5948e2c4b4445fa29020eae28e2187f1474629e28c05509b324
7
+ data.tar.gz: f48211a98ac3616638afbdd58c5b95dca7e6e486cf2eec6503147321ea628c2f6bbe082840568cff4923e865f9842247aadf5d3c3a352fe2b69a0b887660317a
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ log
2
+ tmp
3
+ pkg
4
+
data/.travis.yml ADDED
@@ -0,0 +1,28 @@
1
+ sudo: false
2
+ language: ruby
3
+ install: script/bootstrap
4
+ script: script/test
5
+ rvm:
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - 2.1
9
+ - jruby-18mode
10
+ - jruby-19mode
11
+ - jruby-head
12
+
13
+ matrix:
14
+ allow_failures:
15
+ # "A fatal error has been detected by the Java Runtime Environment:
16
+ # Internal Error (sharedRuntime.cpp:843)"
17
+ - rvm: jruby-18mode
18
+ - rvm: jruby-19mode
19
+ - rvm: jruby-head
20
+ # random crashes
21
+ fast_finish: true
22
+
23
+ env:
24
+ matrix:
25
+ - HURLEY_SSL=no
26
+ - HURLEY_SSL=yes
27
+ - HURLEY_SSL=no HURLEY_ADDRESSABLE=1
28
+ - HURLEY_SSL=yes HURLEY_ADDRESSABLE=1
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hurley (0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.3.6)
10
+ minitest (5.5.0)
11
+ rack (1.6.0)
12
+ rack-protection (1.5.3)
13
+ rack
14
+ sinatra (1.4.5)
15
+ rack (~> 1.4)
16
+ rack-protection (~> 1.4)
17
+ tilt (~> 1.3, >= 1.3.4)
18
+ tilt (1.4.1)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ addressable (~> 2.3.6)
25
+ bundler (~> 1.0)
26
+ hurley!
27
+ minitest (~> 5.5.0)
28
+ sinatra (~> 1.4.5)
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Rick Olson
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
@@ -0,0 +1,317 @@
1
+ # Hurley
2
+
3
+ ![](http://comicstheblog.com/wp-content/uploads/2013/10/Hurley-Run.gif)
4
+
5
+ Hurley is a ruby gem with no runtime dependencies that provides a common
6
+ interface for working with different HTTP adapters. It is an evolution of
7
+ Faraday, with rethought internals.
8
+
9
+ Hurley revolves around three main classes: Client, Request, and Response. A
10
+ Client sets the default properties for all HTTP requests, including the base
11
+ url, headers, and options.
12
+
13
+ ```ruby
14
+ require "hurley"
15
+
16
+ # If you prefer Addressable::URI, require this too:
17
+ # This is required automatically if `Addressable::URI` is defined when Hurley
18
+ # is being loaded.
19
+ require "hurley/addressable"
20
+
21
+ client = Hurley::Client.new "https://api.github.com"
22
+ client.header[:accept] = "application/vnd.github+json"
23
+ client.query["a"] = "?a is set on every request too"
24
+
25
+ client.scheme # => "https"
26
+ client.host # => "api.github.com"
27
+ client.port # => 443
28
+
29
+ # See Hurley::RequestOptions in lib/hurley/options.rb
30
+ client.request_options.timeout = 3
31
+
32
+ # See Hurley::SslOptions in lib/hurley/options.rb
33
+ client.ssl_options.ca_file = "path/to/cert.crt"
34
+
35
+ # Verbs head, get, put, post, patch, delete, and options are supported.
36
+ response = client.get("users/tater") do |req|
37
+ # These properties can be changed on a per-request basis.
38
+ req.header[:accept] = "application/vnd.github.preview+json"
39
+ req.query["a"] = "override!"
40
+
41
+ req.options.timeout = 1
42
+ req.ssl_options.ca_file = "path/to/cert.crt"
43
+
44
+ req.verb # => :get
45
+ req.scheme # => "https"
46
+ req.host # => "api.github.com"
47
+ req.port # => 443
48
+ end
49
+
50
+ # You can also use Hurley class level shortcuts, which use Hurley.default_client.
51
+ response = Hurley.get("https://api.github.com/users/tater")
52
+
53
+ response.header[:content_type] # => "application/json"
54
+ response.status_code # => 200
55
+ response.body # => {"id": 1, ...}
56
+ response.request # => same as `request`
57
+
58
+ # Is this a 2xx response?
59
+ response.success?
60
+
61
+ # Is this a 3xx redirect?
62
+ response.redirection?
63
+
64
+ # Is this is a 4xx response?
65
+ response.client_error?
66
+
67
+ # Is this a 5xx response?
68
+ response.server_error?
69
+
70
+ # What kind of response is this?
71
+ response.status_type # => One of :success, :redirection, :client_error, :server_error, or :other
72
+
73
+ # Timing of the response, in ms
74
+ response.ms
75
+
76
+ # Responses automatically follow 5 redirections by default.
77
+
78
+ response.via # Array of Request objects that redirected.
79
+ response.location # => New Request built from Location header URL.
80
+
81
+ # You can tune the number of redirections, or disable them per Client or Request.
82
+
83
+ # This client follows up to 10 redirects
84
+ client.request_options.redirection_limit = 10
85
+ client.get "/foo" do |req|
86
+ # this specific request never follows any redirects.
87
+ req.options.redirection_limit = 0
88
+ end
89
+ ```
90
+
91
+ ## Connections
92
+
93
+ By default, a `Hurley::Client` uses a `Hurley::Connection` instance to make
94
+ requests with net/http. You can swap the connection with any object that
95
+ responds to `#call` with a Request, and returns a Response. This will not
96
+ interrupt other client properties or callbacks.
97
+
98
+ ```ruby
99
+ client = Hurley::Client.new "https://api.github.com"
100
+ client.connection = lambda do |req|
101
+ # return a Hurley::Response!
102
+ end
103
+ ```
104
+
105
+ ## URLs
106
+
107
+ Hurley joins a Client endpoint with a given request URL to produce the final
108
+ URL that is requested.
109
+
110
+ ```ruby
111
+ client = Hurley::Client.new "https://a:b@api.com/v1?a=1"
112
+
113
+ client.get "user" do |req|
114
+ req.url.user # => "a"
115
+ req.url.password # => "b"
116
+ req.url # https://api.com/v1/user?a=1
117
+ end
118
+
119
+ # Absolute paths remove any path prefix
120
+ client.get "/v2/user" do |req|
121
+ req.url.user # => "a"
122
+ req.url.password # => "b"
123
+ req.url # https://api.com/v2/user?a=1
124
+ end
125
+
126
+ client.get "user?a=2" do |req|
127
+ req.url.user # => "a"
128
+ req.url.password # => "b"
129
+ req.url # https://api.com/v1/user?a=2
130
+ end
131
+
132
+ # Basic auth can be overridden
133
+ client.get "https://c:d@api.com/v1/user" do |req|
134
+ req.url.user # => "c"
135
+ req.url.password # => "d"
136
+ req.url # https://api.com/v1/user?a=1
137
+ end
138
+
139
+ client.get "https://staging.api.com/v1/user" do |req|
140
+ req.url.user # => nil, since the host changed
141
+ req.url.password # => nil
142
+ req.url # https://staging.api.com/v1/user
143
+ end
144
+ ```
145
+
146
+ Hurley uses `Hurley::Query::Nested` for all query encoding and decoding by
147
+ default. This can be changed globally, per client, or per request. Typically
148
+ you won't create `Hurley::Query` instances manually, and will use
149
+ `Hurley::Query.parse` for parsing.
150
+
151
+ ```ruby
152
+ # Nested queries
153
+
154
+ q = Hurley::Query::Nested.new(:a => [1,2], :h => {:a => 1})
155
+ q.to_query_string # => "a[]=1&a[]=2&h[a]=1"
156
+
157
+ Hurley::Query::Nested.parse(q.to_query_string)
158
+ # => #<Hurley::Query::Nested {"a"=>["1", "2"], "h"=>{"a"=>"1"}}>
159
+
160
+ # Flat queries
161
+
162
+ q = Hurley::Query::Flat.new(:a => [1,2])
163
+ q.to_query_string # => "a=1&a=2"
164
+
165
+ Hurley::Query::Flat.parse(q.to_query_string)
166
+ # => #<Hurley::Query::Nested {"a"=>["1", "2"]}>
167
+
168
+ # Change it globally.
169
+ Hurley.default = Hurley::Query::Flat
170
+
171
+ # Change it for just this client.
172
+ client = Hurley::Client.new
173
+ client.request_options.query_class = Hurley::Query::Flat
174
+
175
+ # Change it for just this request.
176
+ client.get "/foo" do |req|
177
+ req.options.query_class = Hurley::Query::Flat
178
+ end
179
+ ```
180
+
181
+ ## Headers
182
+
183
+ A Client's Header is passed down to each request. Header keys can be overridden
184
+ by the request. Headers are stored internally in canonical form, which is
185
+ capitalized with dashes: `"Content-Type"`, for example.
186
+
187
+ See `Hurley::Header` for all of the common header keys that have symbolized
188
+ shortcuts.
189
+
190
+ ```ruby
191
+ client = Hurley::Client.new "https://api.com"
192
+ client.header[:content_type] = "application/json"
193
+
194
+ # Same as:
195
+ client.header["content-type"] = "application/json"
196
+ client.header["Content-Type"] = "application/json"
197
+
198
+ client.get "/something.atom" do |req|
199
+ # Default user agent
200
+ req.header[:user_agent] # => "Hurley v#{Hurley::VERSION}"
201
+
202
+ # Change a header
203
+ req.header[:content_type] = "application/atom"
204
+ end
205
+ ```
206
+
207
+ ## Posting Forms
208
+
209
+ Hurley will encode form bodies for you, while setting default Content-Type and
210
+ Content-Length values as necessary. Multipart forms are supported too, using
211
+ `Hurley::UploadIO` objects.
212
+
213
+ ```ruby
214
+ # Works with HTTP verbs: post, put, and patch
215
+
216
+ # Send a=1 with Content-Type: application/x-www-form-urlencoded
217
+ client.post("/form", :a => 1)
218
+
219
+ # Send a=1 with Content-Type: text/plain
220
+ client.post("/form", {:a => 1}, "text/plain")
221
+
222
+ # Send file with Content-Type: multipart/form-data
223
+ client.post("/multipart", :file => Hurley::UploadIO.new("filename.txt", "text/plain"))
224
+ ```
225
+
226
+ The default query parser (`Hurley::Query::Nested`) is used by default. You can
227
+ change it globally, per client, or per request. See the "URLs" section.
228
+
229
+ ## Client Callbacks
230
+
231
+ Clients can define "before callbacks" that yield a Request, or "after callbacks"
232
+ that yield a Response. Multiple callbacks of the same type are added in order.
233
+
234
+ ```ruby
235
+ client.before_call do |req|
236
+ # modify request before it's called
237
+ end
238
+
239
+ client.before_callbacks # => ["#<Proc:...>"]
240
+
241
+ client.after_call do |res|
242
+ # modify response after it's called
243
+ end
244
+
245
+ # You can set a name to identify the callback
246
+ client.before_call :upcase do |req|
247
+ req.body.upcase!
248
+ end
249
+
250
+ client.before_callbacks # => [:upcase]
251
+
252
+ # You can also pass an object that responds to #call and #name.
253
+ class Upcaser
254
+ def name
255
+ :upcaser
256
+ end
257
+
258
+ def call(req)
259
+ req.body.upcase!
260
+ end
261
+ end
262
+
263
+ client.before_call(Upcaser.new)
264
+ client.before_callbacks # => [:upcaser]
265
+ ```
266
+
267
+ ## Streaming the Response Body
268
+
269
+ A Request object can take a callback that receives the response body in chunks
270
+ as they are read from the socket. Hurley connections that don't support
271
+ streaming will yield the entire response body once.
272
+
273
+ ```ruby
274
+ client.get "big-file" do |req|
275
+ req.on_body do |res, chunk|
276
+ puts "#{res.status_code}: #{chunk}"
277
+ end
278
+
279
+ # This streams the body for 200 or 201 responses only:
280
+ req.on_body(200, 201) do |res, chunk|
281
+ puts "#{res.status_code}: #{chunk}"
282
+ end
283
+ end
284
+ ```
285
+
286
+ ## Testing
287
+
288
+ Hurley includes a Test connection object for testing. This lets you make
289
+ requests without hitting a real endpoint.
290
+
291
+ ```ruby
292
+ require "hurley"
293
+ require "hurley/test"
294
+
295
+ client = Hurley::Client.new "https://api.github.com"
296
+
297
+ client.connection = Hurley::Test.new do |test|
298
+ # Verbs head, get, put, post, patch, delete, and options are supported.
299
+ test.get "/user" do |req|
300
+ # req is a Hurley::Request
301
+ # Return a Rack-compatible response.
302
+ [200, {"Content-Type" => "application/json"}, %({"id": 1})]
303
+ end
304
+ end
305
+
306
+ client.get("/user").body # => {"id": 1}
307
+ ```
308
+
309
+ ## TODO
310
+
311
+ * [ ] Backport Faraday adapters as gems
312
+ * [ ] Integrate into Faraday reliant gems:
313
+ * [ ] [Sawyer](https://github.com/lostisland/sawyer)
314
+ * [ ] [Octokit](https://github.com/octokit/octokit.rb)
315
+ * [ ] [Elastomer](https://github.com/github/elastomer-client)
316
+ * [ ] Fix allll the bugs
317
+ * [ ] Release v1.0
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require File.expand_path("../lib/hurley/tasks", __FILE__)
data/contributors.yaml ADDED
@@ -0,0 +1,8 @@
1
+ # Contributors
2
+ # https://github.com/orgs/lostisland/teams/owners
3
+ # https://github.com/orgs/lostisland/teams/faraday-collaborators
4
+ # Change your name, or add your email if you want to be credited in the gemspec.
5
+ # Ordered according to https://github.com/lostisland/hurley/graphs/contributors
6
+ Rick Olson: technoweenie@gmail.com
7
+ Wynn Netherland:
8
+ Ben Maraney:
data/hurley.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = "hurley"
3
+ lib_file = File.expand_path("../lib/#{lib}.rb", __FILE__)
4
+ File.read(lib_file) =~ /\bVERSION\s*=\s*["'](.+?)["']/
5
+ version = $1
6
+
7
+ require "yaml"
8
+ contributors = YAML.load(IO.read(File.expand_path("../contributors.yaml", __FILE__)))
9
+
10
+ Gem::Specification.new do |spec|
11
+ spec.add_development_dependency "addressable", "~> 2.3", ">= 2.3.6"
12
+ spec.add_development_dependency "bundler", "~> 1.0"
13
+ spec.add_development_dependency "minitest", "~> 5.5", ">= 5.5.0"
14
+ spec.add_development_dependency "rake", "~> 10.4.0", ">= 10.4.2"
15
+ spec.add_development_dependency "sinatra", "~> 1.4", ">= 1.4.5"
16
+ spec.authors = contributors.keys.compact
17
+ spec.description = %q{Hurley provides a common interface for working with different HTTP adapters.}
18
+ spec.email = contributors.values.compact
19
+ spec.homepage = "https://github.com/lostisland/hurley"
20
+ dev_null = File.exist?("/dev/null") ? "/dev/null" : "NUL"
21
+ git_files = `git ls-files -z 2>#{dev_null}`
22
+ spec.files = git_files.split("\0") if $?.success?
23
+ spec.test_files = Dir.glob("test/**/*.rb")
24
+ spec.licenses = ["MIT"]
25
+ spec.name = lib
26
+ spec.require_paths = ["lib"]
27
+ spec.summary = "HTTP client wrapper"
28
+ spec.version = version
29
+ end