 I'm Michael Hartle from Softcover, a self-publishing platform and the Ruby Unreal tutorial. And I'm here to tell you about innumerable for fun and profit. Let's get started here. So this is a range, 1 up to 10. And I just have the dot class there to show what it is. And say you wanted to print out the squares of those numbers 1 up to 10. You could do this. You could do 1 up to 10. Each do n and then put s n squared. Arrays, also, you can iterate through them. Say you want to just print out reversed versions of all the words. Here's a hash. If you wanted to iterate over these, you could have hash dot each do p value and then print out the name and email. Or you could, say, go through all of the users, which is in a Rails application. This is an active record relation. User dot all dot each, and this would reverse all the names in the database if you wanted to do that. So what's the theme here? You can notice that every one of these is doing the same basic thing. It's calling in each method on the particular object. So this is the way that Ruby does iteration, is you have an each method inside of a class. And as long as you've got that, something that returns the next element in the collection, you can get all kinds of amazing magic if you include the innumerable module. So that's what we're going to be talking about the rest of this talk is, what does that give you? If you include innumerable, what sorts of things can you do? And this is where we're going to start off with this. You're not expected to understand this. This is horrendous. This is a method that returns the first n prime numbers. So given, say, the number three, it would return 235. And it's a total disaster, but you can see right at the heart of it there, in fact, is an each call. So innumerable will let us make this rather significantly simpler. This thing is not counting down from 45. I was told to press. And now it's, all right, yeah. I'll just keep track of it on my own. All right, so the people on that side aren't going to be able to see me very well. Let me move over a little bit. This is far as it goes, I think. Yeah. Is that legible? Is it big enough to see? Is the font size big enough? Great. It's kind of a weird aspect ratio, though, isn't it? I can go do a different color scheme, I guess. Is that more readable? All right, cool. So I've got here a class, RubyConf, for the purposes of illustration. So let's write a method. This is the kind of thing you might want to do. You might want to return the first n elements of a collection. And we'll just take an argument there. So how might you do this? You're given a collection, and you want to return the first n elements in that collection. Well, you might be tempted to do something like this. You can say, start introducing a counter and have a return value that's an array. And then, oh, I'm sorry, this takes in also a collection. So let's call it enum, something that's enumerable. And we can do, for each element in the enumerable, let's just put this element into the return array using the shovel operator. And then we can add one. And then we can end the loop, break if i is greater than or equal to n. And then we want to return the value. This is the kind of thing, especially this is greater than or equal to n. The chances of an off by one error are pretty high. So I'm going to save that, and I'm going to fire up. So we've got it running. It's great. So you can see there in the upper right part of the screen, I'm running guard here. It's running a test suite. And run it again. Right now, there aren't any tests. But you can see that it's a green check mark, meaning it's passing. So let's write a test for this. Let's define our setup method. And let's just make an enumerable here. RubyConf.news, RubyConf. And let's just make it very simple. Let's just go make an array. Just 1, 2, 3, 4, 5. So we want to test first-end elements. And let's just pull out the first three. So we're going to do assert equals 1, 2, 3, and RubyConf.first-end elements. I want to make this test. And so why is that breaking? I've got to give it some arguments. So let's give it enum and 3. Still breaking. Anyone see the problem? Assert equal. There we go. Get this eventually. All right, so it's passing. It's the kind of thing if you did the wrong thing here. You had greater than instead of greater than or equal to. Well, that's going to break. All right, so how might I do this in a shorter way? Does anyone know? Rather than iterating through, this is a lot of code here. What's that? You could do a four next loop. It's true. What's that? So we could do this. We could do this enum 0 up to n minus 1. That still passes. In fact, Ruby lets you do three dots here that does the num minus 1 for you. The problem with this, though, is this only works for things that support the square bracket operator, which, for example, hashes do not. So this wouldn't actually work if you wanted to take the first n elements of the hash. So innumerable, when you do that include innumerable line, mixes in the take method. So you can take the first n like this. Or you can also do this, the first n elements. And this works even if the object doesn't support the square brackets. So you can see why don't I keep the old one around, comment it out, just to show you how huge an improvement this is. So let's look at some other examples of what we can do. Suppose I want to make a method that returns true if any of the numbers in innumerable are odd. In fact, this is the kind of thing that I might very well write a test for first. There's been a lot of debate in the Ruby community about whether you want to write tests first or not. And the answer, I think, is that sometimes you do and sometimes you don't. So we want to see. So if any are odd, let's do any are odd. Actually, it's going to be at rubyconf.nerod, it's right there, of at enum. So should this be true or false? I mean, are any of these numbers odd in at enum? Yeah, so like 1, 3, and 5 are a lot too. This should be true, so if I assert it, this should pass. Of course, it doesn't pass yet. So how would you do this just using each? Well, you could have a return value. Let's call it retval again. And you can start off as, obviously, actually, we don't even need this. We can just iterate through. You can say it's going to take an innumerable. And for each number, we can return true right away if the number is odd. And if we get through that whole enumeration, probably want to do this. And then we can return false or just ruby if it just returns the last expression. So try this, see if this passes. There we go, so that's working. But this is a hint here. You can actually call odd question mark on a method or on a number like this. So let's try this. Let's do enum.any question mark. And this is going to iterate right through. And it's going to, this will return true if any are odd. I hope. That's why we have tests, though. There we go. So the any question mark method lets you go right through this collection and apply a Boolean test. And in fact, if you're going to do this, where you call the method right on the number or right on the element, and that's all you're doing, there's a shorthand for this. It looks like this, ampersand colon. You may have seen this, but if you haven't, this is very common. Idiomatically correct ruby here. One of the cool things about this, I think this is really a neat example of how flexible ruby is. This syntax was actually introduced by Rails. It was added to ruby dynamically. But people liked it so much that it's now been added to core ruby. Yeah? Well, this, I mean, you can do any question mark. You can, any question mark will work on a hash. This wouldn't work because you can't say whether an element in a hash is even or odd or not. But if you wanted on a hash to do something like this, you could do like, if you wanted to say key, if there are any elements in the hash where the key is the same as the value, you could do something like this. So you just pass it a block that evaluates to a Boolean, to true or false. All right, so let's look at another one. I'm gonna go through these pretty fast because I think you'll get the parallel structure. So suppose we wanna test if all of the numbers in this are odd. Well, we can actually make an assertion right here. So this should be assert, we can just negate it with a bang, right? This should be false. It's not true that they're all odd. And so here we can say the return value is false. And then if we can say return value is, I'm sorry, return value is true. Let's start it with true. And the return value is false if, or sorry, unless n is odd, right? So as soon as something isn't odd, then it will return, it will go false. And then we can actually, we can probably return false in there, can't we? See, can we do this? So any guesses about what we might do here? If any question mark lets you test if any of the things in the collection are odd in this case, what might the analog of that be? Any guesses? No guesses. What's that? No guesses. So I mean, you know, trying to, it's not supposed to be hard yet. So we can do enum.all a question mark and do the same thing here. Pass it a symbol. And there's one final one, which is really nice. And actually let's do this one here. Let's test none are odd. And this should also be false, right? So we can assert bang to make it true. And so if none, we want this to return, oops, return true if none are odd. So we can return this right. Ah, you're right. Ah, there we go. And as you might guess, this is just like this. All right, so now there's a whole section of related methods that are very common in enumatic Ruby code. And in fact, there's a linguistic connection between them that you may never have seen. So let's just go through these. So what I wanna do is return something that squares each element in this enumeration. So I can do, start off with an empty array. And I'm just going to add n squared, just to append it using the shovel operator. And then return it. And actually let's test this here. And so what is this going to be? This is gonna be one, four, nine, 16, 25. So which enumerable is this one? What's a, not, not nerny. Right, so this is map. We can say enum.map and we can square each element. In this case, we do just need a block. There's not a square method. We could define a square method and use this syntax here if we wanted to. So let's take a look at that. Cool. And there's a synonym for this called collect. It's the same thing. So what this does is just returns a list or it returns an enumerable. Or it returns the original, basically it returns this, this method or whatever's in the block applied to each element in the collection. So there are several closely related methods to manipulate these sorts of enumerables. Let's take a look at this here. So suppose we wanted to find the even numbers in the enum. Actually, let's write a test for this. So I wanna pick out the evens. I thought it was in my buffer there. So even numbers in this are two and four. So this is the kind of thing where you would, you could say evens are equal to like this. Enum.each do n and then add n if n.even. And as you might guess from this name here, there is a method in enumerable called find. So enum.find. Oops, what did I do wrong here? That's weird. This is select, but I thought, okay. Oh yeah, detect, I'm sorry, you're right. That's the next one. Yes, this is the select method. So select applies this method to every element in the collection and returns in this case just two and four. And we can also do this. We can ignore evens. So suppose we wanted to have only, not even thinking in terms of odds, but we want things that aren't even. That's the same thing, but if we want things that aren't even, we can just say non evens because it won't always be the case that everything is just in two sets. So non evens. Again, we're just going to enumerate. You can see every one of these has the same basic structure we're doing each. So we'll add the non evens there and less and is even. Actually, this is going to be one, three, five. And this is this here. Great. Does anyone know this one? Some, I mean, I know, advanced people don't answer. That's a good guess, ignores a good guess. It's the opposite of select. And in fact, you can see that there's a, we have a theme here, collect, select, and this one is reject. There are two more in that vein. Let's find the first even. Actually, let's just do this here. Test find first even. So let's say assert equal two, and then find first even, that enum. You can just iterate through and return immediately. If we find an even number else, it'll just return nil by default. So that's pretty short. No, it's also failing. Ah, you're right, there we are. So this one, you can do find. Yep, let's wait. So there's find where you can do this. Just find the first even number, this collection. And there's also detect. So we've got collect, select, reject, detect, and then my favorite of them, by far the most challenging. So let's do pairs of squares. In fact, this is a really good one to write a test first for. So we wanna do this. We wanna have pairs like this. One, two, sorry, one, one, two, four, three, nine, four, 16, and five, 25. Splitted here, I like those spaces. And this is going to be, so this should be red. Save this here. You're right, look at that. I'm getting a syntax error under the hood. Okay, so this, let's do two square pairs. Start with that, and then enum.each do n, and let's onto square pairs append n and n squared. Save, just return that. That's passing. All right, so we've got collect, select, reject, detect, and, you know the last one? I mean, I know some of you do. People who've ever given a keynote at a conference are not allowed to, or a Ruby conference are not allowed to answer. So this is, I think by far the hardest of these. It's called inject, and it lets you replace this with something that doesn't require defining an auxiliary variable like this. Let me show you that, if you haven't seen it before. So inject takes an optional argument, which is the thing you start with. In this case, an empty array. And then the block takes the thing you want to return, in this case square, but the thing you're sort of accumulating, and the element in the enumerable. And then inside here, we can do this. We can, this is created on the fly. So what this does is that it repeatedly applies this for every element in the enumerable and builds up square pairs, in this case, and then returns it. So inject is really cool, and you will see it in idiomatically correct Ruby, but it's a little bit abstract. It's a little strange. And so I don't think it's a bad idea, really, to write it the straightforward way, and then either have written a test already or write a test to capture the behavior, and then rewrite it using inject. Because it really is a little bit tricky. Okay, so that ends for the end. I would say that the vast majority of working Ruby programmers know these five that I've just mentioned. But now I'm gonna mention some things that are a little bit fancier, and in fact, I wanna copy some stuff here. So I'm gonna make a, I'm just gonna copy this test in here. This is basically cribbed from the real tutorial. This is a little bit long here. So what I've got here is a list of email addresses. It mixes valid and invalid email addresses. And this here is the list of valid ones. And I wanna make a method called valid email addresses that just returns the valid ones in the enum. So here's addresses is the enumerable. So I wanna write a method called valid email addresses that returns only the valid ones. So what we can do here is we can iterate through. And actually I wanna copy something else here too. So this is a regular expression that map that is a pretty good test for a valid email address. This guy here. And so what we can do is have say valid emails this, and we can iterate through these addresses. And then we can add to it valid emails if the address matches, we can do equals tilde that matches the regular expression. I think this will work. Let's see if it's green. I have a bad feeling about this. Valid emails, aha, right. Oh yeah, we need this. Addresses, oh, addresses. All right, that's not working still. All emails that address, if address tilde equals valid email regex, let's see what's happening here. Oh yeah, we do have to return it, don't we? So one of the things about this model of iterating through is it's actually way more error prone. Once you know how to do this, you can do this, you can do something like this. Anyone know, this is a pretty tricky one. So you can see how much trouble I had with all the stupid syntax, right? But look at this. Addresses.grep, it's supposed to work. Oh no, it's the wrong thing. There we go. Yes! So this is amazing. You can just replace all that error prone garbage with one line, addresses.grep. So let's see, in order to make sure we get to the real meat of this, I'm going to, let's see, let's do this. Oh, so I'm gonna paste in some of the garbage, the stuff that's crappy and long. So let's take a look at this here. So this is a test for returning the evens in the original array, which is this, and the odds. So the first element should be this here, the second element should be this. And so we can, don't look ahead, you're cheating, I can tell. So this is kind of a mess. Let's work. Yeah, so we can have the evens and the odds. For each thing, we can say if n is even, add to the evens, otherwise add to the odds, and then return them both. Kind of a mess, and we can do it like this. You can partition them based on this Boolean. Except it didn't work, why didn't it work? Oh yeah, you don't need the n, look at that. I love that syntax, it's beautiful. Okay, so this is a test for, it's the same thing we did before. If someone put it here. So this is more squares and pairs. It's the same thing, same return value, I want one, one, two, four, three, nine, four, 16, five, 25, and so on. So this is a nicer way of doing this, I think. And so I'm just gonna go to the, so what we can do is we can make a list of squares based on the enum, remember we have map or collect, so we can do this is equal to enum dot map, n, n squared, and there's a cool thing you can do if you've got two lists of the same size, you can get the pairs by zipping them together, like a zipper, is that right, is that just gonna work? Okay, and I want to, so I'm gonna add in something to capture standard out here. Oh, do I already have it? I don't, actually so let's take a look at this. Yeah, so we're really close. It's gonna be close to the 55 minutes, here it is. So this is a little bit of code to capture the standard output, I'm gonna put it in here. So if I put s, it's gonna capture it into an array. And see, so I wanna just print out the days of the week for four weeks, like this. So it's just a, I've got Sunday, Monday, Tuesday, Walden's Day, Thursday, Frig Day, and Saturday, it's the original. I learned that two is the Norse God of single combat, that's pretty awesome. Don't wanna mess with two. So this, so we could do something like this, we could, four times, we could go through these and print out today is, today is that, today is Sunday or a moon day. But we can also cycle through them. This is gonna fail, because this put s is a side effect. All the other times I was able to leave it in, actually, because it was returning the lost value, but put s has a side effect, so we can actually comment this out or get rid of it. So cycle four just goes through this list of the days of the week, four times, and prints them out. And finally, I wanna show you, this is the original disastrous first n prime numbers. So this is the first, how many is it? This is the first nine prime numbers. All right, why didn't that work? I mean, Lord only knows, right? This is this disaster of a thing. Oh, I didn't save it. Yeah, so this is the, this is a working finds the first n prime numbers, but it's a total mess. And so let me show you a cooler way to do this. So first, I'm going to add a prime method. This is actually built into Ruby, but you can import it in order to save on time. This is actually not the critical part. So I'm gonna add a prime question mark method to the, to fix num, which is the base class of base gave integers. And here, you can iterate through, the algorithm isn't important, but there's a long, painful way like this, but you can also use the non-question mark method and say two up to the square root of the number. So if it's say 17, it would be two up to the rounding up to the square root of 17. It's going to check to see if the number is divisible by any of these numbers in here. So that would be self. And so it's one number is prime if it's none of, if it's not divisible by any of these. So there's this. And then the really cool thing, and it's amazing is that this is a disaster here, but what I can do is I can actually write, get rid of this. I can say I want to go through the natural numbers and select the prime numbers and I want the first n of them. So actually let's do this. And the natural numbers I can define as one, it's, this is a range, one up to infinity. This is really long, right? This is a lot. But innumerable gives us a method called lazy which will only evaluate it if you need the next one. And so this will almost work. It won't quite because take doesn't actually evaluate the thing. Instead we have to force it and it's not passing in the last. Oh, that's not good. Oh yeah, this is, no. So, wrong number, someone help me debug. What's that? Drop the what? Yeah, so why is this, is it, oh, okay. So that's weird because I thought I had this working. You know what, I'm just gonna do this. Yeah, so that's working. Ruby actually has a prime question mark but you can also do first. First of n does evaluate it. So we replace that monstrosity with this. And so that means we went from this horrendous thing which returns the first n prime numbers to this. That's the numbers that select prime dot first of n and that is the power of innumerable. Thank you.