call next on ruby loop from external method - ruby

in Ruby it's easy to tell loop to go to next item
(1..10).each do |a|
next if a.even?
puts a
end
result =>
1
3
5
7
9
but what if I need to call next from outside of the loop (e.g.: method)
def my_complex_method(item)
next if item.even? # this will obviously fail
end
(1..10).each do |a|
my_complex_method(a)
puts a
end
only solution I found and works is to use throw & catch like in SO question How to break outer cycle in Ruby?
def my_complex_method(item)
throw(:skip) if item.even?
end
(1..10).each do |a|
catch(:skip) do
my_complex_method(a)
puts a
end
end
My question is: anyone got any more niftier solution to do this ?? or is throw/catch only way to do this ??
Also what If I want to call my_complex_method not only as a part of that loop (=> don't throw :skip) , can I somehow tell my method it's called from a loop ?

You complex method could return a boolean, and then you compare on your loop like this:
def my_complex_method(item)
true if item.even?
end
(1..10).each do |a|
next if my_complex_method(a)
puts a
end
A simple approach, but different from the try catch one.
UPDATE
As item.even? already return a boolean value, you don't need the true if item.even? part, you can do as follow:
def my_complex_method(item)
item.even?
end

Enumerator#next and Enumerator#peek will be good option to goo :
def my_complex_method(e)
return if e.peek.even?
p e.peek
end
enum = (1..5).each
enum.size.times do |a|
my_complex_method(enum)
enum.next
end
Output
1
3
5

If all you need is to take actions on only some of values, based on value returned by my_complex_method you could use enumerators wisely:
(1..10).map { |a| [a, my_complex_method(a)] }.each do |a, success|
puts a if success
end
You could define method accepting block and take some action in this block based on success or failure there:
(1..10).each do |a|
my_complex_method { |success| next if success }
end
Thanks to scoping, you are able not to use `catch`/`throw`, and call `next` based on processing status.

Related

How to modify an iterator while iterating over an array

I want to skip a loop x times according to a condition that is determined at runtime. How can I do this?
for i in (0..5)
if i==0
3.times {next} # i=i+3 also doesnt work
end
puts i
end
Expect to output
3
4
5
EDIT:
To clarify, the question is both the condition (ie i==0) and skipping x times iteration are determined dynamically at runtime, more convoluted example:
condition = Array.new(rand(1..100)).map{|el| rand(1..10000)} #edge cases will bug out
condition.uniq!
for i in (0..10000)
if condition.include? i
rand(1..10).times {next} # will not work
end
puts i
end
simple method to skip by a defined multiple.
array_list = (0..5).to_a
# Use a separate enum object to hold index position
enum = array_list.each
multiple = 3
array_list.each do |value|
if value.zero?
multiple.times { enum.next }
end
begin puts enum.next rescue StopIteration end
end

Self enumerating function

I've got some code:
def my_each_with_index
return enum_for(:my_each_with_index) unless block_given?
i = 0
self.my_each do |x|
yield x, i
i += 1
end
self
end
It is my own code, but the line:
return enum_for(:my_each_with_index) unless block_given?
is found in solutions of other's. I can't get why they passed the function to enum_for as a parameter. When I invoke my function without a block, it won't return anything with or without enum_for. I could left sth like:
return unless block_given?
and it has the same result. Or am I wrong?
Being called without a block, it will return an enumerator:
▶ def my_each_with_index
▷ return enum_for(:my_each_with_index) unless block_given?
▷ end
#⇒ :my_each_with_index
▶ e = my_each_with_index
#⇒ #<Enumerator: main:my_each_with_index>
later on you might iterate on this enumerator:
▶ e.each { |elem| ... }
This behavior is specifically useful in some cases, like lazy iteration, passing block to this enumerator later etc.
Just returning nil cuts this ability off.
Think you for very precise answer. I recived also very good example to understand this issue for other new developers:
def iterator
yield 1
yield 2
yield 3
puts "koniec"
end
iterator { |v| puts v }
it = enum_for(:iterator)
puts it.next
puts it.next
puts it.next
puts it.next
Just run and analyze this code.
For any method that accepts a block, a good method implementation should have a well-defined behavior when the block is not given.
In the example shared by you, each_for_index is being re-implemented by author, may be to provide additional semantics or may be just for academic purpose given that its behavior is same as Ruby's Enumerable#each_with_index.
The documentation has following for Enumerable#each_with_index.
Calls block with two arguments, the item and its index, for each item
in enum. Given arguments are passed through to each().
If no block is given, an enumerator is returned instead.
In order to stay consistent with highlighted line indicating what should be the behavior if block is not given, one has to use something like
return enum_for(:my_each_with_index) unless block_given?
enum_for is interesting method
enum_for creates a new Enumerator which will enumerate by calling method on obj.
Below is an example reproduced from documentation:
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
So, if one does not pass block to my_each_with_index, they have a chance to pass it later - just like one would have done with each_with_index.
e = obj.my_each_with_index
...
e.each { |x, i| # do something } # `my_each_with_index` executed later
In summary, my_each_with_index tries to be consistent with each_with_index and tries to be a well-behaved API.

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Ruby StringScanner used for lexing : how to get the line number?

I am using StringScanner for lexical analysis like this :
def next
#scanner.skip(/\s+/)
value,kind=nil,nil
TOKEN_DEF.each{|tok,regex| (kind=tok;break) if #scanner.scan(regex)}
return Token.new(kind,value,#line,#scanner.pos)
end
At first approximation, this works well, except that I can't figure out how to now get the #line number.
I have read the doc, where begin_of_line? method seems appropriate, but I cannot figure how to use it.
Keep the text that you are scanning in a variable and use 'count'
I use the following in my code:
def current_line_number; #text[0..#scanner.pos].count("\n") + 1; end
This code doesn't seem ready to go and for sure somewhere else more elegant solution, it just should give you something to think about.
class Retry < StandardError
end
class TextScanner
def initialize(filename)
#lines = IO.readlines(filename)
#fiber = Fiber.new do
#lines.each_with_index do |line, index|
#scanner = StringScanner.new(line)
#scanner.skip(/\s+/)
value, kind = nil, nil
begin
got_token = false
TOKEN_DEF.each do |tok, regex|
if #scanner.scan(regex)
Fiber.yield Token.new(tok, value, index, #scanner.pos)
got_token = true
end
end
raise Retry if got_token
rescue Retry
retry
end
end
"fiber is finished"
end
end
def next
#fiber.resume
end
end
text_scanner = TextScanner('sometextfile')
puts text_scanner.next #=> first token
puts text_scanner.next #=> second token
puts text_scanner.next #=> third token
...
puts text_scanner.next #=> "fiber is finished"
I think I have a simple solution. Here it is :
def next
#line+=1 while #scanner.skip(/\n/)
#line+=1 if #scanner.bol?
#scanner.skip(/\s+/)
#line+=1 if #scanner.bol?
#scanner.skip(/\s+/)
return :eof if #scanner.eos?
TOKEN_DEF.each { |tok,syntax| (kind=tok;break) if #scanner.scan(syntax)}
return Token.new(kind,nil,#line,#scanner.pos)
end

Ruby passing blocks to blocks

(1..5).each do|x| puts yield(x) end do |x| return x*2 end
In my head this would loop 1 through 5 call the first block that would yield to the second block and put 2,4,6,8,10
Why does this not work and whats the easiest way to write this.
yield works within the methods. Quote from "Programming Ruby":
Within the method, the block may be invoked, almost as if it were a
method itself, using the yield statement.
So, if you want to make this code working, you can change it to something like this:
def f(n)
(1..n).each do |x|
puts yield(x)
end
end
f(5) do |x|
x * 2
end
If you don't want to define method you should put block into the variable and then use it:
b = Proc.new{|x| x *2 }
(1..5).each do |x|
puts b.call(x)
end
The easiest way to write this:
(1..5).each { |x| puts x*2 }

Resources