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.
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