typhoeus 0.4.2 → 0.5.0.rc

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.
Files changed (57) hide show
  1. data/CHANGELOG.md +86 -28
  2. data/Gemfile +17 -1
  3. data/README.md +20 -422
  4. data/Rakefile +21 -12
  5. data/lib/typhoeus/config.rb +47 -0
  6. data/lib/typhoeus/errors/no_stub.rb +12 -0
  7. data/lib/typhoeus/errors/typhoeus_error.rb +8 -0
  8. data/lib/typhoeus/errors.rb +9 -0
  9. data/lib/typhoeus/expectation.rb +174 -0
  10. data/lib/typhoeus/hydra/before.rb +30 -0
  11. data/lib/typhoeus/hydra/block_connection.rb +35 -0
  12. data/lib/typhoeus/hydra/easy_factory.rb +79 -0
  13. data/lib/typhoeus/hydra/easy_pool.rb +42 -0
  14. data/lib/typhoeus/hydra/memoizable.rb +55 -0
  15. data/lib/typhoeus/hydra/queueable.rb +48 -0
  16. data/lib/typhoeus/hydra/runnable.rb +21 -0
  17. data/lib/typhoeus/hydra/stubbable.rb +26 -0
  18. data/lib/typhoeus/hydra.rb +83 -236
  19. data/lib/typhoeus/request/actions.rb +125 -0
  20. data/lib/typhoeus/request/before.rb +30 -0
  21. data/lib/typhoeus/request/block_connection.rb +52 -0
  22. data/lib/typhoeus/request/callbacks.rb +98 -0
  23. data/lib/typhoeus/request/marshal.rb +21 -0
  24. data/lib/typhoeus/request/memoizable.rb +38 -0
  25. data/lib/typhoeus/request/operations.rb +71 -0
  26. data/lib/typhoeus/request/responseable.rb +29 -0
  27. data/lib/typhoeus/request/stubbable.rb +28 -0
  28. data/lib/typhoeus/request.rb +144 -241
  29. data/lib/typhoeus/response/header.rb +54 -0
  30. data/lib/typhoeus/response/informations.rb +205 -0
  31. data/lib/typhoeus/response/status.rb +80 -0
  32. data/lib/typhoeus/response.rb +45 -118
  33. data/lib/typhoeus/version.rb +3 -1
  34. data/lib/typhoeus.rb +87 -39
  35. metadata +37 -143
  36. data/lib/typhoeus/curl.rb +0 -453
  37. data/lib/typhoeus/easy/auth.rb +0 -14
  38. data/lib/typhoeus/easy/callbacks.rb +0 -33
  39. data/lib/typhoeus/easy/ffi_helper.rb +0 -61
  40. data/lib/typhoeus/easy/infos.rb +0 -90
  41. data/lib/typhoeus/easy/options.rb +0 -115
  42. data/lib/typhoeus/easy/proxy.rb +0 -20
  43. data/lib/typhoeus/easy/ssl.rb +0 -82
  44. data/lib/typhoeus/easy.rb +0 -115
  45. data/lib/typhoeus/filter.rb +0 -28
  46. data/lib/typhoeus/form.rb +0 -61
  47. data/lib/typhoeus/header.rb +0 -54
  48. data/lib/typhoeus/hydra/callbacks.rb +0 -24
  49. data/lib/typhoeus/hydra/connect_options.rb +0 -61
  50. data/lib/typhoeus/hydra/stubbing.rb +0 -68
  51. data/lib/typhoeus/hydra_mock.rb +0 -131
  52. data/lib/typhoeus/multi.rb +0 -146
  53. data/lib/typhoeus/param_processor.rb +0 -43
  54. data/lib/typhoeus/remote.rb +0 -306
  55. data/lib/typhoeus/remote_method.rb +0 -108
  56. data/lib/typhoeus/remote_proxy_object.rb +0 -50
  57. data/lib/typhoeus/utils.rb +0 -50
@@ -0,0 +1,47 @@
1
+ module Typhoeus
2
+
3
+ # The Typhoeus configuration used to set global
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
12
+ module Config
13
+ extend self
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
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ module Typhoeus
2
+ module Errors
3
+
4
+ # Raises when block connection is turned on
5
+ # and making a real request.
6
+ class NoStub < TyphoeusError
7
+ def initialize(request)
8
+ super("The connection is blocked and no stub defined.")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Typhoeus
2
+ module Errors
3
+
4
+ # Default typhoeus error class for all custom errors.
5
+ class TyphoeusError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'typhoeus/errors/typhoeus_error'
2
+ require 'typhoeus/errors/no_stub'
3
+
4
+ module Typhoeus
5
+
6
+ # This namespace contains all errors raised by typhoeus.
7
+ module Errors
8
+ end
9
+ 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
@@ -0,0 +1,30 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module provides a way to hook into before
5
+ # a request gets queued in hydra. This is very powerful
6
+ # and you should be careful because when you accidently
7
+ # return a falsy value the request won't be executed.
8
+ #
9
+ # @api private
10
+ module Before
11
+
12
+ # Overrride queue in order to execute callbacks in
13
+ # Typhoeus.before. Will break and return when a
14
+ # callback returns nil or false. Calls super
15
+ # otherwise.
16
+ #
17
+ # @example Queue the request.
18
+ # hydra.queue(request)
19
+ def queue(request)
20
+ Typhoeus.before.each do |callback|
21
+ value = callback.call(request)
22
+ if value.nil? || value == false || value.is_a?(Response)
23
+ return value
24
+ end
25
+ end
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module handles the blocked connection request mode on
5
+ # the hydra side, where only stubbed requests
6
+ # are allowed.
7
+ # Connection blocking needs to be turned on:
8
+ # Typhoeus.configure do |config|
9
+ # config.block_connection = true
10
+ # end
11
+ #
12
+ # When trying to do real requests a NoStub error
13
+ # is raised.
14
+ #
15
+ # @api private
16
+ module BlockConnection
17
+
18
+ # Overrides queue in order to check before if block connection
19
+ # is turned on. If thats the case a NoStub error is
20
+ # raised.
21
+ #
22
+ # @example Queue the request.
23
+ # hydra.queue(request)
24
+ #
25
+ # @param [ Request ] request The request to enqueue.
26
+ def queue(request)
27
+ if request.blocked?
28
+ raise Typhoeus::Errors::NoStub.new(request)
29
+ else
30
+ super
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,79 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This is a Factory for easies to be used in the hydra.
5
+ # Before an easy is ready to be added to a multi, it needs
6
+ # to be prepared and the on_complete callback to be set.
7
+ # This is done by this class.
8
+ #
9
+ # @api private
10
+ class EasyFactory
11
+
12
+ # Returns the request provided.
13
+ #
14
+ # @return [ Typhoeus::Request ]
15
+ attr_reader :request
16
+
17
+ # Returns the hydra provided.
18
+ #
19
+ # @return [ Typhoeus::Hydra ]
20
+ attr_reader :hydra
21
+
22
+ # Create an easy factory.
23
+ #
24
+ # @example Create easy factory.
25
+ # Typhoeus::Hydra::EasyFactory.new(request, hydra)
26
+ #
27
+ # @param [ Request ] request The request to build an easy for.
28
+ # @param [ Hydra ] hydra The hydra to build an easy for.
29
+ def initialize(request, hydra)
30
+ @request = request
31
+ @hydra = hydra
32
+ end
33
+
34
+ # Return the easy in question.
35
+ #
36
+ # @example Return easy.
37
+ # easy_factory.easy
38
+ #
39
+ # @return [ Ethon::Easy ] The easy.
40
+ def easy
41
+ @easy ||= hydra.get_easy
42
+ end
43
+
44
+ # Fabricated and prepared easy.
45
+ #
46
+ # @example Prepared easy.
47
+ # easy_factory.get
48
+ #
49
+ # @return [ Ethon::Easy ] The prepared easy.
50
+ def get
51
+ easy.http_request(
52
+ request.url,
53
+ request.options.fetch(:method, :get),
54
+ request.options.reject{|k,_| k==:method}
55
+ )
56
+ easy.prepare
57
+ set_callback
58
+ easy
59
+ end
60
+
61
+ private
62
+
63
+ # Sets on_complete callback on easy in order to be able to
64
+ # track progress.
65
+ #
66
+ # @example Set callback.
67
+ # easy_factory.set_callback
68
+ #
69
+ # @return [ Ethon::Easy ] The easy.
70
+ def set_callback
71
+ easy.on_complete do |easy|
72
+ request.finish(Response.new(easy.to_hash))
73
+ hydra.release_easy(easy)
74
+ hydra.queue(hydra.queued_requests.shift) unless hydra.queued_requests.empty?
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,42 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # The easy pool stores already initialized
5
+ # easy handles for future use. This is useful
6
+ # because creating them is quite expensive.
7
+ #
8
+ # @api private
9
+ module EasyPool
10
+
11
+ # Return the easy pool.
12
+ #
13
+ # @example Return easy pool.
14
+ # hydra.easy_pool
15
+ #
16
+ # @return [ Array<Ethon::Easy> ] The easy pool.
17
+ def easy_pool
18
+ @easy_pool ||= []
19
+ end
20
+
21
+ # Releases easy into pool. The easy handle is
22
+ # resetted before it gets back in.
23
+ #
24
+ # @example Release easy.
25
+ # hydra.release_easy(easy)
26
+ def release_easy(easy)
27
+ easy.reset
28
+ easy_pool << easy
29
+ end
30
+
31
+ # Return an easy from pool.
32
+ #
33
+ # @example Return easy.
34
+ # hydra.get_easy
35
+ #
36
+ # @return [ Ethon::Easy ] The easy.
37
+ def get_easy
38
+ easy_pool.pop || Ethon::Easy.new
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module handles the GET request memoization
5
+ # on the hydra side. Memoization needs to be turned
6
+ # on:
7
+ # Typhoeus.configure do |config|
8
+ # config.memoize = true
9
+ # end
10
+ #
11
+ # @api private
12
+ module Memoizable
13
+
14
+ # Return the memory.
15
+ #
16
+ # @example Return the memory.
17
+ # hydra.memory
18
+ #
19
+ # @return [ Hash ] The memory.
20
+ def memory
21
+ @memory ||= {}
22
+ end
23
+
24
+ # Overrides queue in order to check before if request
25
+ # is memoizable and already in memory. If thats the case,
26
+ # super is not called, instead the response is set and
27
+ # the on_complete callback called.
28
+ #
29
+ # @example Queue the request.
30
+ # hydra.queue(request)
31
+ #
32
+ # @param [ Request ] request The request to enqueue.
33
+ #
34
+ # @return [ Request ] The queued request.
35
+ def queue(request)
36
+ if request.memoizable? && memory.has_key?(request)
37
+ response = memory[request]
38
+ request.finish(response, true)
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ # Overrides run to make sure the memory is cleared after
45
+ # each run.
46
+ #
47
+ # @example Run hydra.
48
+ # hydra.run
49
+ def run
50
+ super
51
+ memory.clear
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,48 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module handles the request queueing on
5
+ # hydra.
6
+ #
7
+ # @api private
8
+ module Queueable
9
+
10
+ # Return the queued requests.
11
+ #
12
+ # @example Return queued requests.
13
+ # hydra.queued_requests
14
+ #
15
+ # @return [ Array<Typhoeus::Request> ] The queued requests.
16
+ def queued_requests
17
+ @queued_requests ||= []
18
+ end
19
+
20
+ # Abort the current hydra run as good as
21
+ # possible. This means that it only
22
+ # clears the queued requests and can't do
23
+ # anything about already running requests.
24
+ #
25
+ # @example Abort hydra.
26
+ # hydra.abort
27
+ def abort
28
+ queued_requests.clear
29
+ end
30
+
31
+ # Enqueues a request in order to be performed
32
+ # by the hydra. This can even be done while
33
+ # the hydra is running. Also sets hydra on
34
+ # request.
35
+ #
36
+ # @example Queue request.
37
+ # hydra.queue(request)
38
+ def queue(request)
39
+ request.hydra = self
40
+ if multi.easy_handles.size < max_concurrency
41
+ multi.add(Hydra::EasyFactory.new(request, self).get)
42
+ else
43
+ queued_requests << request
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module contains logic to run a hydra.
5
+ #
6
+ # @api private
7
+ module Runnable
8
+
9
+ # Start the hydra run.
10
+ #
11
+ # @example Start hydra run.
12
+ # hydra.run
13
+ #
14
+ # @return [ Symbol ] Return value from multi.perform.
15
+ def run
16
+ multi.prepare
17
+ multi.perform
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ module Typhoeus
2
+ class Hydra
3
+
4
+ # This module handles stubbing on the hydra side.
5
+ # It plays well with the block_connection configuration,
6
+ # which raises when you make a request which is not stubbed.
7
+ #
8
+ # @api private
9
+ module Stubbable
10
+
11
+ # Override queue in order to check for matching expecations.
12
+ # When an expecation is found, super is not called. Instead a
13
+ # canned response is assigned to the request.
14
+ #
15
+ # @example Queue the request.
16
+ # hydra.queue(request)
17
+ def queue(request)
18
+ if expectation = Expectation.find_by(request)
19
+ request.finish(expectation.response)
20
+ else
21
+ super
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end