views:

1201

answers:

3
class Bar   
  def do_things
      Foo.some_method(x) do |x|
            y = x.do_somethign
            return y_is_bad if y.bad? # how do i tell it to stop and return do_things? 
            y.do_something_else
      end
      keep_doing_more_things
  end
end

here is Foo#some_method.

class Foo
    def self.some_method(targets, &block)
      targets.each do |target|
        begin
          r = yield(target)
        rescue 
         failed << target
        end
     end
   end
end

thought about using raise, but I am trying to make it generic, so i don't want to put anything any specific in Foo

+8  A: 

Use the keyword next.

Edit: If you do not want to continue to the next item, use break.

Usage of next in a block: When next is used within a block, it causes the block to exit immediately, returning control to the iterator method, which may then begin a new iteration by invoking the block again:

f.each do |line|              # Iterate over the lines in file f
  next if line[0,1] == "#"    # If this line is a comment, go to the next
  puts eval(line)
  # Control goes here when the next statement is executed
end

Usage of break in a block: When used in a block, break transfers control out of the block, out of the iterator that invoked the block, and to the first expression following the invocation of the iterator:

f.each do |line|             # Iterate over the lines in file f
  break if line == "quit\n"  # If this break statement is executed...
  puts eval(line)
end
puts "Good bye"              # ...then control is transferred here

And finally, usage of return in a block: Return always causes the enclosing method to return, regardless of how deeply nested within blocks it is (except in the case of lambdas):

def find(array, target)
  array.each_with_index do |element,index|
    return index if (element == target)  # return from find
  end
  nil  # If we didn't find the element, return nil
end
JRL
thanks, but next only moves to the next item in the array. is it possible to exit?
You have to call next with the return value."def f; x = yield; puts x; end""f do next 3; puts "o"; end"This prints 3 (but no "o") on the console.
Marcel J.
+1  A: 

use the keyword break instead of return

AShelly
thanks, nope, that does not work neither.
how does that not work?
AShelly
A: 

Perhaps you can use the built-in methods for finding particular items in an Array, instead of each-ing targets and doing everything by hand. A few examples:

class Array
  def first_frog
    detect {|i| i =~ /frog/ }
  end

  def last_frog
    select {|i| i =~ /frog/ }.last
  end
end

p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"

One example would be doing something like this:

class Bar
  def do_things
    Foo.some_method(x) do |i|
      # only valid `targets` here, yay.
    end
  end
end

class Foo
  def self.failed
    @failed ||= []
  end

  def self.some_method(targets, &block)
    targets.reject {|t| t.do_something.bad? }.each(&block)
  end
end
August Lilleaas