typhoeus 0.5.0.pre → 0.5.0.rc
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +12 -0
- data/Gemfile +17 -1
- data/README.md +2 -2
- data/lib/typhoeus.rb +78 -16
- data/lib/typhoeus/config.rb +40 -4
- data/lib/typhoeus/errors.rb +9 -0
- data/lib/typhoeus/errors/no_stub.rb +12 -0
- data/lib/typhoeus/errors/typhoeus_error.rb +8 -0
- data/lib/typhoeus/expectation.rb +174 -0
- data/lib/typhoeus/hydra.rb +71 -14
- data/lib/typhoeus/hydra/before.rb +30 -0
- data/lib/typhoeus/hydra/block_connection.rb +35 -0
- data/lib/typhoeus/{hydras → hydra}/easy_factory.rb +17 -5
- data/lib/typhoeus/{hydras → hydra}/easy_pool.rb +4 -2
- data/lib/typhoeus/{hydras → hydra}/memoizable.rb +7 -5
- data/lib/typhoeus/{hydras → hydra}/queueable.rb +5 -3
- data/lib/typhoeus/{hydras → hydra}/runnable.rb +4 -1
- data/lib/typhoeus/hydra/stubbable.rb +26 -0
- data/lib/typhoeus/request.rb +117 -29
- data/lib/typhoeus/request/actions.rb +125 -0
- data/lib/typhoeus/request/before.rb +30 -0
- data/lib/typhoeus/request/block_connection.rb +52 -0
- data/lib/typhoeus/request/callbacks.rb +98 -0
- data/lib/typhoeus/{requests → request}/marshal.rb +1 -1
- data/lib/typhoeus/{requests → request}/memoizable.rb +4 -2
- data/lib/typhoeus/{requests → request}/operations.rb +25 -5
- data/lib/typhoeus/{requests → request}/responseable.rb +1 -1
- data/lib/typhoeus/request/stubbable.rb +28 -0
- data/lib/typhoeus/response.rb +30 -8
- data/lib/typhoeus/{responses → response}/header.rb +15 -11
- data/lib/typhoeus/response/informations.rb +205 -0
- data/lib/typhoeus/{responses → response}/status.rb +10 -7
- data/lib/typhoeus/version.rb +1 -1
- metadata +32 -135
- data/lib/typhoeus/requests/actions.rb +0 -17
- data/lib/typhoeus/requests/callbacks.rb +0 -48
- data/lib/typhoeus/responses/informations.rb +0 -43
- data/lib/typhoeus/responses/legacy.rb +0 -26
data/CHANGELOG.md
CHANGED
@@ -20,6 +20,7 @@ Major Changes:
|
|
20
20
|
for a description.
|
21
21
|
* The following classes were deleted because they do not seemed to be uesed at all. If that
|
22
22
|
turns out to be wrong, they will be restored: `Typhoeus::Filter`, `Typhoeus::Remote`, `Typhoeus::RemoteMethod`, `Typhoeus::RemoteProxyObject`
|
23
|
+
* `Typhoeus::Easy` and `Typhoeus::Multi` are now `Ethon::Easy` and `Ethon::Multi`
|
23
24
|
|
24
25
|
* Request shortcuts: `Typhoeus.get("www.google.de")`
|
25
26
|
* Global configuration:
|
@@ -32,6 +33,17 @@ end
|
|
32
33
|
* No more Response#headers_hash, instead response#header returning the last
|
33
34
|
header and response#redirections returning the responses with headers
|
34
35
|
generated through redirections
|
36
|
+
* Instead of defining the same callbacks on every request, you can define global callbacks:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Typhoeus.on_complete { p "yay" }
|
40
|
+
```
|
41
|
+
|
42
|
+
* The stubbing interface changed slightly. You now have the same syntax as for requests:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Typhoeus.stub(url, options).and_return(response)
|
46
|
+
```
|
35
47
|
|
36
48
|
Enhancements:
|
37
49
|
|
data/Gemfile
CHANGED
@@ -1,3 +1,19 @@
|
|
1
1
|
source :rubygems
|
2
|
-
|
3
2
|
gemspec
|
3
|
+
|
4
|
+
gem "rake"
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem "rspec", "~> 2.11"
|
8
|
+
|
9
|
+
gem "sinatra", "~> 1.3"
|
10
|
+
gem "json"
|
11
|
+
|
12
|
+
if RUBY_PLATFORM == "java"
|
13
|
+
gem "spoon"
|
14
|
+
end
|
15
|
+
|
16
|
+
unless ENV["CI"]
|
17
|
+
gem "guard-rspec", "~> 0.7"
|
18
|
+
end
|
19
|
+
end
|
data/README.md
CHANGED
@@ -20,8 +20,8 @@ hydra.run
|
|
20
20
|
|
21
21
|
## Project Tracking
|
22
22
|
|
23
|
-
* [Documentation](http://rubydoc.info/github/typhoeus/typhoeus)
|
24
|
-
* [Website](http://typhoeus.github.com/)
|
23
|
+
* [Documentation](http://rubydoc.info/github/typhoeus/typhoeus) (github master)
|
24
|
+
* [Website](http://typhoeus.github.com/) (v0.4.2)
|
25
25
|
* [Mailinglist](http://groups.google.com/group/typhoeus)
|
26
26
|
|
27
27
|
## LICENSE
|
data/lib/typhoeus.rb
CHANGED
@@ -2,41 +2,103 @@ require 'digest/sha2'
|
|
2
2
|
require 'ethon'
|
3
3
|
|
4
4
|
require 'typhoeus/config'
|
5
|
+
require 'typhoeus/errors'
|
6
|
+
require 'typhoeus/expectation'
|
7
|
+
require 'typhoeus/hydra'
|
5
8
|
require 'typhoeus/request'
|
6
9
|
require 'typhoeus/response'
|
7
|
-
require 'typhoeus/hydra'
|
8
10
|
require 'typhoeus/version'
|
9
11
|
|
10
12
|
# Typhoeus is a http client library based on Ethon which
|
11
13
|
# wraps libcurl.
|
12
14
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
+
# @example (see Typhoeus::Request)
|
16
|
+
# @example (see Typhoeus::Hydra)
|
15
17
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
+
# @see Typhoeus::Request
|
19
|
+
# @see Typhoeus::Hydra
|
18
20
|
#
|
19
|
-
#
|
20
|
-
# requests = (0..9).map{ Typhoeus::Request.new("www.example.com") }
|
21
|
-
# requests.each{ |request| hydra.queue(request) }
|
22
|
-
# hydra.run
|
21
|
+
# @since 0.5.0
|
23
22
|
module Typhoeus
|
24
23
|
extend self
|
25
|
-
extend
|
26
|
-
extend
|
24
|
+
extend Hydra::EasyPool
|
25
|
+
extend Request::Actions
|
26
|
+
extend Request::Callbacks::Types
|
27
27
|
|
28
28
|
# The default typhoeus user agent.
|
29
29
|
USER_AGENT = "Typhoeus - https://github.com/typhoeus/typhoeus"
|
30
30
|
|
31
31
|
# Set the Typhoeus configuration options by passing a block.
|
32
32
|
#
|
33
|
-
# @example
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# end
|
33
|
+
# @example (see Typhoeus::Config)
|
34
|
+
#
|
35
|
+
# @yield [ Typhoeus::Config ]
|
37
36
|
#
|
38
|
-
# @return [ Config ] The configuration
|
37
|
+
# @return [ Typhoeus::Config ] The configuration.
|
38
|
+
#
|
39
|
+
# @see Typhoeus::Config
|
39
40
|
def configure
|
40
41
|
yield Config
|
41
42
|
end
|
43
|
+
|
44
|
+
# Stub out specific request.
|
45
|
+
#
|
46
|
+
# @example (see Typhoeus::Expectation)
|
47
|
+
#
|
48
|
+
# @param [ String ] url The url to stub out.
|
49
|
+
# @param [ Hash ] options The options to stub out.
|
50
|
+
#
|
51
|
+
# @return [ Typhoeus::Expectation ] The expecatation.
|
52
|
+
#
|
53
|
+
# @see Typhoeus::Expectation
|
54
|
+
def stub(url, options = {})
|
55
|
+
expectation = Expectation.all.find{ |e| e.url == url && e.options == options }
|
56
|
+
return expectation if expectation
|
57
|
+
|
58
|
+
Expectation.new(url, options).tap do |new_expectation|
|
59
|
+
Expectation.all << new_expectation
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Add before callbacks.
|
64
|
+
#
|
65
|
+
# @example Add before callback.
|
66
|
+
# Typhoeus.before { |request| p request.url }
|
67
|
+
#
|
68
|
+
# @param [ Block ] block The callback.
|
69
|
+
#
|
70
|
+
# @yield [ Typhoeus::Request ]
|
71
|
+
#
|
72
|
+
# @return [ Array<Block> ] All before blocks.
|
73
|
+
def before(&block)
|
74
|
+
@before ||= []
|
75
|
+
@before << block if block_given?
|
76
|
+
@before
|
77
|
+
end
|
78
|
+
|
79
|
+
# Execute given block as if block connection is turned off.
|
80
|
+
# The old block connection state is restored afterwards.
|
81
|
+
#
|
82
|
+
# @example Make a real request, no matter if its blocked.
|
83
|
+
# Typhoeus::Config.block_connection = true
|
84
|
+
# Typhoeus.get("www.example.com").code
|
85
|
+
# #=> raise Typhoeus::Errors::NoStub
|
86
|
+
#
|
87
|
+
# Typhoeus.with_connection do
|
88
|
+
# Typhoeus.get("www.example.com").code
|
89
|
+
# #=> :ok
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# @param [ Block ] block The block to execute.
|
93
|
+
#
|
94
|
+
# @return [ Object ] Returns the return value of block.
|
95
|
+
#
|
96
|
+
# @see Typhoeus::Config#block_connection
|
97
|
+
def with_connection
|
98
|
+
old = Config.block_connection
|
99
|
+
Config.block_connection = false
|
100
|
+
result = yield if block_given?
|
101
|
+
Config.block_connection = old
|
102
|
+
result
|
103
|
+
end
|
42
104
|
end
|
data/lib/typhoeus/config.rb
CHANGED
@@ -1,11 +1,47 @@
|
|
1
1
|
module Typhoeus
|
2
2
|
|
3
3
|
# The Typhoeus configuration used to set global
|
4
|
-
# options.
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# options.
|
5
|
+
# @example Set the configuration options within a block.
|
6
|
+
# Typhoeus.configure do |config|
|
7
|
+
# config.verbose = true
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# @example Set the configuration direct.
|
11
|
+
# Typhoeus::Config.verbose = true
|
7
12
|
module Config
|
8
13
|
extend self
|
9
|
-
|
14
|
+
|
15
|
+
# Defines wether the connection is blocked.
|
16
|
+
# Defaults to false. When set to true, only
|
17
|
+
# stubbed requests are allowed. A
|
18
|
+
# {Typhoeus::Errors::NoStub} error is raised,
|
19
|
+
# when trying to do a real request. Its possible
|
20
|
+
# to work around inside
|
21
|
+
# {Typhoeus#with_connection}.
|
22
|
+
#
|
23
|
+
# @return [ Boolean ]
|
24
|
+
#
|
25
|
+
# @see Typhoeus::Request::BlockConnection
|
26
|
+
# @see Typhoeus::Hydra::BlockConnection
|
27
|
+
# @see Typhoeus#with_connection
|
28
|
+
# @see Typhoeus::Errors::NoStub
|
29
|
+
attr_accessor :block_connection
|
30
|
+
|
31
|
+
# Defines wether GET requests are memoized when using the {Typhoeus::Hydra}.
|
32
|
+
#
|
33
|
+
# @return [ Boolean ]
|
34
|
+
#
|
35
|
+
# @see Typhoeus::Hydra
|
36
|
+
# @see Typhoeus::Hydra::Memoizable
|
37
|
+
attr_accessor :memoize
|
38
|
+
|
39
|
+
# Defines wether curls debug output is shown.
|
40
|
+
# Unfortunately it prints to stderr.
|
41
|
+
#
|
42
|
+
# @return [ Boolean ]
|
43
|
+
#
|
44
|
+
# @see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTVERBOSE
|
45
|
+
attr_accessor :verbose
|
10
46
|
end
|
11
47
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
|
3
|
+
# This class represents an expectation. It is part
|
4
|
+
# of the stubbing mechanism. An expectation contains
|
5
|
+
# an url and options, like a request. They were compared
|
6
|
+
# to the request url and options in order to evaluate
|
7
|
+
# wether they match. If thats the case, the attached
|
8
|
+
# responses were returned one by one.
|
9
|
+
#
|
10
|
+
# @example Stub a request and get specified response.
|
11
|
+
# expected = Typhoeus::Response.new
|
12
|
+
# Typhoeus.stub("www.example.com").and_return(expected)
|
13
|
+
#
|
14
|
+
# actual = Typhoeus.get("www.example.com")
|
15
|
+
# expected == actual
|
16
|
+
# #=> true
|
17
|
+
class Expectation
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
attr_reader :url
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
attr_reader :options
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
attr_reader :from
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
# Returns all expectations.
|
31
|
+
#
|
32
|
+
# @example Return expectations.
|
33
|
+
# Typhoeus::Expectation.all
|
34
|
+
#
|
35
|
+
# @return [ Array<Typhoeus::Expectation> ] The expectations.
|
36
|
+
def all
|
37
|
+
@expectations ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
# Clears expectations. This is handy while
|
41
|
+
# testing and you want to make sure, that
|
42
|
+
# you don't get canned responses.
|
43
|
+
#
|
44
|
+
# @example Clear expectations.
|
45
|
+
# Typhoeus::Expectation.clear
|
46
|
+
def clear
|
47
|
+
all.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns expecation matching the provided
|
51
|
+
# request.
|
52
|
+
#
|
53
|
+
# @example Find expectation.
|
54
|
+
# Typhoeus::Expectation.find_by(request)
|
55
|
+
#
|
56
|
+
# @return [ Expectation ] The matching expectation.
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
def find_by(request)
|
60
|
+
all.find do |expectation|
|
61
|
+
expectation.matches?(request)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Creates an expactation.
|
67
|
+
#
|
68
|
+
# @example Create expactation.
|
69
|
+
# Typhoeus::Expectation.new(url)
|
70
|
+
#
|
71
|
+
# @return [ Expectation ] The created expactation.
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def initialize(url, options = {})
|
75
|
+
@url = url
|
76
|
+
@options = options
|
77
|
+
@response_counter = 0
|
78
|
+
@from = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
# Set from value to mark an expecation. Useful for
|
82
|
+
# other libraries, eg. webmock.
|
83
|
+
#
|
84
|
+
# @example Mark expecation.
|
85
|
+
# expecation.from(:webmock)
|
86
|
+
#
|
87
|
+
# @param [ String ] value Value to set.
|
88
|
+
#
|
89
|
+
# @return [ Expectation ] Returns self.
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
def stubbed_from(value)
|
93
|
+
@from = value
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Specify what should be returned,
|
98
|
+
# when this expactation is hit.
|
99
|
+
#
|
100
|
+
# @example Add response.
|
101
|
+
# expectation.and_return(response)
|
102
|
+
#
|
103
|
+
# @return [ void ]
|
104
|
+
def and_return(response)
|
105
|
+
responses << response
|
106
|
+
end
|
107
|
+
|
108
|
+
# Checks wether this expectation matches
|
109
|
+
# the provided request.
|
110
|
+
#
|
111
|
+
# @example Check if request matches.
|
112
|
+
# expectation.matches? request
|
113
|
+
#
|
114
|
+
# @param [ Request ] request The request to check.
|
115
|
+
#
|
116
|
+
# @return [ Boolean ] True when matches, else false.
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
def matches?(request)
|
120
|
+
url_match?(request.url) &&
|
121
|
+
(options ? options.all?{ |k,v| request.original_options[k] == v } : true)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return canned responses.
|
125
|
+
#
|
126
|
+
# @example Return responses.
|
127
|
+
# expectation.responses
|
128
|
+
#
|
129
|
+
# @return [ Array<Typhoeus::Response> ] The responses.
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
def responses
|
133
|
+
@responses ||= []
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return the response. When there are
|
137
|
+
# multiple responses, they were returned one
|
138
|
+
# by one.
|
139
|
+
#
|
140
|
+
# @example Return response.
|
141
|
+
# expectation.response
|
142
|
+
#
|
143
|
+
# @return [ Response ] The response.
|
144
|
+
#
|
145
|
+
# @api private
|
146
|
+
def response
|
147
|
+
response = responses.fetch(@response_counter, responses.last)
|
148
|
+
@response_counter += 1
|
149
|
+
response.mock = @from || true
|
150
|
+
response
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# Check wether the url matches the request url.
|
156
|
+
# The url can be a string, regex or nil. String and
|
157
|
+
# regexp were checked, nil is always true. Else false.
|
158
|
+
#
|
159
|
+
# Nil serves as a placeholder in case you want to match
|
160
|
+
# all urls.
|
161
|
+
def url_match?(request_url)
|
162
|
+
case url
|
163
|
+
when String
|
164
|
+
url == request_url
|
165
|
+
when Regexp
|
166
|
+
!!request_url.match(url)
|
167
|
+
when nil
|
168
|
+
true
|
169
|
+
else
|
170
|
+
false
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/typhoeus/hydra.rb
CHANGED
@@ -1,37 +1,94 @@
|
|
1
|
-
require 'typhoeus/
|
2
|
-
require 'typhoeus/
|
3
|
-
require 'typhoeus/
|
4
|
-
require 'typhoeus/
|
5
|
-
require 'typhoeus/
|
1
|
+
require 'typhoeus/hydra/before'
|
2
|
+
require 'typhoeus/hydra/block_connection'
|
3
|
+
require 'typhoeus/hydra/easy_factory'
|
4
|
+
require 'typhoeus/hydra/easy_pool'
|
5
|
+
require 'typhoeus/hydra/memoizable'
|
6
|
+
require 'typhoeus/hydra/queueable'
|
7
|
+
require 'typhoeus/hydra/runnable'
|
8
|
+
require 'typhoeus/hydra/stubbable'
|
6
9
|
|
7
10
|
module Typhoeus
|
8
11
|
|
9
12
|
# Hydra manages making parallel HTTP requests. This
|
10
|
-
# is
|
11
|
-
#
|
13
|
+
# is achieved by using libcurls multi interface:
|
14
|
+
# http://curl.haxx.se/libcurl/c/libcurl-multi.html
|
15
|
+
# The benefits are that you don't have to worry running
|
12
16
|
# the requests by yourself.
|
17
|
+
#
|
18
|
+
# Hydra will also handle how many requests you can
|
19
|
+
# make in parallel. Things will get flakey if you
|
20
|
+
# try to make too many requests at the same time.
|
21
|
+
# The built in limit is 200. When more requests than
|
22
|
+
# that are queued up, hydra will save them for later
|
23
|
+
# and start the requests as others are finished. You
|
24
|
+
# can raise or lower the concurrency limit through
|
25
|
+
# the Hydra constructor.
|
26
|
+
#
|
27
|
+
# Regarding the asynchronous behavior of the hydra,
|
28
|
+
# it is important to know that this is completely hidden
|
29
|
+
# from the developer and you are free to apply
|
30
|
+
# whatever technique you want to your code. That should not
|
31
|
+
# conflict with libcurls internal concurrency mechanism.
|
32
|
+
#
|
33
|
+
# @example Use the hydra to do multiple requests.
|
34
|
+
# hydra = Typhoeus::Hydra.new
|
35
|
+
# requests = (0..9).map{ Typhoeus::Request.new("www.example.com") }
|
36
|
+
# requests.each{ |request| hydra.queue(request) }
|
37
|
+
# hydra.run
|
13
38
|
class Hydra
|
14
|
-
include
|
15
|
-
include
|
16
|
-
include
|
17
|
-
include
|
39
|
+
include Hydra::EasyPool
|
40
|
+
include Hydra::Queueable
|
41
|
+
include Hydra::Runnable
|
42
|
+
include Hydra::Memoizable
|
43
|
+
include Hydra::BlockConnection
|
44
|
+
include Hydra::Stubbable
|
45
|
+
include Hydra::Before
|
18
46
|
|
19
|
-
|
47
|
+
# @example Set max_concurrency.
|
48
|
+
# Typhoeus::Hydra.new(:max_concurrency => 20)
|
49
|
+
attr_reader :max_concurrency
|
20
50
|
|
21
|
-
#
|
51
|
+
# @api private
|
52
|
+
attr_reader :multi
|
53
|
+
|
54
|
+
class << self
|
55
|
+
|
56
|
+
# Returns a memoized hydra instance.
|
57
|
+
#
|
58
|
+
# @example Get a hydra.
|
59
|
+
# Typhoeus::Hydra.hydra
|
60
|
+
#
|
61
|
+
# @return [Typhoeus::Hydra] A new hydra.
|
62
|
+
#
|
63
|
+
# @deprecated This is only for convenience because so
|
64
|
+
# much external code relies on it.
|
65
|
+
def hydra
|
66
|
+
@hydra ||= new
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Create a new hydra. All
|
71
|
+
# {http://rubydoc.info/github/typhoeus/ethon/Ethon/Multi#initialize-instance_method Ethon::Multi#initialize}
|
72
|
+
# options are also available.
|
22
73
|
#
|
23
74
|
# @example Create a hydra.
|
24
75
|
# Typhoeus::Hydra.new
|
25
76
|
#
|
77
|
+
# @example Create a hydra with max_concurrency.
|
78
|
+
# Typhoeus::Hydra.new(:max_concurrency => 20)
|
79
|
+
#
|
26
80
|
# @param [ Hash ] options The options hash.
|
27
81
|
#
|
28
82
|
# @option options :max_concurrency [ Integer ] Number
|
29
83
|
# of max concurrent connections to create. Default is
|
30
84
|
# 200.
|
85
|
+
#
|
86
|
+
# @see http://rubydoc.info/github/typhoeus/ethon/Ethon/Multi#initialize-instance_method
|
87
|
+
# Ethon::Multi#initialize
|
31
88
|
def initialize(options = {})
|
32
89
|
@options = options
|
33
90
|
@max_concurrency = @options.fetch(:max_concurrency, 200)
|
34
|
-
@multi = Ethon::Multi.new
|
91
|
+
@multi = Ethon::Multi.new(options.reject{|k,_| k==:max_concurrency})
|
35
92
|
end
|
36
93
|
end
|
37
94
|
end
|