3
\$\begingroup\$

The following logic:

Iterate over the URLs array and If the HTTP request with the given URL does not timeout, continue. If the URL times out, remove it from the array and continue with the next one until the array is exhausted.

Has been implemented in the following way:

@urls.delete_if do |url|
 begin
 doc = perform_request(some_params)
 break
 rescue TimeoutError
 Rails.logger.warn("URL #{url} times out, will be removed from list")
 true
 end
end

Anyone for a cleaner solution? Basically, I want to iterate over an array and remove elements from it if there is a timeout, but if the URL works loop should end and app should continue processing.

Nakilon
1,3387 silver badges17 bronze badges
asked Jan 4, 2013 at 15:23
\$\endgroup\$
3
  • \$\begingroup\$ Specifically, hate the break in there - maybe someone can propose a cleaner solution. \$\endgroup\$ Commented Jan 4, 2013 at 15:23
  • \$\begingroup\$ Btw "true" in the rescue can be removed, not needed. \$\endgroup\$ Commented Jan 4, 2013 at 15:33
  • \$\begingroup\$ if not needed just edit the question! I have a doubt, why do you want to modify inplace @urls? wouldn't do a functional solution? \$\endgroup\$ Commented Jan 4, 2013 at 17:57

3 Answers 3

3
\$\begingroup\$

note : your break is useless, because if the block returns a falsey value, the url is kept.

Maybe it can just be a bit more expressive ?

def timeouts?( url )
 perform_request( url ) && false 
rescue TimeoutError
 true
end
@urls.delete_if {|url| timeouts?( url ) }

You could even make timeouts? a method on your @urls objects, for extra readability :

@urls.delete_if( &:timeouts? )

if you want to keep @tokland's functionnal approach, just use :

@kept_urls = @urls.reject{|url| timeouts?( url ) }

however, it would not be fully "functionnal", because timeouts may not return the same results with the same arguments, depending on the execution environment.

answered Jun 6, 2013 at 13:23
\$\endgroup\$
1
  • \$\begingroup\$ Maybe calling the function timesout? instead of timeouts? would semantically be better. \$\endgroup\$ Commented Jan 26, 2020 at 10:03
0
\$\begingroup\$

You may use drop_while to get rid of iterative operator break:

@urls = @urls.drop_while do |url|
 begin
 doc = perform_request(some_params)
 false
 rescue TimeoutError
 Rails.logger.warn("URL #{url} times out, will be removed from list")
 true
 end
end
answered Jan 4, 2013 at 20:01
\$\endgroup\$
1
  • \$\begingroup\$ the problem is doc won't be visible outside the block's scope. \$\endgroup\$ Commented Jan 4, 2013 at 21:23
0
\$\begingroup\$

I'd take a functional approach (no in-place updates):

url, doc = @urls.map_detect do |url|
 begin
 [url, perform_request(some_params)]
 rescue TimeoutError
 Rails.logger.warn("URL #{url} timed out")
 false
 end
end

This snippet uses the custom abstraction Enumerable#map_detect (see also Facets)

You can then use url to update @urls, but it's better not to mix the algorithm (even if it's so simple) with the updates required by the app.

answered Jan 4, 2013 at 18:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.