kronk 1.6.2 → 1.7.0

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 (48) hide show
  1. data/History.rdoc +29 -1
  2. data/Manifest.txt +6 -1
  3. data/README.rdoc +74 -28
  4. data/Rakefile +4 -3
  5. data/TODO.rdoc +7 -5
  6. data/bin/kronk +2 -11
  7. data/lib/kronk/async/em_ext.rb +34 -0
  8. data/lib/kronk/async/request.rb +73 -0
  9. data/lib/kronk/async/response.rb +70 -0
  10. data/lib/kronk/async.rb +118 -0
  11. data/lib/kronk/cmd.rb +111 -43
  12. data/lib/kronk/constants.rb +1 -0
  13. data/lib/kronk/core_ext.rb +1 -1
  14. data/lib/kronk/data_string.rb +251 -0
  15. data/lib/kronk/diff/output.rb +132 -100
  16. data/lib/kronk/diff.rb +20 -24
  17. data/lib/kronk/path/matcher.rb +8 -4
  18. data/lib/kronk/path/path_match.rb +48 -4
  19. data/lib/kronk/path/transaction.rb +74 -53
  20. data/lib/kronk/path.rb +11 -6
  21. data/lib/kronk/player/benchmark.rb +11 -12
  22. data/lib/kronk/player/input_reader.rb +40 -3
  23. data/lib/kronk/player/request_parser.rb +4 -1
  24. data/lib/kronk/player/stream.rb +2 -2
  25. data/lib/kronk/player/suite.rb +16 -9
  26. data/lib/kronk/player.rb +93 -143
  27. data/lib/kronk/queue_runner.rb +238 -0
  28. data/lib/kronk/request.rb +25 -20
  29. data/lib/kronk/response.rb +39 -10
  30. data/lib/kronk/test/assertions.rb +2 -2
  31. data/lib/kronk/test/helper_methods.rb +1 -1
  32. data/lib/kronk.rb +56 -24
  33. data/test/test_assertions.rb +4 -4
  34. data/test/test_cmd.rb +38 -10
  35. data/test/test_data_string.rb +242 -1
  36. data/test/test_diff.rb +8 -303
  37. data/test/test_helper.rb +1 -1
  38. data/test/test_kronk.rb +21 -28
  39. data/test/test_path.rb +29 -0
  40. data/test/test_path_match.rb +47 -2
  41. data/test/test_path_matcher.rb +42 -1
  42. data/test/test_player.rb +71 -72
  43. data/test/test_request.rb +31 -6
  44. data/test/test_request_parser.rb +7 -1
  45. data/test/test_response.rb +1 -1
  46. data/test/test_transaction.rb +78 -30
  47. metadata +64 -8
  48. data/lib/kronk/data_renderer.rb +0 -219
data/lib/kronk/player.rb CHANGED
@@ -6,33 +6,57 @@ class Kronk
6
6
  # Kronk includes a Suite (test-like) output, a Stream (chunked) output,
7
7
  # and a Benchmark output.
8
8
 
9
- class Player
9
+ class Player < QueueRunner
10
10
 
11
- attr_accessor :number, :concurrency, :queue, :count, :input,
12
- :output, :mutex, :threads, :reader_thread
11
+ RESCUABLE = [Kronk::Exception, Errno::ECONNRESET, URI::InvalidURIError]
12
+
13
+ attr_accessor :input, :output
13
14
 
14
15
  ##
15
16
  # Create a new Player for batch diff or response validation.
16
17
  # Supported options are:
17
- # :concurrency:: Fixnum - The maximum number of concurrent requests to make
18
- # :number:: Fixnum - The number of requests to make
19
18
  # :io:: IO - The IO instance to read from
20
19
  # :output:: Class - The output class to use (see Player::Output)
21
20
  # :parser:: Class - The IO parser to use.
22
21
 
23
22
  def initialize opts={}
24
- @number = opts[:number]
25
- @concurrency = opts[:concurrency]
26
- @concurrency = 1 if !@concurrency || @concurrency <= 0
23
+ super
27
24
  self.output_from opts[:output] || Suite
28
25
 
29
- @count = 0
30
- @queue = []
31
- @threads = []
32
- @input = InputReader.new opts[:io], opts[:parser]
33
- @last_req = nil
26
+ @input = InputReader.new opts[:io], opts[:parser]
27
+ @use_output = true
28
+ @last_req = nil
29
+
30
+ @on_input = Proc.new do
31
+ stop_input! if !@number && @input.eof?
32
+ @last_req = @input.get_next || @queue.last || @last_req || {}
33
+ end
34
+
35
+ @on_result = Proc.new do |kronk, err, mutex|
36
+ err ? @output.error(err, kronk, mutex) :
37
+ @output.result(kronk, mutex)
38
+ end
34
39
 
35
- @mutex = Mutex.new
40
+ on(:input, &@on_input)
41
+ on(:interrupt){
42
+ @output.completed if @use_output
43
+ exit 2
44
+ }
45
+ on(:start){ @output.start if @use_output }
46
+ on(:complete){ @output.completed if @use_output }
47
+ end
48
+
49
+
50
+ ##
51
+ # Populate the queue by reading from the given IO instance and
52
+ # parsing it into kronk options.
53
+ #
54
+ # Default parser is RequestParser. See InputReader for parser requirements.
55
+
56
+ def from_io io, parser=nil
57
+ @input.io = io
58
+ @input.parser = parser if parser
59
+ @input
36
60
  end
37
61
 
38
62
 
@@ -56,37 +80,17 @@ class Kronk
56
80
  end
57
81
 
58
82
 
59
- ##
60
- # Adds kronk request hash options to queue.
61
- # See Kronk#compare for supported options.
62
-
63
- def queue_req kronk_opts
64
- @queue << kronk_opts
65
- end
66
-
67
-
68
- ##
69
- # Populate the queue by reading from the given IO instance and
70
- # parsing it into kronk options.
71
- #
72
- # Default parser is RequestParser. See InputReader for parser requirements.
73
-
74
- def from_io io, parser=nil
75
- @input.io = io
76
- @input.parser = parser if parser
77
- @input
78
- end
79
-
80
-
81
83
  ##
82
84
  # Process the queue to compare two uris.
83
85
  # If options are given, they are merged into every request.
84
86
 
85
- def compare uri1, uri2, opts={}
87
+ def compare uri1, uri2, opts={}, &block
86
88
  return Cmd.compare uri1, uri2, @queue.shift.merge(opts) if single_request?
87
89
 
88
- process_queue do |kronk_opts|
89
- process_compare uri1, uri2, kronk_opts.merge(opts)
90
+ method = self.class.async ? :process_one_async : :process_one
91
+
92
+ run do |kronk_opts, mutex|
93
+ send method, kronk_opts.merge(opts), 'compare', uri1, uri2, &block
90
94
  end
91
95
  end
92
96
 
@@ -95,139 +99,85 @@ class Kronk
95
99
  # Process the queue to request uris.
96
100
  # If options are given, they are merged into every request.
97
101
 
98
- def request uri, opts={}
99
- return Cmd.request(uri, @queue.shift.merge(opts)) if single_request?
102
+ def request uri, opts={}, &block
103
+ return Cmd.request uri, @queue.shift.merge(opts) if single_request?
100
104
 
101
- process_queue do |kronk_opts|
102
- process_request uri, kronk_opts.merge(opts)
103
- end
104
- end
105
+ method = self.class.async ? :process_one_async : :process_one
105
106
 
106
-
107
- ##
108
- # Check if we're only processing a single case.
109
- # If so, yield a single item and return immediately.
110
-
111
- def single_request?
112
- @queue << next_request if @queue.empty? && (!@number || @number <= 1)
113
- @queue.length == 1 && @input.eof?
107
+ run do |kronk_opts, mutex|
108
+ send method, kronk_opts.merge(opts), 'request', uri, &block
109
+ end
114
110
  end
115
111
 
116
112
 
117
113
  ##
118
- # Start processing the queue and reading from IO if available.
119
- # Calls Output#start method and returns the value of Output#completed
120
- # once processing is finished.
114
+ # Run a single compare or request and call the Output#result or
115
+ # Output#error method.
121
116
  #
122
- # Yields queue item until queue and io (if available) are empty and the
123
- # totaly number of requests to run is met (if number is set).
124
-
125
- def process_queue
126
- @reader_thread = try_fill_queue
127
-
128
- trap 'INT' do
129
- @threads.each{|t| t.kill}
130
- @threads.clear
131
- @reader_thread.kill
132
- output_results
133
- exit 2
134
- end
135
-
136
- @output.start
137
- @count = 0
138
-
139
- until finished?
140
- @threads.delete_if{|t| !t.alive? }
141
- next if @threads.length >= @concurrency || @queue.empty?
117
+ # If given a block, will yield the Kronk instance and error. If
118
+ # a third argument is given, mutex will also be passed and the
119
+ # block won't be called from a mutex lock.
120
+ #
121
+ # Returns the result of the block or of the called Output method.
142
122
 
143
- @threads << Thread.new(@queue.shift) do |kronk_opts|
144
- yield kronk_opts if block_given?
145
- end
123
+ def process_one opts={}, *args, &block
124
+ err = nil
125
+ kronk = Kronk.new opts
146
126
 
147
- @count += 1
127
+ begin
128
+ kronk.send(*args)
129
+ rescue *RESCUABLE => e
130
+ err = e
148
131
  end
149
132
 
150
- @threads.each{|t| t.join}
151
- @threads.clear
152
-
153
- @reader_thread.kill
154
-
155
- output_results
133
+ trigger_result kronk, err, &block
156
134
  end
157
135
 
158
136
 
159
137
  ##
160
- # Attempt to fill the queue by reading from the IO instance.
161
- # Starts a new thread and returns the thread instance.
162
-
163
- def try_fill_queue
164
- Thread.new do
165
- loop do
166
- break if !@number && @input.eof?
167
- next if @queue.length >= @concurrency * 2
138
+ # Run a single compare or request and call the Output#result or
139
+ # Output#error method using EventMachine.
140
+ #
141
+ # If given a block, will yield the Kronk instance and error. If
142
+ # a third argument is given, mutex will also be passed and the
143
+ # block won't be called from a mutex lock.
144
+ #
145
+ # Returns either a EM::MultiRequest or an EM::Connection handler.
168
146
 
169
- max_new = @concurrency * 2 - @queue.length
147
+ def process_one_async opts={}, *args, &block
148
+ kronk = Kronk.new opts
149
+ method = args.shift.to_s + '_async'
170
150
 
171
- max_new.times do
172
- @queue << next_request
173
- break if !@number && @input.eof?
174
- end
175
- end
151
+ kronk.send(method, *args) do |obj, err|
152
+ raise err if err && !RESCUABLE.find{|eclass| eclass === err}
153
+ trigger_result kronk, err, &block
176
154
  end
177
155
  end
178
156
 
179
157
 
180
158
  ##
181
- # Gets the next request to perform and always returns a Hash.
182
- # Tries from input first, then from the last item in the queue.
183
- # If both fail, returns an empty Hash.
184
-
185
- def next_request
186
- @last_req = @input.get_next || @queue.last || @last_req || Hash.new
187
- end
159
+ # Trigger a single kronk result callback.
188
160
 
161
+ def trigger_result kronk, err, &block
162
+ block ||= @on_result
189
163
 
190
- ##
191
- # Returns true if processing queue should be stopped, otherwise false.
192
-
193
- def finished?
194
- (@number && @count >= @number) || @queue.empty? &&
195
- @input.eof? && @count > 0 && !@reader_thread.alive?
196
- end
197
-
198
-
199
- ##
200
- # Process and output the results.
201
- # Calls Output#completed method.
202
-
203
- def output_results
204
- @output.completed
205
- end
206
-
207
-
208
- ##
209
- # Run a single compare and call the Output#result or Output#error method.
210
-
211
- def process_compare uri1, uri2, opts={}
212
- kronk = Kronk.new opts
213
- kronk.compare uri1, uri2
214
- @output.result kronk, @mutex
215
-
216
- rescue Kronk::Exception, Response::MissingParser, Errno::ECONNRESET => e
217
- @output.error e, kronk, @mutex
164
+ if block.arity > 2 || block.arity < 0
165
+ block.call kronk, err, @mutex
166
+ else
167
+ @mutex.synchronize do
168
+ block.call kronk, err
169
+ end
170
+ end
218
171
  end
219
172
 
220
173
 
221
174
  ##
222
- # Run a single request and call the Output#result or Output#error method.
223
-
224
- def process_request uri, opts={}
225
- kronk = Kronk.new opts
226
- kronk.retrieve uri
227
- @output.result kronk, @mutex
175
+ # Check if w6ce5e2ce're only processing a single case.
176
+ # If so, yield a single item and return immediately.
228
177
 
229
- rescue Kronk::Exception, Response::MissingParser, Errno::ECONNRESET => e
230
- @output.error e, kronk, @mutex
178
+ def single_request?
179
+ @queue << trigger(:input) if @queue.empty? && (!@number || @number <= 1)
180
+ @queue.length == 1 && @triggers[:input] == @on_input && @input.eof?
231
181
  end
232
182
  end
233
183
  end
@@ -0,0 +1,238 @@
1
+ class Kronk
2
+
3
+ class QueueRunner
4
+
5
+ ##
6
+ # Define whether to use the EventMachine or the threaded behavior.
7
+
8
+ def self.async= value
9
+ @async = !!value
10
+ end
11
+
12
+
13
+ ##
14
+ # Returns true if EventMachine is enabled
15
+
16
+ def self.async
17
+ @async
18
+ end
19
+
20
+ self.async = false
21
+
22
+
23
+ attr_accessor :number, :concurrency, :queue, :count,
24
+ :mutex, :threads, :reader_thread
25
+
26
+ ##
27
+ # Create a new QueueRunner for batch multi-threaded processing.
28
+ # Supported options are:
29
+ # :concurrency:: Fixnum - Maximum number of concurrent items to process
30
+ # :number:: Fixnum - Total number of items to process
31
+
32
+ def initialize opts={}
33
+ @number = opts[:number]
34
+ @concurrency = opts[:concurrency]
35
+ @concurrency = 1 if !@concurrency || @concurrency <= 0
36
+
37
+ @count = 0
38
+ @queue = []
39
+ @threads = []
40
+
41
+ @reader_thread = nil
42
+
43
+ @triggers = {}
44
+
45
+ @mutex = Mutex.new
46
+ end
47
+
48
+
49
+ ##
50
+ # Returns true if processing queue should be stopped, otherwise false.
51
+
52
+ def finished?
53
+ return true if @number && @count >= @number
54
+
55
+ @queue.empty? && @count > 0 &&
56
+ (!@reader_thread || !@reader_thread.alive?)
57
+ end
58
+
59
+
60
+ ##
61
+ # Immediately end all runner processing and threads.
62
+
63
+ def kill
64
+ stop_input!
65
+ EM.stop if defined?(EM) && EM.reactor_running?
66
+ @threads.each{|t| t.kill}
67
+ @threads.clear
68
+ end
69
+
70
+
71
+ ##
72
+ # Specify a block to run for a given trigger name.
73
+ # Supported triggers are:
74
+ # :complete:: Called after queue and input have been fully processed.
75
+ # :input:: Called every time the queue needs populating.
76
+ # :interrupt:: Called when SIGINT is captured.
77
+ # :start:: Called before queue starts being processed.
78
+
79
+ def on trigger_name, &block
80
+ @triggers[trigger_name] = block
81
+ end
82
+
83
+
84
+ ##
85
+ # Start processing the queue and reading from IO if available.
86
+ #
87
+ # Yields queue item until queue and io (if available) are empty and the
88
+ # totaly number of requests to run is met (if number is set).
89
+
90
+ def process_queue
91
+ start_input!
92
+ @count = 0
93
+
94
+ until finished?
95
+ @threads.delete_if{|t| !t.alive? }
96
+
97
+ if @threads.length >= @concurrency || @queue.empty?
98
+ Thread.pass
99
+ next
100
+ end
101
+
102
+ @threads << Thread.new(@queue.shift) do |q_item|
103
+ yield q_item if block_given?
104
+ end
105
+
106
+ @count += 1
107
+ end
108
+
109
+ @threads.each{|t| t.join}
110
+ @threads.clear
111
+
112
+ stop_input!
113
+ end
114
+
115
+
116
+ ##
117
+ # Start processing the queue and reading from IO if available.
118
+ #
119
+ # Yields queue item until queue and io (if available) are empty and the
120
+ # totaly number of requests to run is met (if number is set).
121
+ #
122
+ # Uses EventMachine to run asynchronously.
123
+ #
124
+ # Note: If the block given doesn't use EM, it will be blocking.
125
+
126
+ def process_queue_async &block
127
+ # TODO: Make input use EM from QueueRunner and Player IO.
128
+ require 'kronk/async' unless defined?(EM::HttpRequest)
129
+ Cmd.verbose "Running async"
130
+
131
+ start_input!
132
+
133
+ @count = 0
134
+
135
+ EM.run do
136
+ EM.add_periodic_timer do
137
+ if finished?
138
+ next if EM.connection_count > 0
139
+ kill
140
+ next
141
+ end
142
+
143
+ if @queue.empty? || EM.connection_count >= @concurrency
144
+ Thread.pass
145
+ next
146
+ end
147
+
148
+ yield @queue.shift
149
+ @count += 1
150
+ end
151
+ end
152
+ end
153
+
154
+
155
+ ##
156
+ # Runs the queue and reads from input until it's exhausted or
157
+ # @number is reached. Yields a queue item and a mutex when to passed
158
+ # block:
159
+ #
160
+ # runner = QueueRunner.new :concurrency => 10
161
+ # runner.queue.concat %w{item1 item2 item3}
162
+ #
163
+ # runner.run do |q_item, mutex|
164
+ # # This block is run in its own thread.
165
+ # mutex.synchronize{ do_something_with q_item }
166
+ # end
167
+ #
168
+ # Calls the :start trigger before execution begins, calls :complete
169
+ # when the execution has ended or is interrupted, also calls :interrupt
170
+ # when execution is interrupted.
171
+
172
+ def run
173
+ trap 'INT' do
174
+ kill
175
+ (trigger(:interrupt) || exit(1))
176
+ end
177
+
178
+ trigger :start
179
+
180
+ method = self.class.async ? :process_queue_async : :process_queue
181
+
182
+ send method do |q_item|
183
+ yield q_item, @mutex if block_given?
184
+ end
185
+
186
+ trigger :complete
187
+ end
188
+
189
+
190
+ ##
191
+ # Attempt to fill the queue by reading from the IO instance.
192
+ # Starts a new thread and returns the thread instance.
193
+
194
+ def start_input!
195
+ return unless @triggers[:input]
196
+
197
+ max_queue_size = @concurrency * 2
198
+
199
+ @reader_thread = Thread.new do
200
+ begin
201
+ loop do
202
+ if @queue.length >= max_queue_size
203
+ Thread.pass
204
+ next
205
+ end
206
+
207
+ while @queue.length < max_queue_size
208
+ @queue << trigger(:input)
209
+ end
210
+ Thread.pass
211
+ end
212
+
213
+ rescue => e
214
+ Thread.main.raise e
215
+ end
216
+ end
217
+ end
218
+
219
+
220
+ ##
221
+ # Permanently stop input reading by killing the reader thread for a given
222
+ # QueueRunner#run or QueueRunner#process_queue session.
223
+
224
+ def stop_input!
225
+ Thread.pass
226
+ @reader_thread && @reader_thread.kill
227
+ end
228
+
229
+
230
+ ##
231
+ # Run a previously defined callback. See QueueRunner#on.
232
+
233
+ def trigger name
234
+ t = @triggers[name]
235
+ t && t.call
236
+ end
237
+ end
238
+ end
data/lib/kronk/request.rb CHANGED
@@ -1,15 +1,17 @@
1
1
  class Kronk
2
2
 
3
3
  ##
4
- # Performs HTTP requests or retrieves HTTP responses.
4
+ # Performs HTTP requests and returns a Kronk::Response instance.
5
5
 
6
6
  class Request
7
7
 
8
8
  # Raised by Request.parse when parsing invalid http request string.
9
9
  class ParseError < Kronk::Exception; end
10
10
 
11
- # Matches the first line of an http request string.
12
- REQUEST_LINE_MATCHER = %r{([A-Za-z]+)?(^|[\s'"])(/[^\s'";]+)[\s"']*}
11
+ # Matches the first line of an http request string or a fully
12
+ # qualified URL.
13
+ REQUEST_LINE_MATCHER =
14
+ %r{(?:^|[\s'"])(?:([a-z]+)\s)?(?:(https?://[^/]+)(/[^\s'";]*)?|(/[^\s'";]*))}i
13
15
 
14
16
  ##
15
17
  # Creates a query string from data.
@@ -45,7 +47,7 @@ class Kronk
45
47
  # path and options.
46
48
 
47
49
  def self.build_uri uri, options={}
48
- uri ||= Kronk.config[:default_host]
50
+ uri ||= options[:host] || Kronk.config[:default_host]
49
51
  suffix = options[:uri_suffix]
50
52
 
51
53
  uri = "http://#{uri}" unless uri.to_s =~ %r{^(\w+://|/)}
@@ -64,6 +66,7 @@ class Kronk
64
66
 
65
67
  ##
66
68
  # Parses a raw HTTP request-like string into a Kronk::Request instance.
69
+ # Options passed are used as default values for Request#new.
67
70
 
68
71
  def self.parse str, opts={}
69
72
  opts = parse_to_hash str, opts
@@ -75,7 +78,8 @@ class Kronk
75
78
 
76
79
  ##
77
80
  # Parses a raw HTTP request-like string into a Kronk::Request options hash.
78
- # Also parses most single access log entries.
81
+ # Also parses most single access log entries. Options passed are used
82
+ # as default values for Request#new.
79
83
 
80
84
  def self.parse_to_hash str, opts={}
81
85
  lines = str.split("\n")
@@ -86,7 +90,9 @@ class Kronk
86
90
  opts[:headers] ||= {}
87
91
 
88
92
  lines.shift.strip =~ REQUEST_LINE_MATCHER
89
- opts[:http_method], opts[:uri_suffix] = $1, $3
93
+ opts.merge! :http_method => $1,
94
+ :host => $2,
95
+ :uri_suffix => ($3 || $4)
90
96
 
91
97
  lines.each_with_index do |line, i|
92
98
  case line
@@ -105,6 +111,7 @@ class Kronk
105
111
 
106
112
  opts[:data] = lines[body_start..-1].join("\n") if body_start
107
113
 
114
+ opts.delete(:host) if !opts[:host]
108
115
  opts.delete(:uri_suffix) if !opts[:uri_suffix]
109
116
  opts.delete(:headers) if opts[:headers].empty?
110
117
  opts.delete(:http_method) if !opts[:http_method]
@@ -178,7 +185,7 @@ class Kronk
178
185
  end
179
186
 
180
187
 
181
- attr_accessor :body, :headers, :response, :timeout
188
+ attr_accessor :body, :headers, :proxy, :response, :timeout
182
189
 
183
190
  attr_reader :http_method, :uri, :use_cookies
184
191
 
@@ -187,18 +194,16 @@ class Kronk
187
194
  # Supports the following options:
188
195
  # :data:: Hash/String - the data to pass to the http request
189
196
  # :query:: Hash/String - the data to append to the http request path
190
- # :follow_redirects:: Integer/Bool - number of times to follow redirects
191
197
  # :user_agent:: String - user agent string or alias; defaults to 'kronk'
192
198
  # :auth:: Hash - must contain :username and :password; defaults to nil
193
199
  # :headers:: Hash - extra headers to pass to the request
194
200
  # :http_method:: Symbol - the http method to use; defaults to :get
195
- # :proxy:: Hash/String - http proxy to use; defaults to nil
201
+ # :proxy:: Hash/String - http proxy to use; defaults to {}
196
202
  #
197
203
  # Note: if no http method is specified and data is given, will default
198
204
  # to using a post request.
199
205
 
200
206
  def initialize uri, options={}
201
- @HTTP = Net::HTTP
202
207
  @auth = options[:auth]
203
208
 
204
209
  @body = nil
@@ -213,18 +218,15 @@ class Kronk
213
218
 
214
219
  @uri = self.class.build_uri uri, options
215
220
 
221
+ @proxy = options[:proxy] || {}
222
+ @proxy = {:host => @proxy} unless Hash === @proxy
223
+
216
224
  self.user_agent ||= options[:user_agent]
217
225
 
218
226
  self.http_method = options[:http_method] || (@body ? "POST" : "GET")
219
227
 
220
228
  self.use_cookies = options.has_key?(:no_cookies) ?
221
229
  !options[:no_cookies] : Kronk.config[:use_cookies]
222
-
223
- if Hash === options[:proxy]
224
- self.use_proxy options[:proxy][:address], options[:proxy]
225
- else
226
- self.use_proxy options[:proxy]
227
- end
228
230
  end
229
231
 
230
232
 
@@ -278,8 +280,8 @@ class Kronk
278
280
  # The proxy_opts arg can be a uri String or a Hash with the :address key
279
281
  # and optional :username and :password keys.
280
282
 
281
- def use_proxy addr, opts={}
282
- return @HTTP = Net::HTTP unless addr
283
+ def http_proxy addr, opts={}
284
+ return Net::HTTP unless addr
283
285
 
284
286
  host, port = addr.split ":"
285
287
  port ||= opts[:port] || 8080
@@ -289,7 +291,7 @@ class Kronk
289
291
 
290
292
  Kronk::Cmd.verbose "Using proxy #{addr}\n" if host
291
293
 
292
- @HTTP = Net::HTTP::Proxy host, port, user, pass
294
+ Net::HTTP::Proxy host, port, user, pass
293
295
  end
294
296
 
295
297
 
@@ -355,7 +357,9 @@ class Kronk
355
357
  # Retrieve this requests' response.
356
358
 
357
359
  def retrieve
358
- @_req = @HTTP.new @uri.host, @uri.port
360
+ http_class = http_proxy @proxy[:host], @proxy
361
+
362
+ @_req = http_class.new @uri.host, @uri.port
359
363
 
360
364
  @_req.read_timeout = @timeout if @timeout
361
365
  @_req.use_ssl = true if @uri.scheme =~ /^https$/
@@ -424,3 +428,4 @@ class Kronk
424
428
  end
425
429
  end
426
430
  end
431
+