I encountered the following Ruby code:
class MyClass attr_accessor :items ... def each @items.each{|item| yield item} end ... end What does the each method do? In particular, I don't understand what yield does.
yield is a keyword in Ruby which allow the developer to pass some argument to block from the yield, the number of the argument passed to the block has no limitations, the main advantage of using yield in Ruby, if we face any situation we wanted to our method perform different functions according to calling block, which ...
We can also pass multiple arguments in a block. If we want to call a block multiple times, we can pass it to our method by sending a proc or lamda. But yield is more convenient and quicker in Rails 6 for the same task. Note: yield allows us to inject blocks into a function at any point.
The do keyword comes into play when defining an argument for a multi-line Ruby block. Ruby blocks are anonymous functions that are enclosed in a do-end statement or curly braces {} . Usually, they are enclosed in a do-end statement if the block spans through multiple lines and {} if it's a single line block.
The &block is a way of sending a piece of Ruby code in to a method and then evaluating that code in the scope of that method. In your example code above it means a partial named cart will be rendered in a div.
This is an example fleshing out your sample code:
class MyClass attr_accessor :items def initialize(ary=[]) @items = ary end def each @items.each do |item| yield item end end end my_class = MyClass.new(%w[a b c d]) my_class.each do |y| puts y end # >> a # >> b # >> c # >> d each loops over a collection. In this case it's looping over each item in the @items array, initialized/created when I did the new(%w[a b c d]) statement.
yield item in the MyClass.each method passes item to the block attached to my_class.each. The item being yielded is assigned to the local y.
Does that help?
Now, here's a bit more about how each works. Using the same class definition, here's some code:
my_class = MyClass.new(%w[a b c d]) # This points to the `each` Enumerator/method of the @items array in your instance via # the accessor you defined, not the method "each" you've defined. my_class_iterator = my_class.items.each # => #<Enumerator: ["a", "b", "c", "d"]:each> # get the next item on the array my_class_iterator.next # => "a" # get the next item on the array my_class_iterator.next # => "b" # get the next item on the array my_class_iterator.next # => "c" # get the next item on the array my_class_iterator.next # => "d" # get the next item on the array my_class_iterator.next # => # ~> -:21:in `next': iteration reached an end (StopIteration) # ~> from -:21:in `<main>' Notice that on the last next the iterator fell off the end of the array. This is the potential pitfall for NOT using a block because if you don't know how many elements are in the array you can ask for too many items and get an exception.
Using each with a block will iterate over the @items receiver and stop when it reaches the last item, avoiding the error, and keeping things nice and clean.
When you write a method that takes a block, you can use the yield keyword to execute the block.
As an example, each could have been implemented in the Array class like this:
class Array def each i = 0 while i < self.size yield( self[i] ) i = i + 1 end end end MyClass#each takes a block. It executes that block once for each item in the instance's items array, passing the current item as an argument.
It might be used like this:
instance = MyClass.new instance.items = [1, 2, 3, 4, 5] instance.each do |item| puts item end
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