Background: I need to determine the number of records in a remote location. The records are sequentially numbered (starting at 0
, no gaps) and can only be fetched one by one based on their number.
The method to fetch the records over the network returns a truthy value upon success and a falsey value upon failure. Here'a an example:
fetch_record(0) #=> true (record #0 exists)
fetch_record(1) #=> true (record #1 exists)
fetch_record(2) #=> true (record #2 exists)
fetch_record(3) #=> nil (no record #3)
I'm trying to find an elegant way to count how many times I can call fetch_record
with increasing argument until it returns nil
(3 times in the above example).
What I've tried so far
Given this simplified implementation for testing purposes:
def fetch_record(index)
raise if index > 3 # just to prevent endless loops
true if index < 3
end
Here are my attempts:
A while
loop with an explicit counter variable would obviously work, but I doesn't look very idiomatic:
i = 0
i += 1 while fetch_record(i)
i
#=> 3
I could use step
and break
with an explicit result value but that looks cumbersome:
0.step(by: 1).each { |i| break i unless fetch_record(i) }
#=> 3
A lazy enumerator is even worse:
0.step(by: 1).lazy.map { |i| fetch_record(i) }.take_while(&:itself).count
#=> 3
Is there an easier way to accomplish the above?
Assuming you are free to implement fetch_record
the other way round, to return true
for inexisting record:
def fetch_record index
index >= 3
end
(0..Float::INFINITY).detect &method(:fetch_record)
#⇒ 3
take_while anyone?
records = 0.step.take_while{|i| fetch_record(i)}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With