In this segment, I want to show you a larger example, both to put together a lot of what we've already seen in Ruby as well as to show a few additional features just as we go along. So, what I've chosen to do is to find a small class called MyRational that is actually a lot like the rational modules for fractions that we saw back when we studied the module system NML. I'm calling the class MyRational because it turns out that the current version of Ruby has wonderful built-in support for fractions that actually already uses a class called Rational. But we're going to build our own for purpose of an example. And as I mentioned, we're going to see a number of new features as we go along just to show you that Ruby is a large language. And that I can't show you all the different kinds of useful expressions there are. And to encourage you to learn more on your own if you're interested. Before I just get into the code and show you what I have, let me remind you a little bit about how the rationals we studied in ML work because this is a very similar piece of code that lets you see the same thing in a different programming style. So, we will have numerators and denominators. Our little library, our class is always going to keep thing in reduced form, so 3 over two, not 9 over 6, and it will always make sure the denominator is positive. The numerator may be positive or negative and then we'll have methods, what we used to have functions for, to add together rationals and for converting a rational to a string. So without further do, let's just go over to the code and look at what I have. So I have a class MyRational, so instances of this class will represent fractions. I have an initialization method here. It takes in a numerator, and this is kind of cute, I'll let the denominator be optional. So that you can have a default of 1. So, that if you just pass 1 argument to MyRational dot new then presumably, you want a whole number. Now, I do need some logic in here. The denominator is 0, that's an error, I don't allow 0 denominators in my fractions. So Ruby has a raised primitive that takes a string and that does something like exceptions and errors that we've seen in other languages. Here is an elsif so nested if then elsif notice the unusual and non English spelling of else here. And then if the denominator is less than 0, then I am going to have two statements here, two expressions where I initialize two instance variables num and den to be negative numerator and negative denominator. Right here, these are you know, the local variables that were the parameters to initialize. Else, I initialize them this way. You can put semicolons in, but they're optional when they're on separate lines. And then, the last thing I need to do to start the en-variance that I have for how I represent fractions is called self.reduce. Okay, it's a 0 argument method, so I can put the parentheses in if I want, but they are optional. And because it turns out it's a private method, I'll show it to you down below. You can't write self dot, you have to just write, reduce. So, that's initialize. Now, once I have a fraction, it, we need to be able to convert it to a string, and in typical object-oriented style, it has a method to string, if you will, that, that we call on a fraction and we get back a string. So, fractions know how to convert themselves to string. In sort of OOP terminology, and in Ruby, it's conventional to have such methods to be called to underscore s. Many, many classes have this method defined and it's the standard way so that anything that knows how to convert itself to a string should implement this method. Now, there are many ways we could implement this. I'm actually going to show you a few of them. But here's a good first way, so to_s here starts by taking whatever is in the numerator instance variable and calling its to_s. It turns out that numbers have a to_s method and this will get us the string representation of the numerator. Then, if the denominator is not 1, then let's concatenate so we can use plus on strings that concatenate to the right, a slash character, and then continue to concatenate the denominator converted to a string. If the denominator is 1, then we'll just not do any of this, and when we're all done with that, we'll return ans, which will be a string, which is what we want. So this works fine let me show you two other ways just to show you some other Ruby features that are perhaps a little bit of over kill here. Here's a second version that can way of converting it to string. Let's just create a little local variable, initially the empty string. Then, let's add to that string via concatenation let's change it to / concatenated with to_s of the denominator, but only if the denominator is minus 1. Now, this is somewhat strange if you haven't seen this in scripting languages, it's fairly popular in these languages. It's just a different kind of conditional, that's written e1 if e2, and it reads somewhat backwards, this says if e2 is true then do e 1. So some people find this easier to when it's sort of a one liner. It's a convenient way to just write something on one line that says, will do this action but only if the denominator is 1, so there you go. In any case whatever dens is after this line, we need to concatenate on the front converting the numerator into a string and since this is the last expression in our method that's what will be returned and that's exactly what we want. One more version of two string, this uses things like Racket's quasi quote and unquote which I explain in an optional segment at the end of that unit. Basically I'm just going to return a string, but inside of double quotes, whenever you have hash and then brace, up to the matching brace, what that does is evaluate this expression in here and then convert it to a string. And so it turns out another way to do this is to convert the numerator to a string, this will implicitly call its to_s method I believe. Followed by this conditional which is if the denominator equals 1 then no, nothing else slash concatenated on. If you're interested in this, it's generally called interpolation, expression interpolation in Ruby. And you can learn more of it on your own we won't have much need for it. So that's converting to strings. Now let's see something more interesting. Let's write a version of add, I'm calling it addbay because it's actually going to mutate the object itself. This is a somewhat common convention in Ruby. So what I'm going to do is take in another rational and update myself. Whatever object I call addbay on, will have its numerator denominator replaced by adding to it. The numerator and the denominator in r. So what I need to do is get r's numerator and denominator. Now this is the most interesting part. Because I can not say something like r.@num, because instance variables of r are a private to r that is a different object I can't do that. So r is going to have to provide some methods for me to get to numerator and denominator. So those are defined below on my rational and I made them And protected. Because they're protected, this code, which is part of the same class, even though they're not the same object, will be able to access them, even though they are not fully public methods. So far in, A equals R dot num, B equals dot den. I could then let C and D be my numerator and denominator. Then a little bit of arithmetic to update via mutation. Num to be a times d plus b times c, den to be b times d. Call reduce, because that fraction might not be reduced, and then I find it convenient to return the object itself. I showed you an earlier example where that turns out to be convenient and I'll show you a use of this sort of method where that's convenient in just a minute. So that's an imperative addition. If we wanted a functional addition, we could do that using our imperative addition. So here's how that might work. How about I define a method called plus? This will actually be quite nice. So, I'll able to do calls like r1 dot plus r2. But it turns out that in Ruby, plus the regular plus is just syntactic sugar for calling the plus method on the left argument with the right argument. So by calling this method plus I will actually be able to just use the addition operator on my rationals. And that's kind of syntactically cute as well. So here's how I will do this. What I will do is I will make a local variable ans, that's a new rational that holds this objects val, same values as numerator and denominator. So this is just making a copy, if you will, where I'm just passing to the new thing. The my numerator and my denominator and the initialized method above we'll do the correct thing for that new rational. Now given that new rational let's go ahead and imperatively add to it r and then just return that new rational. So plus always returns a new fraction, it never updates. This object's numerator and denominator field. Okay, so we've seen most of it here. Here is our protected getter methods for numerator and denominator. The comment here, points out that we could have used the shorter syntax of doing something like attr reader. But I find these a little easier to read, so fine. And then I just haven't shown you reduce yet. So, here is reduce, it's just the same logic we had before. It causes helper function gcd for greatest common divisor, it passes the absolute value of the numerator. And numbers all have this method abs define on them, so that works fine. And then gcd which is right here, we've seen a few times in the course, recursion works just fine in Ruby, so this gcd method is just calling itself. This is a self.gcd, but you can't write the self because it's private on itself to do the right calculation to compute the greatest common divisor of an x and a y. So that is our class. Now let me just show you a little top-level method here. We need to find a method outside of a an explicit class that just gets put in the object class. And this method just creates and uses some rationals. So what does it do, it creates a rational 3 over 4. Puts it in the r1 local variable. Then notice the use of plus here, this is actually going to call the plus method that we defined. So, another way to write this would have been r1 dot plus with r1 and then, the result of that dot plus and then MyRational or minus 5 over 2. As you see there, and then I just have some printings so put s r2 to_s. So put s just puts out its argument so when I convert this to a string hopefully I will get, I think minus 1. Because I'll have 3 4ths plus 3 4ths minus 5 halves. Then I do some imperative update on r2, where I add to it imperatively r1 and then take that result, so it turns out this returns the same object that r2 refers to, adds to it imperatively again minus 1 4th and then I try out all my different printing methods on that result. And so sure enough if I just come over here quickly, if I load example.rb, I just get two back just as I successfully loaded because use rationals is a method and I haven't called that method yet. And if I call it, I will see the appropriately print printed out thing. This is the first print where I was just printing I think it was r, yes r2 here which is minus 1. But then after I imperatively update it once with r1 which is 3 4th and then again with a minus 1 4th, that's going to have the overall effect of adding a half to it. So, all my other printing shows three different ways of printing out minus 1 over 2. And that's our larger example, showing a number of new features of Ruby and also an object-oriented programming style, where my rational objects were things with methods that knew how to perform the appropriate computation on the fraction.