typhoeus 0.5.0.pre → 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 (38) hide show
  1. data/CHANGELOG.md +12 -0
  2. data/Gemfile +17 -1
  3. data/README.md +2 -2
  4. data/lib/typhoeus.rb +78 -16
  5. data/lib/typhoeus/config.rb +40 -4
  6. data/lib/typhoeus/errors.rb +9 -0
  7. data/lib/typhoeus/errors/no_stub.rb +12 -0
  8. data/lib/typhoeus/errors/typhoeus_error.rb +8 -0
  9. data/lib/typhoeus/expectation.rb +174 -0
  10. data/lib/typhoeus/hydra.rb +71 -14
  11. data/lib/typhoeus/hydra/before.rb +30 -0
  12. data/lib/typhoeus/hydra/block_connection.rb +35 -0
  13. data/lib/typhoeus/{hydras → hydra}/easy_factory.rb +17 -5
  14. data/lib/typhoeus/{hydras → hydra}/easy_pool.rb +4 -2
  15. data/lib/typhoeus/{hydras → hydra}/memoizable.rb +7 -5
  16. data/lib/typhoeus/{hydras → hydra}/queueable.rb +5 -3
  17. data/lib/typhoeus/{hydras → hydra}/runnable.rb +4 -1
  18. data/lib/typhoeus/hydra/stubbable.rb +26 -0
  19. data/lib/typhoeus/request.rb +117 -29
  20. data/lib/typhoeus/request/actions.rb +125 -0
  21. data/lib/typhoeus/request/before.rb +30 -0
  22. data/lib/typhoeus/request/block_connection.rb +52 -0
  23. data/lib/typhoeus/request/callbacks.rb +98 -0
  24. data/lib/typhoeus/{requests → request}/marshal.rb +1 -1
  25. data/lib/typhoeus/{requests → request}/memoizable.rb +4 -2
  26. data/lib/typhoeus/{requests → request}/operations.rb +25 -5
  27. data/lib/typhoeus/{requests → request}/responseable.rb +1 -1
  28. data/lib/typhoeus/request/stubbable.rb +28 -0
  29. data/lib/typhoeus/response.rb +30 -8
  30. data/lib/typhoeus/{responses → response}/header.rb +15 -11
  31. data/lib/typhoeus/response/informations.rb +205 -0
  32. data/lib/typhoeus/{responses → response}/status.rb +10 -7
  33. data/lib/typhoeus/version.rb +1 -1
  34. metadata +32 -135
  35. data/lib/typhoeus/requests/actions.rb +0 -17
  36. data/lib/typhoeus/requests/callbacks.rb +0 -48
  37. data/lib/typhoeus/responses/informations.rb +0 -43
  38. 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
- # If you want to make a single request, go with:
14
- # Typhoeus.get("www.example.com")
15
+ # @example (see Typhoeus::Request)
16
+ # @example (see Typhoeus::Hydra)
15
17
  #
16
- # When you looking for firing a bunch of requests automatically
17
- # choose the hydra:
18
+ # @see Typhoeus::Request
19
+ # @see Typhoeus::Hydra
18
20
  #
19
- # hydra = Typhoeus::Hydra.new
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 Hydras::EasyPool
26
- extend Requests::Actions
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 Set the configuration options.
34
- # Typhoeus.configure do |config|
35
- # config.verbose = true
36
- # end
33
+ # @example (see Typhoeus::Config)
34
+ #
35
+ # @yield [ Typhoeus::Config ]
37
36
  #
38
- # @return [ Config ] The configuration object.
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
@@ -1,11 +1,47 @@
1
1
  module Typhoeus
2
2
 
3
3
  # The Typhoeus configuration used to set global
4
- # options. Available options:
5
- # * verbose
6
- # * memoize.
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
- attr_accessor :verbose, :memoize
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,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,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,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
@@ -1,37 +1,94 @@
1
- require 'typhoeus/hydras/easy_factory'
2
- require 'typhoeus/hydras/easy_pool'
3
- require 'typhoeus/hydras/memoizable'
4
- require 'typhoeus/hydras/queueable'
5
- require 'typhoeus/hydras/runnable'
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 archived by using libcurls multi interface. The
11
- # benefits are that you don't have to worry running
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 Hydras::EasyPool
15
- include Hydras::Queueable
16
- include Hydras::Runnable
17
- include Hydras::Memoizable
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
- attr_reader :max_concurrency, :multi
47
+ # @example Set max_concurrency.
48
+ # Typhoeus::Hydra.new(:max_concurrency => 20)
49
+ attr_reader :max_concurrency
20
50
 
21
- # Create a new hydra.
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