This question already has answers here:
Why does Ruby use yield?
(4 answers)
Closed 9 years ago.
# Get our data back
def queryNewsTable
#conn.exec( "SELECT * FROM newslib" ) do |result|
result.each do |row|
yield row if block_given?
end
end
end
For this piece of code. I don't quite understand yield row if block_given?
can anybody point to any good article teaching about this or you can briefly explain it to me a little bit
thanks so much
This yield row if block_given? means that block which could be passed into the #queryNewsTable method(!), is evaluated with yield operator, in other words, if you pass the block into function #queryNewsTable:
queryNewsTable do
#some code
end
You will get the call to the code, for each of rows in the result variable.
NOTE: That for your case it will be better to optimize the code (if not dbtrigger is used):
# Get our data back
def queryNewsTable
#conn.exec( "SELECT * FROM newslib" ) do |result|
result.each do |row|
yield row
end
end if block_given?
end
Ask yourself how Hash.new works:
http://www.ruby-doc.org/core-2.1.0/Hash.html#method-c-new
It can take no argument, a single argument, or a block. If there is no argument, fetching the value for a non-existent key gives nil. If there is a block, fetching the value for a non-existent key gives whatever the block says to give. Clearly its implementation needs a way to ask "was there a block?" so that it knows which behavior to use. That is what block_given? does.
http://www.ruby-doc.org/core-2.1.0/Kernel.html#method-i-block_given-3F
As for yield, it is simply the way a method that has taken a block calls the block, passing it parameters as needed.
When you use functions like Enumerable#each, you typically pass in a block using {|arg| ... } or do ... end. The line yield row if block_given? checks to see if a block was supplied to this function call, and if it was, calls that block with row as an argument.
One way you might use this function would be:
queryNewsTable {|row| puts row}
This example would print each row of the query to standard output, since the block that does the printing gets called for each row in the query result. If no block were given, then that line would be ignored.
Related
I am learning Ruby, and for no particular reason, I want to pass the yield object to the Integer#times method so that the yield code block is called a number of times. Here is how I can do it with a named code block:
def withNamedCodeBlock &b
3.times(&b)
end
withNamedCodeBlock {print "Go "}
#returns Go Go Go
Now, I want to do the same, but without named code blocks; I want to do it with by using the yield keyword. Here is how I tried and failed:
def withYield
3.times(&yield)
end
withYield {print "Go "}
#returns Go => #<Enumerator: 3:times>
#I expect it to return Go Go Go
I am still wrapping my head around the various ways to pass code blocks to methods, so additional information regarding that is appreciated.
I want to pass the yield object to the Integer#times method so that the yield code block is called a number of times
yield is not an object, nor is it a block. It's not even a method call. It's a keyword that yields control to a passed block. If you want to do anything else with the block (save it for later, pass it around, etc.), you must name it.
For sake of completeness on this topic, I wanted to demonstrate another technique to call the original block:
def withProc
p = Proc.new
3.times(&p)
end
withProc { print "Go" }
When Proc.new is not given a block, it uses the block that was given to withProc instead. Now you can call p, and it will call the original block. You can also pass p to other methods like times either as a regular argument or as a block argument.
See https://medium.com/#amliving/proc-new-trick-c1df16185599 for more discussion
#sergio-tulentsev's answer is good. But, I wanted to point out that you can wrap yield in a new block and thereby pass along the ability to yield to the original block:
def withYield
3.times { yield }
end
withYield {print "Go "}
To be clear, { yield } is a new block, and it is passed to times. When the new block is executed, it yields to the original { print "Go" } block that was given to withYield. The original block isn't actually passed to times, but the ability to yield to the original block is passed, effectively letting you call the original block.
This question already has an answer here:
Ruby block and unparenthesized arguments
(1 answer)
Closed 7 years ago.
Jokes aside, I have a strange situation, I have some code:
def remotes(form,remotes)
personalised_form = form.dup
remotes.each do |ident,remote|
object = yield(ident)
result = remote.call(object)
insert_into_(personalised_form,ident,result)
end
personalised_form
end
And I'm seeing if it works like so:
pp remotes(forms,remotes) do |ident|
case(ident)
when :get_assets
'#Userobject'
end
end
The problem is that ruby seems to think I'm not passing a block to the remotes function.
Why is ruby insisting that I'm not passing a block? (it gives a no block given (yield) (LocalJumpError) specifically).
Thought it's not relevant, remotes is a hash containing key's and Procs, and form is just a specificly structured hash that has the result of the proc inserted into it using the ident to locate the correct insertion point
Ruby thinks you are passing the block to pp method, which simply ignores it. Try:
res = remotes(forms,remotes) do |ident|
case(ident)
when :get_assets
'#Userobject'
end
end
pp res
Is there a keyword I can use to explicitly tell the map function what the result of that particular iteration should be?
Consider:
a = [1,2,3,4,5]
a.map do |element|
element.to_s
end
In the above example element.to_s is implicitly the result of each iteration.
There are some situations where I don't want to rely on using the last executed line as the result, I would prefer to explicitly say what the result is in code.
For example,
a = [1,2,3,4,5]
a.map do |element|
if some_condition
element.to_s
else
element.to_f
end
end
Might be easier for me to read if it was written like:
a = [1,2,3,4,5]
a.map do |element|
if some_condition
result_is element.to_s
else
result_is element.to_f
end
end
So is there a keyword I can use in place of result_is?
return will return from the calling function, and break will stop the iteration early, so neither of those is what I'm looking for.
The last thing left on the stack is automatically the result of a block being called. You're correct that return would not have the desired effect here, but overlook another possibility: Declaring a separate function to evaluate the entries.
For example, a reworking of your code:
def function(element)
if (some_condition)
return element.to_s
end
element.to_f
end
a.map do |element|
function(element)
end
There is a nominal amount of overhead on calling the function, but on small lists it should not be an issue. If this is highly performance sensitive, you will want to do it the hard way.
Yes, there is, it's called next. However, using next in this particular case will not improve readability. On the contrary, it will a) confuse the reader and b) give him the impression that the author of that code doesn't understand Ruby.
The fact that everything is an expression in Ruby (there are no statements) and that every expression evaluates to the value of the last sub-expression in that expression are fundamental Ruby knowledge.
Just like return, next should only be used when you want to "return" from the middle of a block. Usually, you only use it as a guard clause.
The nature of map is to assign the last executed line to the array. Your last example is very similar to the following, which follows the expected behavior:
a = [1,2,3,4,5]
a.map do |element|
result = if some_condition
element.to_s
else
element.to_f
end
result
end
No, there is no language keyword in ruby you can use to determine the result mapped into the resulting array before executing other code within the iteration.
You may assign a variable which you then return when some other code has been executed:
a.map do |element|
result = some_condition ? element.to_s : element.to_f
#do something else with element
result
end
Keep in mind the reason for ruby not providing a keyword for this kind of code is that these patterns tend to have a really low readability.
I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.
I have a method that accepts a block, lets call it outer. It in turn calls a method that accepts another block, call it inner.
What I would like to have happen is for outer to call inner, passing it a new block which calls the first block.
Here's a concrete example:
class Array
def delete_if_index
self.each_with_index { |element, i| ** A function that removes the element from the array if the block passed to delete_if_index is true }
end
end
['a','b','c','d'].delete_if_index { |i| i.even? }
=> ['b','d']
the block passed to delete_if_index is called by the block passed to each_with_index.
Is this possible in Ruby, and, more broadly, how much access do we have to the block within the function that receives it?
You can wrap a block in another block:
def outer(&block)
if some_condition_is_true
wrapper = lambda {
p 'Do something crazy in this wrapper'
block.call # original block
}
inner(&wrapper)
else
inner(&passed_block)
end
end
def inner(&block)
p 'inner called'
yield
end
outer do
p 'inside block'
sleep 1
end
I'd say opening up an existing block and changing its contents is Doing it WrongTM, maybe continuation-passing would help here? I'd also be wary of passing around blocks with side-effects; I try and keep lambdas deterministic and have actions like deleting stuff in the method body. In a complex application this will likely make debugging a lot easier.
Maybe the example is poorly chosen, but your concrete example is the same as:
[1,2,3,4].reject &:even?
Opening up and modifying a block strikes me as code smell. It'd be difficult to write it in a way that makes the side effects obvious.
Given your example, I think a combination of higher order functions will do what you're looking to solve.
Update: It's not the same, as pointed out in the comments. [1,2,3,4].reject(&:even?) looks at the contents, not the index (and returns [1,3], not [2,4] as it would in the question). The one below is equivalent to the original example, but isn't vary pretty.
[1,2,3,4].each_with_index.reject {|element, index| index.even? }.map(&:first)
So here's a solution to my own question. The passed in block is implicitly converted into a proc which can be received with the & parameter syntax. The proc then exists inside the closure of any nested block, as it is assigned to a local variable in scope, and can be called by it:
class Array
def delete_if_index(&proc)
ary = []
self.each_with_index { |a, i| ary << self[i] unless proc.call(i) }
ary
end
end
[0,1,2,3,4,5,6,7,8,9,10].delete_if_index {|index| index.even?}
=> [1, 3, 5, 7, 9]
Here the block is converted into a proc, and assigned to the variable proc, which is then available within the block passed to each_with_index.