amee 4.3.2 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/CHANGELOG.txt +6 -0
  2. data/Gemfile +7 -1
  3. data/Rakefile +2 -0
  4. data/VERSION +1 -1
  5. data/amee.gemspec +57 -6
  6. data/amee_test_credentials.example.yml +11 -0
  7. data/cassettes/AMEE_Connection/v2/raising_unhandled_errors.yml +36 -0
  8. data/cassettes/AMEE_Connection/v3/retries/502.yml +36 -0
  9. data/cassettes/AMEE_Connection/v3/retries/503.yml +36 -0
  10. data/cassettes/AMEE_Connection/v3/retries/504.yml +36 -0
  11. data/cassettes/AMEE_Connection/v3/retries/AMEE_TimeOut.yml +36 -0
  12. data/cassettes/AMEE_Connection/v3/should_be_able_to_get_from_meta_server.yml +30 -0
  13. data/cassettes/AMEE_Connection/v3/should_be_able_to_handle_failed_gets_from_meta_server.yml +30 -0
  14. data/cassettes/AMEE_Connection/v3/should_be_able_to_post_to_meta_server.yml +59 -0
  15. data/cassettes/AMEE_Connection/v3/should_have_a_connection_to_meta_server.yml +36 -0
  16. data/cassettes/AMEE_Connection/v3/should_login_and_know_the_path_to_the_server.yml +36 -0
  17. data/cassettes/AMEE_Connection_Caching_Off/authenticating.yml +36 -0
  18. data/cassettes/AMEE_Connection_Caching_Off/first_request.yml +40 -0
  19. data/cassettes/AMEE_Connection_Caching_Off/second_request.yml +40 -0
  20. data/cassettes/AMEE_Connection_Caching_On/authenticating.yml +36 -0
  21. data/cassettes/AMEE_Connection_Caching_On/first_request.yml +40 -0
  22. data/cassettes/AMEE_Connection_Caching_clear_all/second_request.yml +40 -0
  23. data/cassettes/AMEE_Connection_Caching_clear_manually/second_request.yml +40 -0
  24. data/cassettes/AMEE_Connection_Caching_further_down_tree/second_request.yml +79 -0
  25. data/cassettes/AMEE_Connection_with_authentication/handling_404s.yml +69 -0
  26. data/cassettes/AMEE_Connection_with_authentication/hitting_private_urls.yml +75 -0
  27. data/cassettes/AMEE_Connection_with_authentication/raising_errors_if_permission_denied.yml +69 -0
  28. data/cassettes/AMEE_Connection_with_authentication/should_re-authenticate_and_refresh_authtoken_when_authtoken_expires.yml +104 -0
  29. data/cassettes/AMEE_Connection_with_authentication/should_refresh_authtoken_when_authtoken_is_changed.yml +114 -0
  30. data/cassettes/AMEE_Connection_with_authentication/using_a_v1_key.yml +71 -0
  31. data/cassettes/AMEE_Connection_with_authentication/using_a_v2_key/detects_the_API_version_for_JSON.yml +36 -0
  32. data/cassettes/AMEE_Connection_with_authentication/using_a_v2_key/detects_the_API_version_for_XML.yml +36 -0
  33. data/cassettes/AMEE_Connection_with_authentication_doing_write-requests.yml +75 -0
  34. data/cassettes/AMEE_Connection_with_authentication_doing_write-requests/working_with_an_existing_profile/deleting_existing_items.yml +108 -0
  35. data/cassettes/AMEE_Connection_with_authentication_doing_write-requests/working_with_an_existing_profile/sending_updates_to_existing_items.yml +108 -0
  36. data/cassettes/AMEE_Connection_with_bad_authentication_information/hitting_a_private_url.yml +29 -0
  37. data/cassettes/AMEE_Connection_with_bad_authentication_information/hitting_a_public_url.yml +32 -0
  38. data/cassettes/AMEE_Connection_with_incorrect_server_name.yml +16 -0
  39. data/cassettes/AMEE_Connection_with_retry_enabled.yml +36 -0
  40. data/lib/amee/connection.rb +234 -110
  41. data/lib/amee/data_category.rb +2 -2
  42. data/lib/amee/data_item.rb +45 -2
  43. data/lib/amee/data_item_value.rb +1 -1
  44. data/lib/amee/exceptions.rb +5 -2
  45. data/lib/amee/parse_helper.rb +2 -0
  46. data/lib/amee/profile_item.rb +6 -2
  47. data/lib/amee/v3/connection.rb +77 -70
  48. data/lib/amee/v3/item_value_definition.rb +1 -1
  49. data/lib/amee/v3/return_value_definition.rb +1 -1
  50. data/spec/cache_spec.rb +107 -48
  51. data/spec/connection_spec.rb +224 -183
  52. data/spec/data_item_spec.rb +12 -0
  53. data/spec/data_item_value_history_spec.rb +4 -4
  54. data/spec/data_item_value_spec.rb +2 -2
  55. data/spec/fixtures/AD63A83B4D41.json +1 -1
  56. data/spec/fixtures/AD63A83B4D41.xml +1 -1
  57. data/spec/profile_item_spec.rb +14 -10
  58. data/spec/spec_helper.rb +29 -0
  59. data/spec/v3/connection_spec.rb +77 -65
  60. data/spec/v3/item_value_definition_spec.rb +1 -0
  61. data/spec/v3/return_value_definition_spec.rb +1 -1
  62. metadata +140 -24
  63. data/Gemfile.lock +0 -63
@@ -1,8 +1,16 @@
1
1
  # Copyright (C) 2008-2011 AMEE UK Ltd. - http://www.amee.com
2
2
  # Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
3
3
 
4
- require 'net/http'
5
- require 'net/https'
4
+ require 'typhoeus'
5
+ require 'json'
6
+ require 'log_buddy'
7
+
8
+
9
+
10
+ # LogBuddy.init :log_to_stdout => false
11
+ LogBuddy.init :disabled => true
12
+ # Set this to true to output curl debug messages in development
13
+ DEBUG = false
6
14
 
7
15
  module AMEE
8
16
  class Connection
@@ -13,6 +21,7 @@ module AMEE
13
21
  unless options.is_a?(Hash)
14
22
  raise AMEE::ArgumentError.new("Fourth argument must be a hash of options!")
15
23
  end
24
+
16
25
  @server = server
17
26
  @username = username
18
27
  @password = password
@@ -25,6 +34,9 @@ module AMEE
25
34
  if !valid?
26
35
  raise "You must supply connection details - server, username and password are all required!"
27
36
  end
37
+
38
+ # Working with caching
39
+
28
40
  # Handle old option
29
41
  if options[:enable_caching]
30
42
  Kernel.warn '[DEPRECATED] :enable_caching => true is deprecated. Use :cache => :memory_store instead'
@@ -33,7 +45,7 @@ module AMEE
33
45
  # Create cache store
34
46
  if options[:cache] &&
35
47
  (options[:cache_store].class.name == "ActiveSupport::Cache::MemCacheStore" ||
36
- options[:cache].to_sym == :mem_cache_store)
48
+ options[:cache].to_sym == :mem_cache_store)
37
49
  raise 'ActiveSupport::Cache::MemCacheStore is not supported, as it doesn\'t allow regexp expiry'
38
50
  end
39
51
  if options[:cache_store].is_a?(ActiveSupport::Cache::Store)
@@ -46,18 +58,22 @@ module AMEE
46
58
  @cache = ActiveSupport::Cache.lookup_store(options[:cache].to_sym)
47
59
  end
48
60
  end
49
- # Make connection to server
50
- @http = Net::HTTP.new(@server, @port)
61
+
62
+ # set up hash to pass to builder block
63
+ @params = {
64
+ :ssl => @ssl,
65
+ :params => {},
66
+ :headers => {}
67
+ }
68
+
51
69
  if @ssl == true
52
- @http.use_ssl = true
70
+ @params[:ssl] = true
53
71
  if File.exists? RootCA
54
- @http.ca_file = RootCA
55
- @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
56
- @http.verify_depth = 5
72
+ @params[:ca_file] = RootCA
57
73
  end
58
74
  end
75
+
59
76
  self.timeout = options[:timeout] || 60
60
- @http.set_debug_output($stdout) if options[:enable_debug]
61
77
  @debug = options[:enable_debug]
62
78
  end
63
79
 
@@ -66,13 +82,14 @@ module AMEE
66
82
  attr_reader :username
67
83
  attr_reader :password
68
84
  attr_reader :retries
85
+ attr_accessor :auth_token #Only used in tests really
69
86
 
70
87
  def timeout
71
- @http.read_timeout
88
+ @params[:timeout]
72
89
  end
73
90
 
74
91
  def timeout=(t)
75
- @http.open_timeout = @http.read_timeout = t
92
+ @params[:open_timeout] = @params[:timeout] = t
76
93
  end
77
94
 
78
95
  def version
@@ -84,99 +101,142 @@ module AMEE
84
101
  @username && @password && @server
85
102
  end
86
103
 
104
+ # check if we have a valid authentication token
87
105
  def authenticated?
88
- !@auth_token.nil?
106
+ @auth_token =~ /^.*$/
89
107
  end
90
108
 
109
+ # GET data from the API, passing in a hash of parameters
91
110
  def get(path, data = {})
92
111
  # Allow format override
93
112
  format = data.delete(:format) || @format
94
- # Create URL parameters
95
- params = []
96
- data.each_pair do |key, value|
97
- params << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
98
- end
99
- if params.size > 0
100
- path += "?#{params.join('&')}"
101
- end
102
- # Send request
103
- cache(path) { do_request(Net::HTTP::Get.new(path), format) }
113
+ # Add parameters to URL query string
114
+ get_params = {
115
+ :method => "get",
116
+ :verbose => DEBUG
117
+ }
118
+ get_params[:params] = data unless data.empty?
119
+ # Create GET request
120
+ get = Typhoeus::Request.new("#{protocol}#{@server}#{path}", get_params)
121
+ # Send request
122
+ do_request(get, format, :cache => true)
104
123
  end
105
124
 
125
+ # POST to the AMEE API, passing in a hash of values
106
126
  def post(path, data = {})
107
127
  # Allow format override
108
128
  format = data.delete(:format) || @format
109
129
  # Clear cache
110
130
  expire_matching "#{raw_path(path)}.*"
131
+ # Extract return unit params
132
+ query_params = {}
133
+ query_params[:returnUnit] = data.delete(:returnUnit) if data[:returnUnit]
134
+ query_params[:returnPerUnit] = data.delete(:returnPerUnit) if data[:returnPerUnit]
111
135
  # Create POST request
112
- post = Net::HTTP::Post.new(path)
113
- body = []
114
- data.each_pair do |key, value|
115
- body << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
116
- end
117
- post.body = body.join '&'
136
+ post_params = {
137
+ :verbose => DEBUG,
138
+ :method => "post",
139
+ :body => form_encode(data)
140
+ }
141
+ post_params[:params] = query_params unless query_params.empty?
142
+ post = Typhoeus::Request.new("#{protocol}#{@server}#{path}", post_params)
118
143
  # Send request
119
- do_request(post, format)
144
+ do_request(post, format)
120
145
  end
121
146
 
147
+ # POST to the AMEE API, passing in a string of data
122
148
  def raw_post(path, body, options = {})
123
149
  # Allow format override
124
150
  format = options.delete(:format) || @format
125
151
  # Clear cache
126
152
  expire_matching "#{raw_path(path)}.*"
127
153
  # Create POST request
128
- post = Net::HTTP::Post.new(path)
129
- post['Content-type'] = options[:content_type] || content_type(format)
130
- post.body = body
154
+ post = Typhoeus::Request.new("#{protocol}#{@server}#{path}",
155
+ :verbose => DEBUG,
156
+ :method => "post",
157
+ :body => body,
158
+ :headers => { :'Content-type' => options[:content_type] || content_type(format) }
159
+ )
160
+
131
161
  # Send request
132
162
  do_request(post, format)
133
163
  end
134
164
 
165
+ # PUT to the AMEE API, passing in a hash of data
135
166
  def put(path, data = {})
136
167
  # Allow format override
137
168
  format = data.delete(:format) || @format
138
169
  # Clear cache
139
170
  expire_matching "#{parent_path(path)}.*"
171
+ # Extract return unit params
172
+ query_params = {}
173
+ query_params[:returnUnit] = data.delete(:returnUnit) if data[:returnUnit]
174
+ query_params[:returnPerUnit] = data.delete(:returnPerUnit) if data[:returnPerUnit]
140
175
  # Create PUT request
141
- put = Net::HTTP::Put.new(path)
142
- body = []
143
- data.each_pair do |key, value|
144
- body << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
145
- end
146
- put.body = body.join '&'
147
- # Send request
176
+ put_params = {
177
+ :verbose => DEBUG,
178
+ :method => "put",
179
+ :body => form_encode(data)
180
+ }
181
+ put_params[:params] = query_params unless query_params.empty?
182
+ put = Typhoeus::Request.new("#{protocol}#{@server}#{path}", put_params)
183
+ # Send request
148
184
  do_request(put, format)
149
185
  end
150
186
 
187
+ # PUT to the AMEE API, passing in a string of data
151
188
  def raw_put(path, body, options = {})
152
189
  # Allow format override
153
190
  format = options.delete(:format) || @format
154
191
  # Clear cache
155
192
  expire_matching "#{parent_path(path)}.*"
156
193
  # Create PUT request
157
- put = Net::HTTP::Put.new(path)
158
- put['Content-type'] = options[:content_type] || content_type(format)
159
- put.body = body
194
+ put = Typhoeus::Request.new("#{protocol}#{@server}#{path}",
195
+ :verbose => DEBUG,
196
+ :method => "put",
197
+ :body => body,
198
+ :headers => { :'Content-type' => options[:content_type] || content_type(format) }
199
+ )
160
200
  # Send request
161
201
  do_request(put, format)
162
202
  end
163
203
 
164
204
  def delete(path)
205
+ # Clear cache
165
206
  expire_matching "#{parent_path(path)}.*"
166
207
  # Create DELETE request
167
- delete = Net::HTTP::Delete.new(path)
168
- # Send request
208
+ delete = Typhoeus::Request.new("#{protocol}#{@server}#{path}",
209
+ :verbose => DEBUG,
210
+ :method => "delete"
211
+ )
212
+ # Send request
169
213
  do_request(delete)
170
214
  end
171
215
 
216
+ # Post to the sign in resource on the API, so that all future
217
+ # requests are signed
172
218
  def authenticate
173
- response = nil
174
- post = Net::HTTP::Post.new("/auth/signIn")
175
- post.body = "username=#{@username}&password=#{@password}"
176
- post['Accept'] = content_type(:xml)
177
- post['X-AMEE-Source'] = @amee_source if @amee_source
178
- response = @http.request(post)
179
- @auth_token = response['authToken']
219
+ # :x_amee_source = "X-AMEE-Source".to_sym
220
+ request = Typhoeus::Request.new("#{protocol}#{@server}/auth/signIn",
221
+ :method => "post",
222
+ :verbose => DEBUG,
223
+ :headers => {
224
+ :Accept => content_type(:xml),
225
+ },
226
+ :body => form_encode(:username=>@username, :password=>@password)
227
+ )
228
+
229
+ hydra.queue(request)
230
+ hydra.run
231
+ response = request.response
232
+
233
+ @auth_token = response.headers_hash['AuthToken']
234
+ d {request.url}
235
+ d {response.code}
236
+ d {@auth_token}
237
+
238
+ connection_failed if response.code == 0
239
+
180
240
  unless authenticated?
181
241
  raise AMEE::AuthFailed.new("Authentication failed. Please check your username and password. (tried #{@username},#{@password})")
182
242
  end
@@ -192,6 +252,22 @@ module AMEE
192
252
 
193
253
  protected
194
254
 
255
+ def protocol
256
+ @ssl == true ? 'https://' : 'http://'
257
+ end
258
+
259
+ # Encode a hash into a application/x-www-form-urlencoded format
260
+ def form_encode(data)
261
+ data.map { |datum|
262
+ "#{CGI::escape(datum[0].to_s)}=#{CGI::escape(datum[1].to_s)}"
263
+ }.join('&')
264
+ end
265
+
266
+ ## set up the hydra for running http requests. Increase concurrency as needed
267
+ def hydra
268
+ @hydra ||= Typhoeus::Hydra.new(:max_concurrency => 1)
269
+ end
270
+
195
271
  def content_type(format = @format)
196
272
  case format
197
273
  when :xml
@@ -204,66 +280,104 @@ module AMEE
204
280
  end
205
281
 
206
282
  def redirect?(response)
207
- response.code == '301' || response.code == '302'
283
+ response.code == 301 || response.code == 302
208
284
  end
209
-
285
+
286
+ def connection_failed
287
+ raise AMEE::ConnectionFailed.new("Connection failed. Check server name or network connection.")
288
+ end
289
+
290
+ # run each request through some basic error checking, and
291
+ # if needed log requests
210
292
  def response_ok?(response, request)
211
- case response.code
212
- when '200', '201'
213
- return true
214
- when '404'
215
- raise AMEE::NotFound.new("The URL was not found on the server.\nRequest: #{request.method} #{request.path}")
216
- when '403'
217
- raise AMEE::PermissionDenied.new("You do not have permission to perform the requested operation.\nRequest: #{request.method} #{request.path}\n#{request.body}\Response: #{response.body}")
218
- when '401'
219
- authenticate
220
- return false
221
- when '400'
222
- if response.body.include? "would have resulted in a duplicate resource being created"
223
- raise AMEE::DuplicateResource.new("The specified resource already exists. This is most often caused by creating an item that overlaps another in time.\nRequest: #{request.method} #{request.path}\n#{request.body}\Response: #{response.body}")
224
- else
225
- raise AMEE::BadRequest.new("Bad request. This is probably due to malformed input data.\nRequest: #{request.method} #{request.path}\n#{request.body}\Response: #{response.body}")
226
- end
293
+
294
+ # first allow for debugging
295
+ d {request.object_id}
296
+ d {request}
297
+ d {response.object_id}
298
+ d {response.code}
299
+ d {response.headers_hash}
300
+ d {response.body}
301
+
302
+ case response.code.to_i
303
+
304
+ when 502, 503, 504
305
+ raise AMEE::ConnectionFailed.new("A connection error occurred while talking to AMEE: HTTP response code #{response.code}.\nRequest: #{request.method.upcase} #{request.url.gsub(request.host, '')}")
306
+ when 408
307
+ raise AMEE::TimeOut.new("Request timed out.")
308
+ when 404
309
+ raise AMEE::NotFound.new("The URL was not found on the server.\nRequest: #{request.method.upcase} #{request.url.gsub(request.host, '')}")
310
+ when 403
311
+ raise AMEE::PermissionDenied.new("You do not have permission to perform the requested operation.\nRequest: #{request.method.upcase} #{request.url.gsub(request.host, '')}\n#{request.body}\Response: #{response.body}")
312
+ when 401
313
+ authenticate
314
+ return false
315
+ when 400
316
+ if response.body.include? "would have resulted in a duplicate resource being created"
317
+ raise AMEE::DuplicateResource.new("The specified resource already exists. This is most often caused by creating an item that overlaps another in time.\nRequest: #{request.method.upcase} #{request.url.gsub(request.host, '')}\n#{request.body}\Response: #{response.body}")
318
+ else
319
+ raise AMEE::BadRequest.new("Bad request. This is probably due to malformed input data.\nRequest: #{request.method.upcase} #{request.url.gsub(request.host, '')}\n#{request.body}\Response: #{response.body}")
320
+ end
321
+ when 200, 201, 204
322
+ return response
323
+ when 0
324
+ connection_failed
227
325
  end
228
- raise AMEE::UnknownError.new("An error occurred while talking to AMEE: HTTP response code #{response.code}.\nRequest: #{request.method} #{request.path}\n#{request.body}\Response: #{response.body}")
326
+ # If we get here, something unhandled has happened, so raise an unknown error.
327
+ raise AMEE::UnknownError.new("An error occurred while talking to AMEE: HTTP response code #{response.code}.\nRequest: #{request.method.upcase} #{request.url}\n#{request.body}\Response: #{response.body}")
229
328
  end
230
329
 
231
- def do_request(request, format = @format)
232
- # Open HTTP connection
233
- @http.start
234
- begin
235
- # Set auth token in cookie (and header just in case someone's stripping cookies)
236
- request['Cookie'] = "authToken=#{@auth_token}"
237
- request['authToken'] = @auth_token
238
- # Do request
239
- timethen=Time.now
240
- response = send_request(@http, request, format)
241
- Logger.log.debug("Requesting #{request.class} at #{request.path} with #{request.body} in format #{format}, taking #{(Time.now-timethen)*1000} miliseconds")
242
- end while !response_ok?(response, request)
243
- # Return response
244
- return response
245
- rescue SocketError
246
- raise AMEE::ConnectionFailed.new("Connection failed. Check server name or network connection.")
247
- ensure
248
- # Close HTTP connection
249
- @http.finish if @http.started?
250
- end
330
+ # Wrapper for sending requests through to the API.
331
+ # Takes care of making sure requests authenticated, and
332
+ # if set, attempts to retry a number of times set when
333
+ # initialising the class
334
+ def do_request(request, format = @format, options = {})
335
+
336
+ # Is this a v3 request?
337
+ v3_request = request.url.include?("/#{v3_hostname}/")
251
338
 
252
- def send_request(connection, request, format = @format)
253
- # Set accept header
254
- request['Accept'] = content_type(format)
339
+ # make sure we have our auth token before we start
340
+ # any v1 or v2 requests
341
+ if !@auth_token && !v3_request
342
+ d "Authenticating first before we hit #{request.url}"
343
+ authenticate
344
+ end
345
+
346
+ request.headers['Accept'] = content_type(format)
255
347
  # Set AMEE source header if set
256
- request['X-AMEE-Source'] = @amee_source if @amee_source
257
- # Do the business
348
+ request.headers['X-AMEE-Source'] = @amee_source if @amee_source
349
+
350
+ # path+query string only (split with an int limits the number of splits)
351
+ path_and_query = '/' + request.url.split('/', 4)[3]
352
+
353
+ if options[:cache]
354
+ # Get response with caching
355
+ response = cache(path_and_query) { run_request(request, :xml) }
356
+ else
357
+ response = run_request(request, :xml)
358
+ end
359
+ response
360
+ end
361
+
362
+ # run request. Extracted from do_request to make
363
+ # cache code simpler
364
+ def run_request(request, format)
365
+ # Is this a v3 request?
366
+ v3_request = request.url.include?("/#{v3_hostname}/")
367
+ # Execute with retries
258
368
  retries = [1] * @retries
259
- begin
260
- response = connection.request(request)
261
- # 500-series errors fail early
262
- if ['502', '503', '504'].include? response.code
263
- raise AMEE::ConnectionFailed.new("A connection error occurred while talking to AMEE: HTTP response code #{response.code}.\nRequest: #{request.method} #{request.path}")
264
- end
265
- rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
266
- Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, AMEE::ConnectionFailed => e
369
+ begin
370
+ begin
371
+ d "Queuing the request for #{request.url}"
372
+ add_authentication_to(request) if @auth_token && !v3_request
373
+ hydra.queue request
374
+ hydra.run
375
+ # Return response if OK
376
+ end while !response_ok?(request.response, request)
377
+ # Store updated authToken
378
+ @auth_token = request.response.headers_hash['AuthToken']
379
+ return request.response
380
+ rescue AMEE::ConnectionFailed, AMEE::TimeOut => e
267
381
  if delay = retries.shift
268
382
  sleep delay
269
383
  retry
@@ -271,17 +385,27 @@ module AMEE
271
385
  raise
272
386
  end
273
387
  end
274
- # Done
275
- response
388
+ end
389
+
390
+ # Take an existing request, and add authentication
391
+ # may no longer be needed now that we authenticate before
392
+ # making a request anyway
393
+ def add_authentication_to(request=nil)
394
+ if @auth_token
395
+ request.headers['Cookie'] = "AuthToken=#{@auth_token}"
396
+ request.headers['AuthToken'] = @auth_token
397
+ else
398
+ raise "The connection can't authenticate. Check if the auth_token is being set by the server"
399
+ end
276
400
  end
277
401
 
278
402
  def cache(path, &block)
279
403
  key = cache_key(path)
280
404
  if @cache && @cache.exist?(key)
281
- puts "CACHE HIT on #{key}" if @debug
405
+ d "CACHE HIT on #{key}" if @debug
282
406
  return @cache.read(key)
283
407
  end
284
- puts "CACHE MISS on #{key}" if @debug
408
+ d "CACHE MISS on #{key}" if @debug
285
409
  data = block.call
286
410
  @cache.write(key, data) if @cache
287
411
  return data
@@ -298,8 +422,8 @@ module AMEE
298
422
  def cache_key(path)
299
423
  # We have to make sure cache keys don't get too long for the filesystem,
300
424
  # so we cut them off if they're too long and add a digest for uniqueness.
301
- newpath = @server + path.gsub(/[^0-9a-z\/]/i, '').gsub(/\//i, '_')
302
- newpath = (newpath.length < 250) ? newpath : newpath.first(218)+Digest::MD5.hexdigest(newpath)
425
+ key = @server + path.gsub(/[^0-9a-z\/]/i, '').gsub(/\//i, '_')
426
+ key = (key.length < 250) ? key : key.first(218)+Digest::MD5.hexdigest(key)
303
427
  end
304
428
 
305
429
  public