Yield
Tags: beginners, ruby, methods
Published: 2020-11-10 21:10:30

#Intro

Of the many things I take for granted as a beginner Rubyist, I think the concept I've taken for granted the most is **code blocks**, and the keyword `yield`.  I assumed that `do` and `end` were just inherent parts of enumerables, conditional statements, and forms.  

The truth is, we can take advantage of these code blocks in our own methods, and access them with the keyword `yield`.

##What is ***yield***?

`yield` is a built-in Ruby *keyword*.  A list of all Ruby keywords can be found [here](https://docs.ruby-lang.org/en/2.2.0/keywords_rdoc.html).  

When `yield` is interpreted, it begins the execution of the code-block that directly succeeds the method:

```Ruby
def execute_block
   yield
end

execute_block { puts "Hello" } 
"Hello"
#=> nil

execute_block do
   2 + 2
end 
#=> 4
```

In the above example, we have a method that simply executes the code block it is given.  When the `yield` keyword is hit, the method is paused, and the block is ran.  The result of the block gets returned to the method, and execution can continue.

Now that we've seen the basic idea of blocks & `yield`, let's look at some cool implementation.

### Performance testing

A common use for a custom `yield` method is when performance testing a method or block of code.
```Ruby
def speedtest
    t1 = Time.now
    result = yield
    t2 = Time.now
    puts t2 - t1
    result
end
```
This method will take a time-stamp before and after the execution of a block.  It will take the difference of those times to find the runtime, then return the result of the code-block.
```Ruby
speedtest { 1 + 1 }
1.0e-06
=> 2

speedtest { [1, 1].reduce(:+) }
3.0e-06
=> 2
```

### Customized Conditional-flow

Let's make our own conditional flow:

```Ruby
def allow_if_true(method, false_message)
    return false_message unless yield
    method
end
```
With this method, we limit the execution of `method`, so that it only runs if the given block returns `true`.

```Ruby
allow_if_true(top_secret_internet_stuff, "Access Denied") do
   session[:username] == "Bill Gates"
end
```
Now, we can successfully keep safe all of the internet's deep dark secrets.  Take **that** hackers!

### What about enumerating?

Fun fact: We can pass parameters to our `yield`!  Let's take a look at how we can use that by making our own **each**-like enumerator:

```Ruby
def do_stuff_to(arr)
   return "not an array!" unless arr.class == Array
   count = 0
   while count < arr.length
      yield arr[count]
      count += 1
   end
   arr
end
```
With this simple implementation, we
1. First assure we have the right data-type with `unless`
2. Iterate over the array with a `while` loop & `count`
3. Display the original array at the end.
```Ruby
do_stuff_to([1, 2, 3]) do |i|
   puts i ** 2
end
1
4
9
#=> [1, 2, 3]
```
Did you notice the `|i|`?  When we pass a value to yield, we denote it's presence by declaring it in pipe-notation in the block.  Just like our built-in enumerable methods, we have a parameter for each value passed to the yield.

### Closing

To be completely honest, at this point I don't know how useful a custom `yield` method will be to your day-to-day development.  But at the very least, I hope this helps de-mystify this concept to you, and that you'll be more comfortable knowing what goes on when you see these come up.

Cheers!